From 0d0a1ab5f2987a926c7a717b93a2a3e59bf3344b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 29 Apr 2014 14:26:51 +0200 Subject: [PATCH 0001/1154] import v1.0.0 --- .gitignore | 10 + .gitmodules | 6 + COPYING | 165 +++++ Makefile | 15 + Makefile.include | 123 ++++ README | 3 + buttons.c | 68 ++ buttons.h | 40 + demo/Makefile | 17 + demo/demo.c | 285 ++++++++ firmware/Makefile | 48 ++ firmware/coins.c | 61 ++ firmware/coins.h | 33 + firmware/debug.c | 53 ++ firmware/debug.h | 35 + firmware/fsm.c | 672 +++++++++++++++++ firmware/fsm.h | 63 ++ firmware/layout2.c | 191 +++++ firmware/layout2.h | 35 + firmware/messages.c | 414 +++++++++++ firmware/messages.h | 53 ++ firmware/pinmatrix.c | 87 +++ firmware/pinmatrix.h | 27 + firmware/protect.c | 222 ++++++ firmware/protect.h | 31 + firmware/protob/.gitignore | 1 + firmware/protob/Makefile | 10 + firmware/protob/messages.options | 79 ++ firmware/protob/messages.pb.c | 305 ++++++++ firmware/protob/messages.pb.h | 639 ++++++++++++++++ firmware/protob/messages.proto | 1 + firmware/protob/pb.h | 519 +++++++++++++ firmware/protob/pb_decode.c | 1178 ++++++++++++++++++++++++++++++ firmware/protob/pb_decode.h | 149 ++++ firmware/protob/pb_encode.c | 667 +++++++++++++++++ firmware/protob/pb_encode.h | 154 ++++ firmware/protob/storage.options | 4 + firmware/protob/storage.pb.c | 44 ++ firmware/protob/storage.pb.h | 55 ++ firmware/protob/storage.proto | 1 + firmware/protob/types.options | 26 + firmware/protob/types.pb.c | 144 ++++ firmware/protob/types.pb.h | 262 +++++++ firmware/protob/types.proto | 1 + firmware/recovery.c | 179 +++++ firmware/recovery.h | 32 + firmware/reset.c | 151 ++++ firmware/reset.h | 31 + firmware/signing.c | 426 +++++++++++ firmware/signing.h | 32 + firmware/ssp.c | 40 + firmware/ssp.h | 26 + firmware/storage.c | 327 +++++++++ firmware/storage.h | 61 ++ firmware/transaction.c | 459 ++++++++++++ firmware/transaction.h | 67 ++ firmware/trezor.c | 53 ++ firmware/trezor.h | 38 + firmware/usb.c | 334 +++++++++ firmware/usb.h | 28 + gen/bitmaps.c | 49 ++ gen/bitmaps.h | 35 + gen/bitmaps/.gitignore | 2 + gen/bitmaps/digit0.png | Bin 0 -> 121 bytes gen/bitmaps/digit1.png | Bin 0 -> 112 bytes gen/bitmaps/digit2.png | Bin 0 -> 129 bytes gen/bitmaps/digit3.png | Bin 0 -> 125 bytes gen/bitmaps/digit4.png | Bin 0 -> 137 bytes gen/bitmaps/digit5.png | Bin 0 -> 128 bytes gen/bitmaps/digit6.png | Bin 0 -> 133 bytes gen/bitmaps/digit7.png | Bin 0 -> 127 bytes gen/bitmaps/digit8.png | Bin 0 -> 125 bytes gen/bitmaps/digit9.png | Bin 0 -> 132 bytes gen/bitmaps/gears0.png | Bin 0 -> 301 bytes gen/bitmaps/gears1.png | Bin 0 -> 326 bytes gen/bitmaps/gears2.png | Bin 0 -> 293 bytes gen/bitmaps/gears3.png | Bin 0 -> 330 bytes gen/bitmaps/generate.py | 59 ++ gen/bitmaps/icon_error.png | Bin 0 -> 152 bytes gen/bitmaps/icon_info.png | Bin 0 -> 138 bytes gen/bitmaps/icon_ok.png | Bin 0 -> 167 bytes gen/bitmaps/icon_question.png | Bin 0 -> 153 bytes gen/bitmaps/icon_warning.png | Bin 0 -> 138 bytes gen/bitmaps/logo48.png | Bin 0 -> 283 bytes gen/bitmaps/logo48_empty.png | Bin 0 -> 310 bytes gen/bitmaps/logo64.png | Bin 0 -> 317 bytes gen/bitmaps/logo64_empty.png | Bin 0 -> 444 bytes gen/fonts.c | 118 +++ gen/fonts.h | 15 + gen/fonts/font.png | Bin 0 -> 1079 bytes gen/fonts/generate.py | 31 + gen/handlers/handlers.py | 99 +++ layout.c | 105 +++ layout.h | 37 + memory.c | 45 ++ memory.h | 104 +++ memory.ld | 9 + memory_app_0.0.0.ld | 9 + memory_app_1.0.0.ld | 9 + oled.c | 331 +++++++++ oled.h | 57 ++ rng.c | 45 ++ rng.h | 28 + serialno.c | 46 ++ serialno.h | 26 + setup.c | 66 ++ setup.h | 29 + trezor-common | 1 + trezor-crypto | 1 + util.c | 81 ++ util.h | 41 ++ 111 files changed, 10758 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 COPYING create mode 100644 Makefile create mode 100644 Makefile.include create mode 100644 README create mode 100644 buttons.c create mode 100644 buttons.h create mode 100644 demo/Makefile create mode 100644 demo/demo.c create mode 100644 firmware/Makefile create mode 100644 firmware/coins.c create mode 100644 firmware/coins.h create mode 100644 firmware/debug.c create mode 100644 firmware/debug.h create mode 100644 firmware/fsm.c create mode 100644 firmware/fsm.h create mode 100644 firmware/layout2.c create mode 100644 firmware/layout2.h create mode 100644 firmware/messages.c create mode 100644 firmware/messages.h create mode 100644 firmware/pinmatrix.c create mode 100644 firmware/pinmatrix.h create mode 100644 firmware/protect.c create mode 100644 firmware/protect.h create mode 100644 firmware/protob/.gitignore create mode 100644 firmware/protob/Makefile create mode 100644 firmware/protob/messages.options create mode 100644 firmware/protob/messages.pb.c create mode 100644 firmware/protob/messages.pb.h create mode 120000 firmware/protob/messages.proto create mode 100644 firmware/protob/pb.h create mode 100644 firmware/protob/pb_decode.c create mode 100644 firmware/protob/pb_decode.h create mode 100644 firmware/protob/pb_encode.c create mode 100644 firmware/protob/pb_encode.h create mode 100644 firmware/protob/storage.options create mode 100644 firmware/protob/storage.pb.c create mode 100644 firmware/protob/storage.pb.h create mode 120000 firmware/protob/storage.proto create mode 100644 firmware/protob/types.options create mode 100644 firmware/protob/types.pb.c create mode 100644 firmware/protob/types.pb.h create mode 120000 firmware/protob/types.proto create mode 100644 firmware/recovery.c create mode 100644 firmware/recovery.h create mode 100644 firmware/reset.c create mode 100644 firmware/reset.h create mode 100644 firmware/signing.c create mode 100644 firmware/signing.h create mode 100644 firmware/ssp.c create mode 100644 firmware/ssp.h create mode 100644 firmware/storage.c create mode 100644 firmware/storage.h create mode 100644 firmware/transaction.c create mode 100644 firmware/transaction.h create mode 100644 firmware/trezor.c create mode 100644 firmware/trezor.h create mode 100644 firmware/usb.c create mode 100644 firmware/usb.h create mode 100644 gen/bitmaps.c create mode 100644 gen/bitmaps.h create mode 100644 gen/bitmaps/.gitignore create mode 100644 gen/bitmaps/digit0.png create mode 100644 gen/bitmaps/digit1.png create mode 100644 gen/bitmaps/digit2.png create mode 100644 gen/bitmaps/digit3.png create mode 100644 gen/bitmaps/digit4.png create mode 100644 gen/bitmaps/digit5.png create mode 100644 gen/bitmaps/digit6.png create mode 100644 gen/bitmaps/digit7.png create mode 100644 gen/bitmaps/digit8.png create mode 100644 gen/bitmaps/digit9.png create mode 100644 gen/bitmaps/gears0.png create mode 100644 gen/bitmaps/gears1.png create mode 100644 gen/bitmaps/gears2.png create mode 100644 gen/bitmaps/gears3.png create mode 100755 gen/bitmaps/generate.py create mode 100644 gen/bitmaps/icon_error.png create mode 100644 gen/bitmaps/icon_info.png create mode 100644 gen/bitmaps/icon_ok.png create mode 100644 gen/bitmaps/icon_question.png create mode 100644 gen/bitmaps/icon_warning.png create mode 100644 gen/bitmaps/logo48.png create mode 100644 gen/bitmaps/logo48_empty.png create mode 100644 gen/bitmaps/logo64.png create mode 100644 gen/bitmaps/logo64_empty.png create mode 100644 gen/fonts.c create mode 100644 gen/fonts.h create mode 100644 gen/fonts/font.png create mode 100755 gen/fonts/generate.py create mode 100755 gen/handlers/handlers.py create mode 100644 layout.c create mode 100644 layout.h create mode 100644 memory.c create mode 100644 memory.h create mode 100644 memory.ld create mode 100644 memory_app_0.0.0.ld create mode 100644 memory_app_1.0.0.ld create mode 100644 oled.c create mode 100644 oled.h create mode 100644 rng.c create mode 100644 rng.h create mode 100644 serialno.c create mode 100644 serialno.h create mode 100644 setup.c create mode 100644 setup.h create mode 160000 trezor-common create mode 160000 trezor-crypto create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..335be47ead --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.a +*.d +*.o +*.bin +*.elf +*.hex +*.list +*.srec +usb.pb* +bootloader diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..e029233140 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "trezor-crypto"] + path = trezor-crypto + url = https://github.com/trezor/trezor-crypto.git +[submodule "trezor-common"] + path = trezor-common + url = https://github.com/trezor/trezor-common.git diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..4d13b6063e --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +OBJS += buttons.o +OBJS += layout.o +OBJS += oled.o +OBJS += rng.o +OBJS += serialno.o +OBJS += setup.o +OBJS += util.o +OBJS += memory.o +OBJS += gen/bitmaps.o +OBJS += gen/fonts.o + +libtrezor.a: $(OBJS) + ar rcs libtrezor.a $(OBJS) + +include Makefile.include diff --git a/Makefile.include b/Makefile.include new file mode 100644 index 0000000000..0efd840479 --- /dev/null +++ b/Makefile.include @@ -0,0 +1,123 @@ +PREFIX ?= arm-none-eabi- +CC = $(PREFIX)gcc +LD = $(PREFIX)gcc +OBJCOPY = $(PREFIX)objcopy +OBJDUMP = $(PREFIX)objdump +FLASH = st-flash +OPENOCD = openocd +TOP_DIR = /home/stick/work/trezor/trezor-mcu +TOOLCHAIN_DIR = $(TOP_DIR)/../libopencm3 + +OPTFLAGS = -Os -g + +CFLAGS += $(OPTFLAGS) \ + -W \ + -Wall \ + -Wextra \ + -Wimplicit-function-declaration \ + -Wredundant-decls \ + -Wstrict-prototypes \ + -Wundef \ + -Wshadow \ + -Wpointer-arith \ + -Wformat \ + -Wreturn-type \ + -Wsign-compare \ + -Wmultichar \ + -Wformat-nonliteral \ + -Winit-self \ + -Wuninitialized \ + -Wformat-security \ + -Werror \ + -fno-common \ + -fno-exceptions \ + -fvisibility=internal \ + -mcpu=cortex-m3 \ + -mthumb \ + -msoft-float \ + -DSTM32F2 \ + -I$(TOOLCHAIN_DIR)/include \ + -I$(TOP_DIR) \ + -I$(TOP_DIR)/gen \ + -I$(TOP_DIR)/trezor-crypto \ + +ifdef APPVER +CFLAGS += -DAPPVER=$(APPVER) +LDSCRIPT = $(TOP_DIR)/memory_app_$(APPVER).ld +else +LDSCRIPT = $(TOP_DIR)/memory.ld +endif + +LDFLAGS += --static \ + -Wl,--start-group \ + -lc \ + -lgcc \ + -lnosys \ + -Wl,--end-group \ + -L$(TOP_DIR) \ + -L$(TOOLCHAIN_DIR)/lib \ + -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ + -T$(LDSCRIPT) \ + -nostartfiles \ + -Wl,--gc-sections \ + -mthumb \ + -march=armv7 \ + -mfix-cortex-m3-ldrd \ + -msoft-float + +all: $(NAME).bin + +flash: $(NAME).bin + $(FLASH) write $(NAME).bin 0x8000000 + +flash2: $(NAME).hex + $(OPENOCD) -f board/stm32f4discovery.cfg \ + -c "init" \ + -c "reset init" \ + -c "stm32f2x mass_erase 0" \ + -c "flash write_image $(NAME).hex" \ + -c "reset" \ + -c "shutdown" + +upload: + ../../python-trezor/cmd.py firmware_update -f $(NAME).bin + +sign: $(NAME).bin + ../bootloader/firmware_sign.py -f $(NAME).bin + +release: $(NAME).bin + ../bootloader/firmware_sign.py -f $(NAME).bin + cp $(NAME).bin $(NAME)-$(APPVER).bin + chmod -x $(NAME)-$(APPVER).bin + xxd -p $(NAME)-$(APPVER).bin | tr -d '\n' > $(NAME)-$(APPVER).bin.hex + +$(NAME).bin: $(NAME).elf + $(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin + +$(NAME).hex: $(NAME).elf + $(OBJCOPY) -Oihex $(NAME).elf $(NAME).hex + +$(NAME).srec: $(NAME).elf + $(OBJCOPY) -Osrec $(NAME).elf $(NAME).srec + +$(NAME).list: $(NAME).elf + $(OBJDUMP) -S $(NAME).elf > $(NAME).list + +$(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP_DIR)/libtrezor.a + $(LD) -o $(NAME).elf $(OBJS) -ltrezor -lopencm3_stm32f2 $(LDFLAGS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -o $@ -c $< + +%.small.o: %.c Makefile + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f $(OBJS) + rm -f *.a + rm -f *.d + rm -f *.elf + rm -f *.bin + rm -f *.hex + rm -f *.srec + rm -f *.list diff --git a/README b/README new file mode 100644 index 0000000000..98772f8ca7 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +Embedded software for TREZOR + +http://bitcointrezor.com/ diff --git a/buttons.c b/buttons.c new file mode 100644 index 0000000000..5bac9dcd55 --- /dev/null +++ b/buttons.c @@ -0,0 +1,68 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "buttons.h" + +struct buttonState button; + +void buttonUpdate() +{ + uint16_t state; + static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; + + state = gpio_port_read(BTN_PORT); + + if ((state & BTN_PIN_YES) == 0) { // Yes button is down + if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down + if (button.YesDown < 2000000000) button.YesDown++; + button.YesUp = false; + } else { // last Yes was up + button.YesDown = 0; + button.YesUp = false; + } + } else { // Yes button is up + if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down + button.YesDown = 0; + button.YesUp = true; + } else { // last Yes was up + button.YesDown = 0; + button.YesUp = false; + } + } + + if ((state & BTN_PIN_NO) == 0) { // No button is down + if ((last_state & BTN_PIN_NO) == 0) { // last No was down + if (button.NoDown < 2000000000) button.NoDown++; + button.NoUp = false; + } else { // last No was up + button.NoDown = 0; + button.NoUp = false; + } + } else { // No button is up + if ((last_state & BTN_PIN_NO) == 0) { // last No was down + button.NoDown = 0; + button.NoUp = true; + } else { // last No was up + button.NoDown = 0; + button.NoUp = false; + } + } + + last_state = state; +} diff --git a/buttons.h b/buttons.h new file mode 100644 index 0000000000..78a0fe24f5 --- /dev/null +++ b/buttons.h @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __BUTTONS_H__ +#define __BUTTONS_H__ + +#include + +struct buttonState { + volatile bool YesUp; + volatile int YesDown; + volatile bool NoUp; + volatile int NoDown; +}; + +extern struct buttonState button; + +void buttonUpdate(void); + +#define BTN_PORT GPIOC +#define BTN_PIN_YES GPIO2 +#define BTN_PIN_NO GPIO5 + +#endif diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 index 0000000000..5f16147c7e --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,17 @@ +APPVER = 1.0.0 + +NAME = demo + +OBJS += demo.o + +OBJS += ../trezor-crypto/bignum.o +OBJS += ../trezor-crypto/bip32.o +OBJS += ../trezor-crypto/ecdsa.o +OBJS += ../trezor-crypto/hmac.o +OBJS += ../trezor-crypto/ripemd160.o +OBJS += ../trezor-crypto/secp256k1.o +OBJS += ../trezor-crypto/sha2.o +OBJS += ../trezor-crypto/bip39.o +OBJS += ../trezor-crypto/pbkdf2.o + +include ../Makefile.include diff --git a/demo/demo.c b/demo/demo.c new file mode 100644 index 0000000000..77dc3b5f1f --- /dev/null +++ b/demo/demo.c @@ -0,0 +1,285 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include "bitmaps.h" +#include "buttons.h" +#include "layout.h" +#include "oled.h" +#include "setup.h" +//#include "util.h" +#include "hmac.h" +#include "pbkdf2.h" + +const int states = 2; +int state = 0; +int frame = 0; + +uint8_t seed[128]; +uint8_t *pass = (uint8_t *)"meadow"; +uint32_t passlen; +uint8_t *salt = (uint8_t *)"TREZOR"; +uint32_t saltlen; + +static const struct usb_device_descriptor dev_descr = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x534c, + .idProduct = 0x0001, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* got via usbhid-dump from CP2110 */ +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, + 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, + 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, + 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, + 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, + 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, + 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, + 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, + 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, + 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, + 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, + 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, + 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, + 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, + 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, + 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, + 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, + 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, + 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, + 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, + 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, + 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, +}; + +static const struct { + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) hid_function = { + .hid_descriptor = { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + } +}; + +static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor hid_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = hid_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SatoshiLabs", + "TREZOR", + "01234567", +}; + +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *, struct usb_setup_data *)) +{ + (void)complete; + (void)dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) + return 0; + + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + + return 1; +} + +static void hid_rx_callback(usbd_device *dev, uint8_t ep) +{ + (void)dev; + (void)ep; +} + +static void hid_set_config(usbd_device *dev, uint16_t wValue) +{ + (void)wValue; + + usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + + usbd_register_control_callback( + dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + hid_control_request); +} + +static usbd_device *usbd_dev; +static uint8_t usbd_control_buffer[128]; + +void usbInit(void) +{ + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); +} + +int main(void) +{ + setup(); + oledInit(); + usbInit(); + + passlen = strlen((char *)pass); + saltlen = strlen((char *)salt); + + for (;;) { + frame = 0; + switch (state) { + case 0: + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64); + break; + } + oledRefresh(); + + do { + usbd_poll(usbd_dev); + switch (state) { + case 1: + layoutProgress("WORKING", frame % 41 * 25, frame % 4); + pbkdf2(pass, passlen, salt, saltlen, 100, seed, 64, NULL); + usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); + break; + } + + buttonUpdate(); + frame += 1; + } while (!button.YesUp && !button.NoUp); + + if (button.YesUp) { + state = (state + 1) % states; + oledSwipeLeft(); + } else { + state = (state + states - 1) % states; + oledSwipeRight(); + } + } + + return 0; +} diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000000..ccd2d9ccc5 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,48 @@ +APPVER = 1.0.0 + +NAME = trezor + +OBJS += ssp.o +OBJS += usb.o +OBJS += messages.o +OBJS += storage.o +OBJS += trezor.o +OBJS += pinmatrix.o +OBJS += fsm.o +OBJS += coins.o +OBJS += transaction.o +OBJS += protect.o +OBJS += layout2.o +OBJS += recovery.o +OBJS += reset.o +OBJS += signing.o + +OBJS += debug.o + +OBJS += ../trezor-crypto/bignum.o +OBJS += ../trezor-crypto/ecdsa.o +OBJS += ../trezor-crypto/secp256k1.o +OBJS += ../trezor-crypto/sha2.o +OBJS += ../trezor-crypto/hmac.o +OBJS += ../trezor-crypto/bip32.o +OBJS += ../trezor-crypto/ripemd160.o +OBJS += ../trezor-crypto/bip39.o +OBJS += ../trezor-crypto/pbkdf2.o +OBJS += ../trezor-crypto/aescrypt.o +OBJS += ../trezor-crypto/aeskey.o +OBJS += ../trezor-crypto/aestab.o + +OBJS += protob/pb_decode.o +OBJS += protob/pb_encode.o +OBJS += protob/messages.pb.o +OBJS += protob/storage.pb.o +OBJS += protob/types.pb.o + +include ../Makefile.include + +# CFLAGS += -fstack-protector -fstack-protector-all +CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 +CFLAGS += -DDEBUG_LINK=0 +CFLAGS += -DDEBUG_LOG=0 +CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' +CFLAGS += -DSCM_REVISION_LEN=20 diff --git a/firmware/coins.c b/firmware/coins.c new file mode 100644 index 0000000000..9c028f6758 --- /dev/null +++ b/firmware/coins.c @@ -0,0 +1,61 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include "coins.h" + +const CoinType coins[COINS_COUNT] = { + {true, "Bitcoin", true, "BTC", true, 0, true, 10000}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000}, + {true, "Litecoin", true, "LTC", true, 48, true, 10000000}, +}; + +const CoinType *coinByShortcut(const char *shortcut) +{ + int i; + for (i = 0; i < COINS_COUNT; i++) { + if (strcmp(shortcut, coins[i].coin_shortcut) == 0) { + return &(coins[i]); + } + } + return 0; +} + +const CoinType *coinByName(const char *name) +{ + int i; + for (i = 0; i < COINS_COUNT; i++) { + if (strcmp(name, coins[i].coin_name) == 0) { + return &(coins[i]); + } + } + return 0; +} + +const CoinType *coinByAddressType(uint8_t address_type) +{ + int i; + for (i = 0; i < COINS_COUNT; i++) { + if (address_type == coins[i].address_type) { + return &(coins[i]); + } + } + return 0; +} diff --git a/firmware/coins.h b/firmware/coins.h new file mode 100644 index 0000000000..6ce02c2d2d --- /dev/null +++ b/firmware/coins.h @@ -0,0 +1,33 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __COINS_H__ +#define __COINS_H__ + +#include "types.pb.h" + +#define COINS_COUNT 4 + +extern const CoinType coins[COINS_COUNT]; + +const CoinType *coinByShortcut(const char *shortcut); +const CoinType *coinByName(const char *name); +const CoinType *coinByAddressType(uint8_t address_type); + +#endif diff --git a/firmware/debug.c b/firmware/debug.c new file mode 100644 index 0000000000..0149b4d507 --- /dev/null +++ b/firmware/debug.c @@ -0,0 +1,53 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "trezor.h" +#include "debug.h" +#include "oled.h" + +#if DEBUG_LOG + +void oledDebug(const char *line) +{ + int i; + static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + static char id = 3; + for (i = 0; i < 7; i++) { + lines[i] = lines[i + 1]; + } + lines[7] = line; + oledClear(); + for (i = 0; i < 8; i++) { + if (lines[i]) { + oledDrawChar(0, i * 8, '0' + (id + i) % 10); + oledDrawString(8, i * 8, lines[i]); + } + } + oledRefresh(); + id = (id + 1) % 10; +} + +void debugLog(int level, const char *bucket, const char *text) +{ + (void)level; + (void)bucket; + oledDebug(text); +} + +#endif diff --git a/firmware/debug.h b/firmware/debug.h new file mode 100644 index 0000000000..4b71db3a5b --- /dev/null +++ b/firmware/debug.h @@ -0,0 +1,35 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include "trezor.h" + +#if DEBUG_LOG + +void debugLog(int level, const char *bucket, const char *text); + +#else + +#define debugLog(L, B, T) do{}while(0) + +#endif + +#endif diff --git a/firmware/fsm.c b/firmware/fsm.c new file mode 100644 index 0000000000..d14e86d19b --- /dev/null +++ b/firmware/fsm.c @@ -0,0 +1,672 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "trezor.h" +#include "fsm.h" +#include "messages.h" +#include "bip32.h" +#include "storage.h" +#include "coins.h" +#include "debug.h" +#include "transaction.h" +#include "rng.h" +#include "storage.h" +#include "oled.h" +#include "protect.h" +#include "pinmatrix.h" +#include "layout2.h" +#include "ecdsa.h" +#include "reset.h" +#include "recovery.h" +#include "memory.h" +#include "usb.h" +#include "util.h" +#include "signing.h" + +// message methods + +static uint8_t msg_resp[MSG_OUT_SIZE]; + +#define RESP_INIT(TYPE) TYPE *resp = (TYPE *)msg_resp; memset(resp, 0, sizeof(TYPE)); + +void fsm_sendSuccess(const char *text) +{ + RESP_INIT(Success); + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Success, resp); +} + +void fsm_sendFailure(FailureType code, const char *text) +{ + RESP_INIT(Failure); + resp->has_code = true; + resp->code = code; + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Failure, resp); +} + +HDNode *fsm_getRootNode(void) +{ + static HDNode node; + if (!storage_getRootNode(&node)) { + layoutHome(); + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); + return 0; + } + return &node; +} + +void fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) +{ + size_t i; + if (address_n_count > 3) { + layoutProgressSwipe("Preparing keys", 0, 0); + } + for (i = 0; i < address_n_count; i++) { + hdnode_private_ckd(node, address_n[i]); + if (address_n_count > 3) { + layoutProgress("Preparing keys", 1000 * i / address_n_count, i); + } + } +} + +void fsm_msgInitialize(Initialize *msg) +{ + (void)msg; + recovery_abort(); + signing_abort(); + RESP_INIT(Features); + resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); + resp->has_major_version = true; resp->major_version = VERSION_MAJOR; + resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; + resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; + resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); + resp->has_pin_protection = true; resp->pin_protection = storage.has_pin; + resp->has_passphrase_protection = true; resp->passphrase_protection = storage.passphrase_protection; +#ifdef SCM_REVISION + resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, sizeof(resp->revision)); resp->revision.size = SCM_REVISION_LEN; +#endif + resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); + if (storage.has_language) { + resp->has_language = true; + strlcpy(resp->language, storage.language, sizeof(resp->language)); + } + if (storage.has_label) { + resp->has_label = true; + strlcpy(resp->label, storage.label, sizeof(resp->label)); + } + resp->coins_count = COINS_COUNT; + memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType)); + resp->has_initialized = true; resp->initialized = storage_isInitialized(); + msg_write(MessageType_MessageType_Features, resp); +} + +void fsm_msgPing(Ping *msg) +{ + RESP_INIT(Success); + + if (msg->has_button_protection && msg->button_protection) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + layoutHome(); + return; + } + } + + if (msg->has_pin_protection && msg->pin_protection) { + if (!protectPin(true)) { + layoutHome(); + return; + } + } + + if (msg->has_passphrase_protection && msg->passphrase_protection) { + if (!protectPassphrase()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + return; + } + } + + if (msg->has_message) { + resp->has_message = true; + memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Success, resp); + layoutHome(); +} + +void fsm_msgChangePin(ChangePin *msg) +{ + bool removal = msg->has_remove && msg->remove; + if (removal) { + if (storage_hasPin()) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL); + } else { + fsm_sendSuccess("PIN removed"); + return; + } + } else { + if (storage_hasPin()) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL); + } else { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL); + } + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, removal ? "PIN removal cancelled" : "PIN change cancelled"); + layoutHome(); + return; + } + if (!protectPin(false)) { + layoutHome(); + return; + } + if (removal) { + storage_setPin(0); + fsm_sendSuccess("PIN removed"); + } else { + if (protectChangePin()) { + fsm_sendSuccess("PIN changed"); + } else { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + } + } + layoutHome(); +} + +void fsm_msgWipeDevice(WipeDevice *msg) +{ + (void)msg; + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); + layoutHome(); + return; + } + storage_reset(); + storage_reset_uuid(); + storage_commit(); + // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed + // usbReconnect(); // force re-enumeration because of the serial number change + fsm_sendSuccess("Device wiped"); + layoutHome(); +} + +void fsm_msgFirmwareErase(FirmwareErase *msg) +{ + (void)msg; + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in bootloader mode"); +} + +void fsm_msgFirmwareUpload(FirmwareUpload *msg) +{ + (void)msg; + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in bootloader mode"); +} + +void fsm_msgGetEntropy(GetEntropy *msg) +{ + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); + layoutHome(); + return; + } + RESP_INIT(Entropy); + uint32_t len = msg->size; + if (len > 1024) { + len = 1024; + } + resp->entropy.size = len; + random_buffer(resp->entropy.bytes, len); + msg_write(MessageType_MessageType_Entropy, resp); + layoutHome(); +} + +void fsm_msgGetPublicKey(GetPublicKey *msg) +{ + RESP_INIT(PublicKey); + + HDNode *node = fsm_getRootNode(); + if (!node) return; + + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + + resp->node.depth = node->depth; + resp->node.fingerprint = node->fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); + + msg_write(MessageType_MessageType_PublicKey, resp); + layoutHome(); +} + +void fsm_msgLoadDevice(LoadDevice *msg) +{ + if (storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); + return; + } + + storage_loadDevice(msg); + storage_commit(); + fsm_sendSuccess("Device loaded"); + layoutHome(); +} + +void fsm_msgResetDevice(ResetDevice *msg) +{ + if (storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); + return; + } + + reset_init( + msg->has_display_random && msg->display_random, + msg->has_strength ? msg->strength : 128, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0 + ); +} + +void fsm_msgSignTx(SignTx *msg) +{ + if (msg->inputs_count < 1) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); + layoutHome(); + return; + } + + if (msg->outputs_count < 1) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); + layoutHome(); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + HDNode *node = fsm_getRootNode(); + if (!node) return; + const CoinType *coin = coinByName(msg->coin_name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return; + } + + signing_init(msg->inputs_count, msg->outputs_count, coin, node); +} + +void fsm_msgSimpleSignTx(SimpleSignTx *msg) +{ + RESP_INIT(TxRequest); + + if (msg->inputs_count < 1) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); + layoutHome(); + return; + } + + if (msg->outputs_count < 1) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); + layoutHome(); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + HDNode *node = fsm_getRootNode(); + if (!node) return; + const CoinType *coin = coinByName(msg->coin_name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return; + } + + uint32_t version = 1; + uint32_t lock_time = 0; + int tx_size = transactionSimpleSign(coin, node, msg->inputs, msg->inputs_count, msg->outputs, msg->outputs_count, version, lock_time, resp->serialized.serialized_tx.bytes); + if (tx_size < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); + layoutHome(); + return; + } + if (tx_size == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error signing transaction"); + layoutHome(); + return; + } + + size_t i, j; + + // determine change address + uint64_t change_spend = 0; + for (i = 0; i < msg->outputs_count; i++) { + if (msg->outputs[i].address_n_count > 0) { // address_n set -> change address + if (change_spend == 0) { // not set + change_spend = msg->outputs[i].amount; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + layoutHome(); + return; + } + } + } + + // check origin transactions + uint8_t prev_hashes[ pb_arraysize(SimpleSignTx, transactions) ][32]; + for (i = 0; i < msg->transactions_count; i++) { + if (!transactionHash(&(msg->transactions[i]), prev_hashes[i])) { + memset(prev_hashes[i], 0, 32); + } + } + + // calculate spendings + uint64_t to_spend = 0; + bool found; + for (i = 0; i < msg->inputs_count; i++) { + found = false; + for (j = 0; j < msg->transactions_count; j++) { + if (memcmp(msg->inputs[i].prev_hash.bytes, prev_hashes[j], 32) == 0) { // found prev TX + if (msg->inputs[i].prev_index < msg->transactions[j].bin_outputs_count) { + to_spend += msg->transactions[j].bin_outputs[msg->inputs[i].prev_index].amount; + found = true; + break; + } + } + } + if (!found) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid prevhash"); + layoutHome(); + return; + } + } + + uint64_t spending = 0; + for (i = 0; i < msg->outputs_count; i++) { + spending += msg->outputs[i].amount; + } + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); + layoutHome(); + return; + } + + uint64_t fee = to_spend - spending; + if (fee > (((uint64_t)tx_size + 999) / 1000) * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee, ((uint64_t)tx_size + 999) / 1000); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); + layoutHome(); + return; + } + } + + // last confirmation + layoutConfirmTx(coin, to_spend - change_spend - fee, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + } else { + resp->has_request_type = true; + resp->request_type = RequestType_TXFINISHED; + resp->has_serialized = true; + resp->serialized.has_serialized_tx = true; + resp->serialized.serialized_tx.size = (uint32_t)tx_size; + msg_write(MessageType_MessageType_TxRequest, resp); + } + + layoutHome(); +} + +void fsm_msgCancel(Cancel *msg) +{ + (void)msg; + recovery_abort(); + signing_abort(); +} + +void fsm_msgTxAck(TxAck *msg) +{ + if (msg->has_tx) { + signing_txack(&(msg->tx)); + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No transaction provided"); + } +} + +void fsm_msgApplySettings(ApplySettings *msg) +{ + if (msg->has_label && msg->has_language) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "and language to", msg->language, "?"); + } else + if (msg->has_label) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); + } else + if (msg->has_language) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); + return; + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + layoutHome(); + return; + } + if (!protectPin(true)) { + layoutHome(); + return; + } + if (msg->has_label) { + storage_setLabel(msg->label); + } + if (msg->has_language) { + storage_setLanguage(msg->language); + } + storage_commit(); + fsm_sendSuccess("Settings applied"); + layoutHome(); +} + +void fsm_msgGetAddress(GetAddress *msg) +{ + RESP_INIT(Address); + + HDNode *node = fsm_getRootNode(); + if (!node) return; + const CoinType *coin = coinByName(msg->coin_name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return; + } + + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + + ecdsa_get_address(node->public_key, coin->address_type, resp->address); + + msg_write(MessageType_MessageType_Address, resp); + layoutHome(); +} + +void fsm_msgEntropyAck(EntropyAck *msg) +{ + if (msg->has_entropy) { + reset_entropy(msg->entropy.bytes, msg->entropy.size); + } else { + reset_entropy(0, 0); + } +} + +void fsm_msgSignMessage(SignMessage *msg) +{ + RESP_INIT(MessageSignature); + + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); + layoutHome(); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + HDNode *node = fsm_getRootNode(); + if (!node) return; + const CoinType *coin = coinByName(msg->coin_name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return; + } + + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + + ecdsa_get_address(node->public_key, coin->address_type, resp->address); + if (transactionMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->address, resp->signature.bytes)) { + resp->has_address = true; + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_MessageSignature, resp); + } else { + fsm_sendFailure(FailureType_Failure_Other, "Error signing message"); + } + layoutHome(); +} + +void fsm_msgVerifyMessage(VerifyMessage *msg) +{ + const char *address = msg->has_address ? msg->address : 0; + if (msg->signature.size == 65 && transactionMessageVerify(msg->message.bytes, msg->message.size, msg->signature.bytes, address)) { + // TODO: show verified message & wait for button + // layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", NULL, "Verified message", NULL, NULL, NULL, NULL, NULL); + // protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendSuccess("Message verified"); + } else { + fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); + } + layoutHome(); +} + +void fsm_msgEstimateTxSize(EstimateTxSize *msg) +{ + RESP_INIT(TxSize); + resp->has_tx_size = true; + resp->tx_size = transactionEstimateSize(msg->inputs_count, msg->outputs_count); + msg_write(MessageType_MessageType_TxSize, resp); +} + +void fsm_msgRecoveryDevice(RecoveryDevice *msg) +{ + if (storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); + return; + } + recovery_init( + msg->has_word_count ? msg->word_count : 12, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_enforce_wordlist ? msg->enforce_wordlist : false + ); +} + +void fsm_msgWordAck(WordAck *msg) +{ + recovery_word(msg->word); +} + +#if DEBUG_LINK + +void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) +{ + (void)msg; + RESP_INIT(DebugLinkState); + +// resp->has_layout = true; +// resp->layout.size = OLED_BUFSIZE; +// memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + + if (storage.has_pin) { + resp->has_pin = true; + strlcpy(resp->pin, storage.pin, sizeof(resp->pin)); + } + + resp->has_matrix = true; + strlcpy(resp->matrix, pinmatrix_get(), sizeof(resp->matrix)); + + resp->has_reset_entropy = true; + resp->reset_entropy.size = reset_get_int_entropy(resp->reset_entropy.bytes); + + resp->has_reset_word = true; + strlcpy(resp->reset_word, reset_get_word(), sizeof(resp->reset_word)); + + resp->has_recovery_fake_word = true; + strlcpy(resp->recovery_fake_word, recovery_get_fake_word(), sizeof(resp->recovery_fake_word)); + + resp->has_recovery_word_pos = true; + resp->recovery_word_pos = recovery_get_word_pos(); + + if (storage.has_mnemonic) { + resp->has_mnemonic = true; + strlcpy(resp->mnemonic, storage.mnemonic, sizeof(resp->mnemonic)); + } + + if (storage.has_node) { + resp->has_node = true; + memcpy(&(resp->node), &(storage.node), sizeof(HDNode)); + } + + resp->has_passphrase_protection = true; + resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; + + msg_debug_write(MessageType_MessageType_DebugLinkState, resp); +} + +void fsm_msgDebugLinkStop(DebugLinkStop *msg) +{ + (void)msg; +} + +#endif diff --git a/firmware/fsm.h b/firmware/fsm.h new file mode 100644 index 0000000000..8344f67b3b --- /dev/null +++ b/firmware/fsm.h @@ -0,0 +1,63 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __FSM_H__ +#define __FSM_H__ + +#include "messages.pb.h" + +// message functions + +void fsm_sendSuccess(const char *text); +void fsm_sendFailure(FailureType code, const char *text); + +void fsm_msgInitialize(Initialize *msg); +void fsm_msgPing(Ping *msg); +void fsm_msgChangePin(ChangePin *msg); +void fsm_msgWipeDevice(WipeDevice *msg); +void fsm_msgFirmwareErase(FirmwareErase *msg); +void fsm_msgFirmwareUpload(FirmwareUpload *msg); +void fsm_msgGetEntropy(GetEntropy *msg); +void fsm_msgGetPublicKey(GetPublicKey *msg); +void fsm_msgLoadDevice(LoadDevice *msg); +void fsm_msgResetDevice(ResetDevice *msg); +void fsm_msgSignTx(SignTx *msg); +void fsm_msgSimpleSignTx(SimpleSignTx *msg); +//void fsm_msgPinMatrixAck(PinMatrixAck *msg); +void fsm_msgCancel(Cancel *msg); +void fsm_msgTxAck(TxAck *msg); +void fsm_msgApplySettings(ApplySettings *msg); +//void fsm_msgButtonAck(ButtonAck *msg); +void fsm_msgGetAddress(GetAddress *msg); +void fsm_msgEntropyAck(EntropyAck *msg); +void fsm_msgSignMessage(SignMessage *msg); +void fsm_msgVerifyMessage(VerifyMessage *msg); +//void fsm_msgPassphraseAck(PassphraseAck *msg); +void fsm_msgEstimateTxSize(EstimateTxSize *msg); +void fsm_msgRecoveryDevice(RecoveryDevice *msg); +void fsm_msgWordAck(WordAck *msg); + +// debug message functions +#if DEBUG_LINK +//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); +void fsm_msgDebugLinkGetState(DebugLinkGetState *msg); +void fsm_msgDebugLinkStop(DebugLinkStop *msg); +#endif + +#endif diff --git a/firmware/layout2.c b/firmware/layout2.c new file mode 100644 index 0000000000..49adcce4c5 --- /dev/null +++ b/firmware/layout2.c @@ -0,0 +1,191 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include "layout2.h" +#include "storage.h" +#include "oled.h" +#include "bitmaps.h" +#include "string.h" +#include "util.h" + +void *layoutLast = layoutHome; + +void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) +{ + layoutLast = layoutDialogSwipe; + oledSwipeLeft(); + layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, line6); +} + +void layoutProgressSwipe(const char *desc, int permil, int gearstep) +{ + if (layoutLast == layoutProgressSwipe) { + oledClear(); + } else { + layoutLast = layoutProgressSwipe; + oledSwipeLeft(); + } + layoutProgress(desc, permil, gearstep); +} + +void layoutHome(void) +{ + if (layoutLast == layoutHome) { + oledClear(); + } else { + layoutLast = layoutHome; + oledSwipeLeft(); + } + const char *label = storage_getLabel(); + if (label && strlen(label) > 0) { + oledDrawBitmap(44, 4, &bmp_logo48); + oledDrawStringCenter(OLED_HEIGHT - 8, label); + } else { + oledDrawBitmap(40, 0, &bmp_logo64); + } + oledRefresh(); +} + +const char *str_amount(uint64_t amnt, const char *abbr, char *buf, int len) +{ + memset(buf, 0, len); + uint64_t a = amnt, b = 1; + int i; + for (i = 0; i < 8; i++) { + buf[16 - i] = '0' + (a / b) % 10; + b *= 10; + } + buf[8] = '.'; + for (i = 0; i < 8; i++) { + buf[7 - i] = '0' + (a / b) % 10; + b *= 10; + } + i = 17; + while (i > 10 && buf[i - 1] == '0') { // drop trailing zeroes + i--; + } + if (abbr) { + buf[i] = ' '; + strlcpy(buf + i + 1, abbr, len - i - 1); + } else { + buf[i] = 0; + } + const char *r = buf; + while (*r == '0' && *(r + 1) != '.') r++; // drop leading zeroes + return r; +} + +static char buf_out[32], buf_fee[32]; + +void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) +{ + static char first_half[17 + 1]; + strlcpy(first_half, out->address, sizeof(first_half)); + const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); + layoutDialogSwipe(DIALOG_ICON_QUESTION, + "Cancel", + "Confirm", + NULL, + "Confirm sending", + str_out, + "to", + first_half, + out->address + 17, + NULL + ); +} + +void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee) +{ + const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); + const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee)); + layoutDialogSwipe(DIALOG_ICON_QUESTION, + "Cancel", + "Confirm", + NULL, + "Really send", + str_out, + "from your wallet?", + "Fee will be", + str_fee, + NULL + ); +} + +void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) +{ + (void)kb; + const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); + layoutDialogSwipe(DIALOG_ICON_QUESTION, + "Cancel", + "Confirm", + NULL, + "Fee", + str_out, + "is unexpectedly high.", + NULL, + "Send anyway?", + NULL + ); +} + +void layoutSignMessage(const uint8_t *msg, uint32_t len) +{ + bool ascii = true; + uint32_t i; + for (i = 0; i < len; i++) { + if (msg[i] < 0x20 || msg[i] >= 0x80) { + ascii = false; + break; + } + } + + char str[4][17]; + memset(str, 0, sizeof(str)); + if (ascii) { + strlcpy(str[0], (char *)msg, 17); + if (len > 16) { + strlcpy(str[1], (char *)msg + 16, 17); + } + if (len > 32) { + strlcpy(str[2], (char *)msg + 32, 17); + } + if (len > 48) { + strlcpy(str[3], (char *)msg + 48, 17); + } + } else { + data2hex(msg, len > 8 ? 8 : len, str[0]); + if (len > 8) { + data2hex(msg + 8, len > 16 ? 8 : len - 8, str[1]); + } + if (len > 16) { + data2hex(msg + 16, len > 24 ? 8 : len - 16, str[2]); + } + if (len > 24) { + data2hex(msg + 24, len > 32 ? 8 : len - 24, str[3]); + } + } + + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, + ascii ? "Sign text message?" : "Sign binary message?", + str[0], str[1], str[2], str[3], NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h new file mode 100644 index 0000000000..f406ae4158 --- /dev/null +++ b/firmware/layout2.h @@ -0,0 +1,35 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __LAYOUT2_H__ +#define __LAYOUT2_H__ + +#include "layout.h" +#include "types.pb.h" + +void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutProgressSwipe(const char *desc, int permil, int gearstep); + +void layoutHome(void); +void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); +void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); +void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); +void layoutSignMessage(const uint8_t *msg, uint32_t len); + +#endif diff --git a/firmware/messages.c b/firmware/messages.c new file mode 100644 index 0000000000..70ff6da835 --- /dev/null +++ b/firmware/messages.c @@ -0,0 +1,414 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "trezor.h" +#include "messages.h" +#include "debug.h" +#include "fsm.h" +#include "util.h" + +#include "pb_decode.h" +#include "pb_encode.h" +#include "messages.pb.h" + +// SimpleSignTx_size is the largest message we operate with +#if MSG_IN_SIZE < SimpleSignTx_size +#error "MSG_IN_SIZE is too small!" +#endif + +struct MessagesMap_t { + char type; // n = normal, d = debug + char dir; // i = in, o = out + uint16_t msg_id; + const pb_field_t *fields; + void (*process_func)(void *ptr); +}; + +static const struct MessagesMap_t MessagesMap[] = { + // in messages + {'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *))fsm_msgInitialize}, + {'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *))fsm_msgPing}, + {'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *))fsm_msgChangePin}, + {'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *))fsm_msgWipeDevice}, + {'n', 'i', MessageType_MessageType_FirmwareErase, FirmwareErase_fields, (void (*)(void *))fsm_msgFirmwareErase}, + {'n', 'i', MessageType_MessageType_FirmwareUpload, FirmwareUpload_fields, (void (*)(void *))fsm_msgFirmwareUpload}, + {'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *))fsm_msgGetEntropy}, + {'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *))fsm_msgGetPublicKey}, + {'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *))fsm_msgLoadDevice}, + {'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *))fsm_msgResetDevice}, + {'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *))fsm_msgSignTx}, + {'n', 'i', MessageType_MessageType_SimpleSignTx, SimpleSignTx_fields, (void (*)(void *))fsm_msgSimpleSignTx}, +// {'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *))fsm_msgPinMatrixAck}, + {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, + {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, + {'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *))fsm_msgApplySettings}, +// {'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *))fsm_msgButtonAck}, + {'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *))fsm_msgGetAddress}, + {'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *))fsm_msgEntropyAck}, + {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, + {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, +// {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck}, + {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, + {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, + {'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *))fsm_msgWordAck}, + // out messages + {'n', 'o', MessageType_MessageType_Success, Success_fields, 0}, + {'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0}, + {'n', 'o', MessageType_MessageType_Entropy, Entropy_fields, 0}, + {'n', 'o', MessageType_MessageType_PublicKey, PublicKey_fields, 0}, + {'n', 'o', MessageType_MessageType_Features, Features_fields, 0}, + {'n', 'o', MessageType_MessageType_PinMatrixRequest, PinMatrixRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_TxRequest, TxRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_ButtonRequest, ButtonRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_Address, Address_fields, 0}, + {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, + {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, + {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, +#if DEBUG_LINK + // debug in messages +// {'d', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *))fsm_msgDebugLinkDecision}, + {'d', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *))fsm_msgDebugLinkGetState}, + {'d', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *))fsm_msgDebugLinkStop}, + // debug out messages + {'d', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0}, + {'d', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0}, +#endif + // end + {0, 0, 0, 0, 0} +}; + +const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) +{ + const struct MessagesMap_t *m = MessagesMap; + while (m->type) { + if (type == m->type && dir == m->dir && msg_id == m->msg_id) { + return m->fields; + } + m++; + } + return 0; +} + +void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) +{ + const struct MessagesMap_t *m = MessagesMap; + while (m->type) { + if (type == m->type && dir == m->dir && msg_id == m->msg_id) { + m->process_func(ptr); + return; + } + m++; + } +} + +static uint32_t msg_out_start = 0; +static uint32_t msg_out_end = 0; +static uint32_t msg_out_cur = 0; +static uint8_t msg_out[MSG_OUT_SIZE]; + +#if DEBUG_LINK + +static uint32_t msg_debug_out_start = 0; +static uint32_t msg_debug_out_end = 0; +static uint32_t msg_debug_out_cur = 0; +static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE]; + +#endif + +inline void msg_out_append(uint8_t c) +{ + if (msg_out_cur == 0) { + msg_out[msg_out_end * 64] = '?'; + msg_out_cur = 1; + } + msg_out[msg_out_end * 64 + msg_out_cur] = c; + msg_out_cur++; + if (msg_out_cur == 64) { + msg_out_cur = 0; + msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); + } +} + +#if DEBUG_LINK + +inline void msg_debug_out_append(uint8_t c) +{ + if (msg_debug_out_cur == 0) { + msg_debug_out[msg_debug_out_end * 64] = '?'; + msg_debug_out_cur = 1; + } + msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = c; + msg_debug_out_cur++; + if (msg_debug_out_cur == 64) { + msg_debug_out_cur = 0; + msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); + } +} + +#endif + +inline void msg_out_pad(void) +{ + if (msg_out_cur == 0) return; + while (msg_out_cur < 64) { + msg_out[msg_out_end * 64 + msg_out_cur] = 0; + msg_out_cur++; + } + msg_out_cur = 0; + msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); +} + +#if DEBUG_LINK + +inline void msg_debug_out_pad(void) +{ + if (msg_debug_out_cur == 0) return; + while (msg_debug_out_cur < 64) { + msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0; + msg_debug_out_cur++; + } + msg_debug_out_cur = 0; + msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); +} + +#endif + +static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + (void)stream; + size_t i; + for (i = 0; i < count; i++) { + msg_out_append(buf[i]); + } + return true; +} + +#if DEBUG_LINK + +static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + (void)stream; + size_t i; + for (i = 0; i < count; i++) { + msg_debug_out_append(buf[i]); + } + return true; +} + +#endif + +bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) +{ + const pb_field_t *fields = MessageFields(type, 'o', msg_id); + if (!fields) { // unknown message + return false; + } + + pb_ostream_t sizestream = {0, 0, SIZE_MAX, 0, 0}; + bool status = pb_encode(&sizestream, fields, msg_ptr); + + if (!status) { + return false; + } + + void (*append)(uint8_t); + bool (*pb_callback)(pb_ostream_t *, const uint8_t *, size_t); + + if (type == 'n') { + append = msg_out_append; + pb_callback = pb_callback_out; + } else +#if DEBUG_LINK + if (type == 'd') { + append = msg_debug_out_append; + pb_callback = pb_debug_callback_out; + } else +#endif + { + return false; + } + + uint32_t len = sizestream.bytes_written; + append('#'); + append('#'); + append((msg_id >> 8) & 0xFF); + append(msg_id & 0xFF); + append((len >> 24) & 0xFF); + append((len >> 16) & 0xFF); + append((len >> 8) & 0xFF); + append(len & 0xFF); + pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0}; + status = pb_encode(&stream, fields, msg_ptr); + if (type == 'n') { + msg_out_pad(); + } +#if DEBUG_LINK + else if (type == 'd') { + msg_debug_out_pad(); + } +#endif + return status; +} + +enum { + READSTATE_IDLE, + READSTATE_READING, +}; + +void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) +{ + static uint8_t msg_data[MSG_IN_SIZE]; + pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); + bool status = pb_decode(&stream, fields, msg_data); + if (status) { + MessageProcessFunc(type, 'i', msg_id, msg_data); + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, stream.errmsg); + } +} + +void msg_read_common(char type, uint8_t *buf, int len) +{ + static char read_state = READSTATE_IDLE; + static uint8_t msg_in[MSG_IN_SIZE]; + static uint16_t msg_id = 0xFFFF; + static uint32_t msg_size = 0; + static uint32_t msg_pos = 0; + static const pb_field_t *fields = 0; + + if (read_state == READSTATE_IDLE) { + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard + return; + } + msg_id = (buf[3] << 8) + buf[4]; + msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + + fields = MessageFields(type, 'i', msg_id); + if (!fields) { // unknown message + // fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + return; + } + if (msg_size > MSG_IN_SIZE) { // message is too big :( + fsm_sendFailure(FailureType_Failure_SyntaxError, "Message too big"); + return; + } + + read_state = READSTATE_READING; + + memcpy(msg_in, buf + 9, len - 9); + msg_pos = len - 9; + } else + if (read_state == READSTATE_READING) { + if (buf[0] != '?') { // invalid contents + read_state = READSTATE_IDLE; + return; + } + memcpy(msg_in + msg_pos, buf + 1, len - 1); + msg_pos += len - 1; + } + + if (msg_pos >= msg_size) { + msg_process(type, msg_id, fields, msg_in, msg_size); + msg_pos = 0; + read_state = READSTATE_IDLE; + } +} + +uint8_t *msg_out_data(void) +{ + if (msg_out_start == msg_out_end) return 0; + uint8_t *data = msg_out + (msg_out_start * 64); + msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64); + debugLog(0, "", "msg_out_data"); + return data; +} + +#if DEBUG_LINK + +uint8_t *msg_debug_out_data(void) +{ + if (msg_debug_out_start == msg_debug_out_end) return 0; + uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); + msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64); + debugLog(0, "", "msg_debug_out_data"); + return data; +} + +#endif + +uint8_t msg_tiny[64]; +uint16_t msg_tiny_id = 0xFFFF; + +void msg_read_tiny(uint8_t *buf, int len) +{ + if (len < 9) return; + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { + return; + } + uint16_t msg_id = (buf[3] << 8) + buf[4]; + uint32_t msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + if (msg_size > 64 || len - msg_size < 9) { + return; + } + + const pb_field_t *fields = 0; + pb_istream_t stream = pb_istream_from_buffer(buf + 9, len - 9); + + switch (msg_id) { + case MessageType_MessageType_PinMatrixAck: + fields = PinMatrixAck_fields; + break; + case MessageType_MessageType_ButtonAck: + fields = ButtonAck_fields; + break; + case MessageType_MessageType_PassphraseAck: + fields = PassphraseAck_fields; + break; + case MessageType_MessageType_Cancel: + fields = Cancel_fields; + break; + case MessageType_MessageType_Initialize: + fields = Initialize_fields; + break; +#if DEBUG_LINK + case MessageType_MessageType_DebugLinkDecision: + fields = DebugLinkDecision_fields; + break; + case MessageType_MessageType_DebugLinkGetState: + fields = DebugLinkGetState_fields; + break; +#endif + } + if (fields) { + bool status = pb_decode(&stream, fields, msg_tiny); + if (status) { + msg_tiny_id = msg_id; + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, stream.errmsg); + msg_tiny_id = 0xFFFF; + } + } else { + // fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + msg_tiny_id = 0xFFFF; + } +} diff --git a/firmware/messages.h b/firmware/messages.h new file mode 100644 index 0000000000..6f3b83e2f5 --- /dev/null +++ b/firmware/messages.h @@ -0,0 +1,53 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __MESSAGES_H__ +#define __MESSAGES_H__ + +#include +#include +#include "trezor.h" + +#define MSG_IN_SIZE (24*1024) + +#define MSG_OUT_SIZE (9*1024) + +#define msg_read(buf, len) msg_read_common('n', (buf), (len)) +#define msg_write(id, ptr) msg_write_common('n', (id), (ptr)) +uint8_t *msg_out_data(void); + +#if DEBUG_LINK + +#define MSG_DEBUG_OUT_SIZE (2*1024) + +#define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) +#define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) +uint8_t *msg_debug_out_data(void); + +#endif + +void msg_read_common(char type, uint8_t *buf, int len); +bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr); + +void msg_read_tiny(uint8_t *buf, int len); +void msg_debug_read_tiny(uint8_t *buf, int len); +extern uint8_t msg_tiny[64]; +extern uint16_t msg_tiny_id; + +#endif diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c new file mode 100644 index 0000000000..8212972443 --- /dev/null +++ b/firmware/pinmatrix.c @@ -0,0 +1,87 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "pinmatrix.h" +#include "oled.h" +#include "rng.h" + +static char pinmatrix_perm[10] = "XXXXXXXXX"; + +void pinmatrix_draw(const char *text) +{ + const BITMAP *bmp_digits[10] = { + &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, + &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, + }; + oledSwipeLeft(); + const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; + int i, j, k; + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + // use (2 - j) instead of j to achieve 789456123 layout + k = pinmatrix_perm[i + (2 - j) * 3] - '0'; + if (text) { + oledDrawStringCenter(0, text); + } + oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); + } + } + oledRefresh(); +} + +void pinmatrix_start(const char *text) +{ + int i, j, k; + char t; + + for (i = 0; i < 9; i++) { + pinmatrix_perm[i] = '1' + i; + } + pinmatrix_perm[9] = 0; + for (i = 0; i < 10000; i++) { + j = random32() % 9; + k = random32() % 9; + t = pinmatrix_perm[j]; + pinmatrix_perm[j] = pinmatrix_perm[k]; + pinmatrix_perm[k] = t; + } + pinmatrix_draw(text); +} + +void pinmatrix_done(char *pin) +{ + int k, i = 0; + while (pin && pin[i]) { + k = pin[i] - '1'; + if (k >= 0 && k <= 8) { + pin[i] = pinmatrix_perm[k]; + } else { + pin[i] = 'X'; + } + i++; + } + memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm)); +} + +const char *pinmatrix_get(void) +{ + return pinmatrix_perm; +} diff --git a/firmware/pinmatrix.h b/firmware/pinmatrix.h new file mode 100644 index 0000000000..9c6c312937 --- /dev/null +++ b/firmware/pinmatrix.h @@ -0,0 +1,27 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __PINMATRIX_H__ +#define __PINMATRIX_H__ + +void pinmatrix_start(const char *text); +void pinmatrix_done(char *pin); +const char *pinmatrix_get(void); + +#endif diff --git a/firmware/protect.c b/firmware/protect.c new file mode 100644 index 0000000000..57684a2ed7 --- /dev/null +++ b/firmware/protect.c @@ -0,0 +1,222 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "protect.h" +#include "storage.h" +#include "messages.h" +#include "usb.h" +#include "oled.h" +#include "buttons.h" +#include "pinmatrix.h" +#include "fsm.h" +#include "layout2.h" +#include "util.h" +#include "debug.h" + +bool protectButton(ButtonRequestType type, bool confirm_only) +{ + ButtonRequest resp; + bool result; + bool acked = false; + + memset(&resp, 0, sizeof(ButtonRequest)); + resp.has_code = true; + resp.code = type; + usbTiny(1); + msg_write(MessageType_MessageType_ButtonRequest, &resp); + + for (;;) { + usbPoll(); + + // wait for ButtonAck + if (msg_tiny_id == MessageType_MessageType_ButtonAck) { + msg_tiny_id = 0xFFFF; + acked = true; + } + + // button acked - check buttons + if (acked) { + delay(50000); + buttonUpdate(); + if (button.YesUp) { + result = true; + break; + } + if (!confirm_only && button.NoUp) { + result = false; + break; + } + } + + if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { + if (msg_tiny_id == MessageType_MessageType_Initialize) { + fsm_msgInitialize((Initialize *)msg_tiny); + } + msg_tiny_id = 0xFFFF; + result = false; + break; + } + + // check debug link +#if DEBUG_LINK + if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) { + msg_tiny_id = 0xFFFF; + DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny; + result = dld->yes_no; + break; + } + + if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { + msg_tiny_id = 0xFFFF; + fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); + } +#endif + } + + usbTiny(0); + + return result; +} + +const char *requestPin(PinMatrixRequestType type, const char *text) +{ + PinMatrixRequest resp; + memset(&resp, 0, sizeof(PinMatrixRequest)); + resp.has_type = true; + resp.type = type; + usbTiny(1); + msg_write(MessageType_MessageType_PinMatrixRequest, &resp); + pinmatrix_start(text); + for (;;) { + usbPoll(); + if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) { + msg_tiny_id = 0xFFFF; + PinMatrixAck *pma = (PinMatrixAck *)msg_tiny; + pinmatrix_done(pma->pin); // convert via pinmatrix + usbTiny(0); + return pma->pin; + } + if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { + pinmatrix_done(0); + if (msg_tiny_id == MessageType_MessageType_Initialize) { + fsm_msgInitialize((Initialize *)msg_tiny); + } + msg_tiny_id = 0xFFFF; + usbTiny(0); + return 0; + } +#if DEBUG_LINK + if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { + msg_tiny_id = 0xFFFF; + fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); + } +#endif + } +} + +bool protectPin(bool use_cached) +{ + if (!storage.has_pin || strlen(storage.pin) == 0 || (use_cached && session_isPinCached())) { + return true; + } + const char *pin; + uint32_t wait = storage_getPinFails(); + if (wait) { + if (wait > 4) { + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait ...", NULL, NULL, NULL); + } + wait = (wait < 32) ? (1u << wait) : 0xFFFFFFFF; + while (--wait > 0) { + delay(1000000); + } + } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + return false; + } + if (storage_isPinCorrect(pin)) { + session_cachePin(pin); + storage_resetPinFails(); + return true; + } else { + storage_increasePinFails(); + fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); + return false; + } +} + +bool protectChangePin(void) +{ + const char *pin; + char pin1[17], pin2[17]; + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, "Please enter new PIN:"); + if (!pin) { + return false; + } + strlcpy(pin1, pin, sizeof(pin1)); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, "Please re-enter new PIN:"); + if (!pin) { + return false; + } + strlcpy(pin2, pin, sizeof(pin2)); + if (strcmp(pin1, pin2) == 0) { + storage_setPin(pin1); + return true; + } else { + return false; + } +} + +bool protectPassphrase(void) +{ + if (!storage.has_passphrase_protection || !storage.passphrase_protection || session_isPassphraseCached()) { + return true; + } + + PassphraseRequest resp; + memset(&resp, 0, sizeof(PassphraseRequest)); + usbTiny(1); + msg_write(MessageType_MessageType_PassphraseRequest, &resp); + + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL); + + bool result; + for (;;) { + usbPoll(); + if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { + msg_tiny_id = 0xFFFF; + PassphraseAck *ppa = (PassphraseAck *)msg_tiny; + session_cachePassphrase(ppa->passphrase); + result = true; + break; + } + if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { + if (msg_tiny_id == MessageType_MessageType_Initialize) { + fsm_msgInitialize((Initialize *)msg_tiny); + } + msg_tiny_id = 0xFFFF; + result = false; + break; + } + } + usbTiny(0); + layoutHome(); + return result; +} diff --git a/firmware/protect.h b/firmware/protect.h new file mode 100644 index 0000000000..07fdb2532c --- /dev/null +++ b/firmware/protect.h @@ -0,0 +1,31 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __PROTECT_H__ +#define __PROTECT_H__ + +#include +#include "types.pb.h" + +bool protectButton(ButtonRequestType type, bool confirm_only); +bool protectPin(bool use_cached); +bool protectChangePin(void); +bool protectPassphrase(void); + +#endif diff --git a/firmware/protob/.gitignore b/firmware/protob/.gitignore new file mode 100644 index 0000000000..0a5bea8f2b --- /dev/null +++ b/firmware/protob/.gitignore @@ -0,0 +1 @@ +*.pb diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile new file mode 100644 index 0000000000..f9dd9c718a --- /dev/null +++ b/firmware/protob/Makefile @@ -0,0 +1,10 @@ +all: messages.pb.c storage.pb.c types.pb.c + +%.pb.c: %.pb %.options + nanopb $< -L '#include "%s"' -T + +%.pb: %.proto + protoc -I/usr/include -I. $< -o $@ + +clean: + rm -f *.pb *.o *.pb.c *.pb.h diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options new file mode 100644 index 0000000000..56c540b5e2 --- /dev/null +++ b/firmware/protob/messages.options @@ -0,0 +1,79 @@ +Features.vendor max_size:33 +Features.device_id max_size:25 +Features.language max_size:17 +Features.label max_size:33 +Features.coins max_count:4 +Features.revision max_size:20 +Features.bootloader_hash max_size:32 + +ApplySettings.language max_size:17 +ApplySettings.label max_size:33 + +Ping.message max_size:256 + +Success.message max_size:256 + +Failure.message max_size:256 + +ButtonRequest.data max_size:256 + +PinMatrixAck.pin max_size:10 + +PassphraseAck.passphrase max_size:51 + +Entropy.entropy max_size:1024 + +GetPublicKey.address_n max_count:8 + +GetAddress.address_n max_count:8 +GetAddress.coin_name max_size:17 + +Address.address max_size:35 + +LoadDevice.mnemonic max_size:241 +LoadDevice.pin max_size:10 +LoadDevice.language max_size:17 +LoadDevice.label max_size:33 + +ResetDevice.language max_size:17 +ResetDevice.label max_size:33 + +EntropyAck.entropy max_size:128 + +RecoveryDevice.language max_size:17 +RecoveryDevice.label max_size:33 + +WordAck.word max_size:12 + +SignMessage.address_n max_count:8 +SignMessage.message max_size:256 +SignMessage.coin_name max_size:17 + +VerifyMessage.address max_size:35 +VerifyMessage.signature max_size:65 +VerifyMessage.message max_size:256 + +MessageSignature.address max_size:35 +MessageSignature.signature max_size:65 + +EstimateTxSize.coin_name max_size:17 + +SignTx.coin_name max_size:17 + +SimpleSignTx.inputs max_count:4 +SimpleSignTx.outputs max_count:4 +SimpleSignTx.transactions max_count:4 +SimpleSignTx.coin_name max_size:17 + +FirmwareUpload.payload max_size:0 # not used in firmware + +DebugLinkState.layout max_size:1024 +DebugLinkState.pin max_size:10 +DebugLinkState.matrix max_size:10 +DebugLinkState.mnemonic max_size:241 +DebugLinkState.reset_word max_size:12 +DebugLinkState.reset_entropy max_size:128 +DebugLinkState.recovery_fake_word max_size:12 + +DebugLinkLog.bucket max_size:33 +DebugLinkLog.text max_size:256 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c new file mode 100644 index 0000000000..22578bca68 --- /dev/null +++ b/firmware/protob/messages.pb.c @@ -0,0 +1,305 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.2.7 */ + +#include "messages.pb.h" + +const char GetAddress_coin_name_default[17] = "Bitcoin"; +const char LoadDevice_language_default[17] = "english"; +const uint32_t ResetDevice_strength_default = 128u; +const char ResetDevice_language_default[17] = "english"; +const char RecoveryDevice_language_default[17] = "english"; +const char SignMessage_coin_name_default[17] = "Bitcoin"; +const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; +const char SignTx_coin_name_default[17] = "Bitcoin"; +const char SimpleSignTx_coin_name_default[17] = "Bitcoin"; + + +const pb_field_t Initialize_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t Features_fields[15] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), + PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), + PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), + PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), + PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), + PB_FIELD2( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), + PB_FIELD2( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), + PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), + PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), + PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), + PB_LAST_FIELD +}; + +const pb_field_t ApplySettings_fields[3] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), + PB_LAST_FIELD +}; + +const pb_field_t ChangePin_fields[2] = { + PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), + PB_LAST_FIELD +}; + +const pb_field_t Ping_fields[5] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), + PB_LAST_FIELD +}; + +const pb_field_t Success_fields[2] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t Failure_fields[3] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), + PB_LAST_FIELD +}; + +const pb_field_t ButtonRequest_fields[3] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), + PB_LAST_FIELD +}; + +const pb_field_t ButtonAck_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PinMatrixRequest_fields[2] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), + PB_LAST_FIELD +}; + +const pb_field_t PinMatrixAck_fields[2] = { + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), + PB_LAST_FIELD +}; + +const pb_field_t Cancel_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PassphraseRequest_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t PassphraseAck_fields[2] = { + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetEntropy_fields[2] = { + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), + PB_LAST_FIELD +}; + +const pb_field_t Entropy_fields[2] = { + PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), + PB_LAST_FIELD +}; + +const pb_field_t GetPublicKey_fields[2] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), + PB_LAST_FIELD +}; + +const pb_field_t PublicKey_fields[2] = { + PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), + PB_LAST_FIELD +}; + +const pb_field_t GetAddress_fields[3] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), + PB_LAST_FIELD +}; + +const pb_field_t Address_fields[2] = { + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t WipeDevice_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t LoadDevice_fields[8] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), + PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), + PB_LAST_FIELD +}; + +const pb_field_t ResetDevice_fields[7] = { + PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), + PB_LAST_FIELD +}; + +const pb_field_t EntropyRequest_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t EntropyAck_fields[2] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), + PB_LAST_FIELD +}; + +const pb_field_t RecoveryDevice_fields[7] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), + PB_LAST_FIELD +}; + +const pb_field_t WordRequest_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t WordAck_fields[2] = { + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignMessage_fields[4] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), + PB_LAST_FIELD +}; + +const pb_field_t VerifyMessage_fields[4] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), + PB_LAST_FIELD +}; + +const pb_field_t MessageSignature_fields[3] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t EstimateTxSize_fields[4] = { + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), + PB_LAST_FIELD +}; + +const pb_field_t TxSize_fields[2] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignTx_fields[4] = { + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), + PB_LAST_FIELD +}; + +const pb_field_t SimpleSignTx_fields[5] = { + PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), + PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), + PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), + PB_LAST_FIELD +}; + +const pb_field_t TxRequest_fields[4] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), + PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), + PB_LAST_FIELD +}; + +const pb_field_t TxAck_fields[2] = { + PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), + PB_LAST_FIELD +}; + +const pb_field_t FirmwareErase_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t FirmwareUpload_fields[2] = { + PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkDecision_fields[2] = { + PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkGetState_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkState_fields[11] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), + PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), + PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), + PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), + PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), + PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkStop_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkLog_fields[4] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +#error Field descriptor for Entropy.entropy is too large. Define PB_FIELD_16BIT to fix this. +#endif + + diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h new file mode 100644 index 0000000000..225e8ab092 --- /dev/null +++ b/firmware/protob/messages.pb.h @@ -0,0 +1,639 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.2.7 */ + +#ifndef _PB_MESSAGES_PB_H_ +#define _PB_MESSAGES_PB_H_ +#include "pb.h" +#include "types.pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +typedef enum _MessageType { + MessageType_MessageType_Initialize = 0, + MessageType_MessageType_Ping = 1, + MessageType_MessageType_Success = 2, + MessageType_MessageType_Failure = 3, + MessageType_MessageType_ChangePin = 4, + MessageType_MessageType_WipeDevice = 5, + MessageType_MessageType_FirmwareErase = 6, + MessageType_MessageType_FirmwareUpload = 7, + MessageType_MessageType_GetEntropy = 9, + MessageType_MessageType_Entropy = 10, + MessageType_MessageType_GetPublicKey = 11, + MessageType_MessageType_PublicKey = 12, + MessageType_MessageType_LoadDevice = 13, + MessageType_MessageType_ResetDevice = 14, + MessageType_MessageType_SignTx = 15, + MessageType_MessageType_SimpleSignTx = 16, + MessageType_MessageType_Features = 17, + MessageType_MessageType_PinMatrixRequest = 18, + MessageType_MessageType_PinMatrixAck = 19, + MessageType_MessageType_Cancel = 20, + MessageType_MessageType_TxRequest = 21, + MessageType_MessageType_TxAck = 22, + MessageType_MessageType_ApplySettings = 25, + MessageType_MessageType_ButtonRequest = 26, + MessageType_MessageType_ButtonAck = 27, + MessageType_MessageType_GetAddress = 29, + MessageType_MessageType_Address = 30, + MessageType_MessageType_EntropyRequest = 35, + MessageType_MessageType_EntropyAck = 36, + MessageType_MessageType_SignMessage = 38, + MessageType_MessageType_VerifyMessage = 39, + MessageType_MessageType_MessageSignature = 40, + MessageType_MessageType_PassphraseRequest = 41, + MessageType_MessageType_PassphraseAck = 42, + MessageType_MessageType_EstimateTxSize = 43, + MessageType_MessageType_TxSize = 44, + MessageType_MessageType_RecoveryDevice = 45, + MessageType_MessageType_WordRequest = 46, + MessageType_MessageType_WordAck = 47, + MessageType_MessageType_DebugLinkDecision = 100, + MessageType_MessageType_DebugLinkGetState = 101, + MessageType_MessageType_DebugLinkState = 102, + MessageType_MessageType_DebugLinkStop = 103, + MessageType_MessageType_DebugLinkLog = 104 +} MessageType; + +/* Struct definitions */ +typedef struct _ButtonAck { + uint8_t dummy_field; +} ButtonAck; + +typedef struct _Cancel { + uint8_t dummy_field; +} Cancel; + +typedef struct _DebugLinkGetState { + uint8_t dummy_field; +} DebugLinkGetState; + +typedef struct _DebugLinkStop { + uint8_t dummy_field; +} DebugLinkStop; + +typedef struct _EntropyRequest { + uint8_t dummy_field; +} EntropyRequest; + +typedef struct _FirmwareErase { + uint8_t dummy_field; +} FirmwareErase; + +typedef struct _Initialize { + uint8_t dummy_field; +} Initialize; + +typedef struct _PassphraseRequest { + uint8_t dummy_field; +} PassphraseRequest; + +typedef struct _WipeDevice { + uint8_t dummy_field; +} WipeDevice; + +typedef struct _WordRequest { + uint8_t dummy_field; +} WordRequest; + +typedef struct _Address { + char address[35]; +} Address; + +typedef struct _ApplySettings { + bool has_language; + char language[17]; + bool has_label; + char label[33]; +} ApplySettings; + +typedef struct _ButtonRequest { + bool has_code; + ButtonRequestType code; + bool has_data; + char data[256]; +} ButtonRequest; + +typedef struct _ChangePin { + bool has_remove; + bool remove; +} ChangePin; + +typedef struct _DebugLinkDecision { + bool yes_no; +} DebugLinkDecision; + +typedef struct _DebugLinkLog { + bool has_level; + uint32_t level; + bool has_bucket; + char bucket[33]; + bool has_text; + char text[256]; +} DebugLinkLog; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DebugLinkState_layout_t; + +typedef struct { + size_t size; + uint8_t bytes[128]; +} DebugLinkState_reset_entropy_t; + +typedef struct _DebugLinkState { + bool has_layout; + DebugLinkState_layout_t layout; + bool has_pin; + char pin[10]; + bool has_matrix; + char matrix[10]; + bool has_mnemonic; + char mnemonic[241]; + bool has_node; + HDNodeType node; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_reset_word; + char reset_word[12]; + bool has_reset_entropy; + DebugLinkState_reset_entropy_t reset_entropy; + bool has_recovery_fake_word; + char recovery_fake_word[12]; + bool has_recovery_word_pos; + uint32_t recovery_word_pos; +} DebugLinkState; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} Entropy_entropy_t; + +typedef struct _Entropy { + Entropy_entropy_t entropy; +} Entropy; + +typedef struct { + size_t size; + uint8_t bytes[128]; +} EntropyAck_entropy_t; + +typedef struct _EntropyAck { + bool has_entropy; + EntropyAck_entropy_t entropy; +} EntropyAck; + +typedef struct _EstimateTxSize { + uint32_t outputs_count; + uint32_t inputs_count; + bool has_coin_name; + char coin_name[17]; +} EstimateTxSize; + +typedef struct _Failure { + bool has_code; + FailureType code; + bool has_message; + char message[256]; +} Failure; + +typedef struct { + size_t size; + uint8_t bytes[20]; +} Features_revision_t; + +typedef struct { + size_t size; + uint8_t bytes[32]; +} Features_bootloader_hash_t; + +typedef struct _Features { + bool has_vendor; + char vendor[33]; + bool has_major_version; + uint32_t major_version; + bool has_minor_version; + uint32_t minor_version; + bool has_patch_version; + uint32_t patch_version; + bool has_bootloader_mode; + bool bootloader_mode; + bool has_device_id; + char device_id[25]; + bool has_pin_protection; + bool pin_protection; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_language; + char language[17]; + bool has_label; + char label[33]; + size_t coins_count; + CoinType coins[4]; + bool has_initialized; + bool initialized; + bool has_revision; + Features_revision_t revision; + bool has_bootloader_hash; + Features_bootloader_hash_t bootloader_hash; +} Features; + +typedef struct { + size_t size; + uint8_t bytes[0]; +} FirmwareUpload_payload_t; + +typedef struct _FirmwareUpload { + FirmwareUpload_payload_t payload; +} FirmwareUpload; + +typedef struct _GetAddress { + size_t address_n_count; + uint32_t address_n[8]; + bool has_coin_name; + char coin_name[17]; +} GetAddress; + +typedef struct _GetEntropy { + uint32_t size; +} GetEntropy; + +typedef struct _GetPublicKey { + size_t address_n_count; + uint32_t address_n[8]; +} GetPublicKey; + +typedef struct _LoadDevice { + bool has_mnemonic; + char mnemonic[241]; + bool has_node; + HDNodeType node; + bool has_pin; + char pin[10]; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_language; + char language[17]; + bool has_label; + char label[33]; + bool has_skip_checksum; + bool skip_checksum; +} LoadDevice; + +typedef struct { + size_t size; + uint8_t bytes[65]; +} MessageSignature_signature_t; + +typedef struct _MessageSignature { + bool has_address; + char address[35]; + bool has_signature; + MessageSignature_signature_t signature; +} MessageSignature; + +typedef struct _PassphraseAck { + char passphrase[51]; +} PassphraseAck; + +typedef struct _PinMatrixAck { + char pin[10]; +} PinMatrixAck; + +typedef struct _PinMatrixRequest { + bool has_type; + PinMatrixRequestType type; +} PinMatrixRequest; + +typedef struct _Ping { + bool has_message; + char message[256]; + bool has_button_protection; + bool button_protection; + bool has_pin_protection; + bool pin_protection; + bool has_passphrase_protection; + bool passphrase_protection; +} Ping; + +typedef struct _PublicKey { + HDNodeType node; +} PublicKey; + +typedef struct _RecoveryDevice { + bool has_word_count; + uint32_t word_count; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_pin_protection; + bool pin_protection; + bool has_language; + char language[17]; + bool has_label; + char label[33]; + bool has_enforce_wordlist; + bool enforce_wordlist; +} RecoveryDevice; + +typedef struct _ResetDevice { + bool has_display_random; + bool display_random; + bool has_strength; + uint32_t strength; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_pin_protection; + bool pin_protection; + bool has_language; + char language[17]; + bool has_label; + char label[33]; +} ResetDevice; + +typedef struct { + size_t size; + uint8_t bytes[256]; +} SignMessage_message_t; + +typedef struct _SignMessage { + size_t address_n_count; + uint32_t address_n[8]; + SignMessage_message_t message; + bool has_coin_name; + char coin_name[17]; +} SignMessage; + +typedef struct _SignTx { + uint32_t outputs_count; + uint32_t inputs_count; + bool has_coin_name; + char coin_name[17]; +} SignTx; + +typedef struct _SimpleSignTx { + size_t inputs_count; + TxInputType inputs[4]; + size_t outputs_count; + TxOutputType outputs[4]; + size_t transactions_count; + TransactionType transactions[4]; + bool has_coin_name; + char coin_name[17]; +} SimpleSignTx; + +typedef struct _Success { + bool has_message; + char message[256]; +} Success; + +typedef struct _TxAck { + bool has_tx; + TransactionType tx; +} TxAck; + +typedef struct _TxRequest { + bool has_request_type; + RequestType request_type; + bool has_details; + TxRequestDetailsType details; + bool has_serialized; + TxRequestSerializedType serialized; +} TxRequest; + +typedef struct _TxSize { + bool has_tx_size; + uint32_t tx_size; +} TxSize; + +typedef struct { + size_t size; + uint8_t bytes[65]; +} VerifyMessage_signature_t; + +typedef struct { + size_t size; + uint8_t bytes[256]; +} VerifyMessage_message_t; + +typedef struct _VerifyMessage { + bool has_address; + char address[35]; + bool has_signature; + VerifyMessage_signature_t signature; + bool has_message; + VerifyMessage_message_t message; +} VerifyMessage; + +typedef struct _WordAck { + char word[12]; +} WordAck; + +/* Default values for struct fields */ +extern const char GetAddress_coin_name_default[17]; +extern const char LoadDevice_language_default[17]; +extern const uint32_t ResetDevice_strength_default; +extern const char ResetDevice_language_default[17]; +extern const char RecoveryDevice_language_default[17]; +extern const char SignMessage_coin_name_default[17]; +extern const char EstimateTxSize_coin_name_default[17]; +extern const char SignTx_coin_name_default[17]; +extern const char SimpleSignTx_coin_name_default[17]; + +/* Field tags (for use in manual encoding/decoding) */ +#define Address_address_tag 1 +#define ApplySettings_language_tag 1 +#define ApplySettings_label_tag 2 +#define ButtonRequest_code_tag 1 +#define ButtonRequest_data_tag 2 +#define ChangePin_remove_tag 1 +#define DebugLinkDecision_yes_no_tag 1 +#define DebugLinkLog_level_tag 1 +#define DebugLinkLog_bucket_tag 2 +#define DebugLinkLog_text_tag 3 +#define DebugLinkState_layout_tag 1 +#define DebugLinkState_pin_tag 2 +#define DebugLinkState_matrix_tag 3 +#define DebugLinkState_mnemonic_tag 4 +#define DebugLinkState_node_tag 5 +#define DebugLinkState_passphrase_protection_tag 6 +#define DebugLinkState_reset_word_tag 7 +#define DebugLinkState_reset_entropy_tag 8 +#define DebugLinkState_recovery_fake_word_tag 9 +#define DebugLinkState_recovery_word_pos_tag 10 +#define Entropy_entropy_tag 1 +#define EntropyAck_entropy_tag 1 +#define EstimateTxSize_outputs_count_tag 1 +#define EstimateTxSize_inputs_count_tag 2 +#define EstimateTxSize_coin_name_tag 3 +#define Failure_code_tag 1 +#define Failure_message_tag 2 +#define Features_vendor_tag 1 +#define Features_major_version_tag 2 +#define Features_minor_version_tag 3 +#define Features_patch_version_tag 4 +#define Features_bootloader_mode_tag 5 +#define Features_device_id_tag 6 +#define Features_pin_protection_tag 7 +#define Features_passphrase_protection_tag 8 +#define Features_language_tag 9 +#define Features_label_tag 10 +#define Features_coins_tag 11 +#define Features_initialized_tag 12 +#define Features_revision_tag 13 +#define Features_bootloader_hash_tag 14 +#define FirmwareUpload_payload_tag 1 +#define GetAddress_address_n_tag 1 +#define GetAddress_coin_name_tag 2 +#define GetEntropy_size_tag 1 +#define GetPublicKey_address_n_tag 1 +#define LoadDevice_mnemonic_tag 1 +#define LoadDevice_node_tag 2 +#define LoadDevice_pin_tag 3 +#define LoadDevice_passphrase_protection_tag 4 +#define LoadDevice_language_tag 5 +#define LoadDevice_label_tag 6 +#define LoadDevice_skip_checksum_tag 7 +#define MessageSignature_address_tag 1 +#define MessageSignature_signature_tag 2 +#define PassphraseAck_passphrase_tag 1 +#define PinMatrixAck_pin_tag 1 +#define PinMatrixRequest_type_tag 1 +#define Ping_message_tag 1 +#define Ping_button_protection_tag 2 +#define Ping_pin_protection_tag 3 +#define Ping_passphrase_protection_tag 4 +#define PublicKey_node_tag 1 +#define RecoveryDevice_word_count_tag 1 +#define RecoveryDevice_passphrase_protection_tag 2 +#define RecoveryDevice_pin_protection_tag 3 +#define RecoveryDevice_language_tag 4 +#define RecoveryDevice_label_tag 5 +#define RecoveryDevice_enforce_wordlist_tag 6 +#define ResetDevice_display_random_tag 1 +#define ResetDevice_strength_tag 2 +#define ResetDevice_passphrase_protection_tag 3 +#define ResetDevice_pin_protection_tag 4 +#define ResetDevice_language_tag 5 +#define ResetDevice_label_tag 6 +#define SignMessage_address_n_tag 1 +#define SignMessage_message_tag 2 +#define SignMessage_coin_name_tag 3 +#define SignTx_outputs_count_tag 1 +#define SignTx_inputs_count_tag 2 +#define SignTx_coin_name_tag 3 +#define SimpleSignTx_inputs_tag 1 +#define SimpleSignTx_outputs_tag 2 +#define SimpleSignTx_transactions_tag 3 +#define SimpleSignTx_coin_name_tag 4 +#define Success_message_tag 1 +#define TxAck_tx_tag 1 +#define TxRequest_request_type_tag 1 +#define TxRequest_details_tag 2 +#define TxRequest_serialized_tag 3 +#define TxSize_tx_size_tag 1 +#define VerifyMessage_address_tag 1 +#define VerifyMessage_signature_tag 2 +#define VerifyMessage_message_tag 3 +#define WordAck_word_tag 1 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t Initialize_fields[1]; +extern const pb_field_t Features_fields[15]; +extern const pb_field_t ApplySettings_fields[3]; +extern const pb_field_t ChangePin_fields[2]; +extern const pb_field_t Ping_fields[5]; +extern const pb_field_t Success_fields[2]; +extern const pb_field_t Failure_fields[3]; +extern const pb_field_t ButtonRequest_fields[3]; +extern const pb_field_t ButtonAck_fields[1]; +extern const pb_field_t PinMatrixRequest_fields[2]; +extern const pb_field_t PinMatrixAck_fields[2]; +extern const pb_field_t Cancel_fields[1]; +extern const pb_field_t PassphraseRequest_fields[1]; +extern const pb_field_t PassphraseAck_fields[2]; +extern const pb_field_t GetEntropy_fields[2]; +extern const pb_field_t Entropy_fields[2]; +extern const pb_field_t GetPublicKey_fields[2]; +extern const pb_field_t PublicKey_fields[2]; +extern const pb_field_t GetAddress_fields[3]; +extern const pb_field_t Address_fields[2]; +extern const pb_field_t WipeDevice_fields[1]; +extern const pb_field_t LoadDevice_fields[8]; +extern const pb_field_t ResetDevice_fields[7]; +extern const pb_field_t EntropyRequest_fields[1]; +extern const pb_field_t EntropyAck_fields[2]; +extern const pb_field_t RecoveryDevice_fields[7]; +extern const pb_field_t WordRequest_fields[1]; +extern const pb_field_t WordAck_fields[2]; +extern const pb_field_t SignMessage_fields[4]; +extern const pb_field_t VerifyMessage_fields[4]; +extern const pb_field_t MessageSignature_fields[3]; +extern const pb_field_t EstimateTxSize_fields[4]; +extern const pb_field_t TxSize_fields[2]; +extern const pb_field_t SignTx_fields[4]; +extern const pb_field_t SimpleSignTx_fields[5]; +extern const pb_field_t TxRequest_fields[4]; +extern const pb_field_t TxAck_fields[2]; +extern const pb_field_t FirmwareErase_fields[1]; +extern const pb_field_t FirmwareUpload_fields[2]; +extern const pb_field_t DebugLinkDecision_fields[2]; +extern const pb_field_t DebugLinkGetState_fields[1]; +extern const pb_field_t DebugLinkState_fields[11]; +extern const pb_field_t DebugLinkStop_fields[1]; +extern const pb_field_t DebugLinkLog_fields[4]; + +/* Maximum encoded size of messages (where known) */ +#define Initialize_size 0 +#define Features_size (222 + 4*CoinType_size) +#define ApplySettings_size 54 +#define ChangePin_size 2 +#define Ping_size 265 +#define Success_size 259 +#define Failure_size 265 +#define ButtonRequest_size 265 +#define ButtonAck_size 0 +#define PinMatrixRequest_size 6 +#define PinMatrixAck_size 12 +#define Cancel_size 0 +#define PassphraseRequest_size 0 +#define PassphraseAck_size 53 +#define GetEntropy_size 6 +#define Entropy_size 1027 +#define GetPublicKey_size 48 +#define PublicKey_size (6 + HDNodeType_size) +#define GetAddress_size 67 +#define Address_size 37 +#define WipeDevice_size 0 +#define LoadDevice_size (320 + HDNodeType_size) +#define ResetDevice_size 66 +#define EntropyRequest_size 0 +#define EntropyAck_size 131 +#define RecoveryDevice_size 66 +#define WordRequest_size 0 +#define WordAck_size 14 +#define SignMessage_size 326 +#define VerifyMessage_size 363 +#define MessageSignature_size 104 +#define EstimateTxSize_size 31 +#define TxSize_size 6 +#define SignTx_size 31 +#define SimpleSignTx_size (91 + 4*TxInputType_size + 4*TxOutputType_size + 4*TransactionType_size) +#define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) +#define TxAck_size (6 + TransactionType_size) +#define FirmwareErase_size 0 +#define FirmwareUpload_size 2 +#define DebugLinkDecision_size 2 +#define DebugLinkGetState_size 0 +#define DebugLinkState_size (1468 + HDNodeType_size) +#define DebugLinkStop_size 0 +#define DebugLinkLog_size 300 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/protob/messages.proto b/firmware/protob/messages.proto new file mode 120000 index 0000000000..f788ef73ab --- /dev/null +++ b/firmware/protob/messages.proto @@ -0,0 +1 @@ +../../trezor-common/protob/messages.proto \ No newline at end of file diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h new file mode 100644 index 0000000000..b5cb3ea4b9 --- /dev/null +++ b/firmware/protob/pb.h @@ -0,0 +1,519 @@ +/* Common parts of the nanopb library. Most of these are quite low-level + * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. + */ + +#ifndef _PB_H_ +#define _PB_H_ + +/***************************************************************** + * Nanopb compilation time options. You can change these here by * + * uncommenting the lines, or on the compiler command line. * + *****************************************************************/ + +/* Enable support for dynamically allocated fields */ +/* #define PB_ENABLE_MALLOC 1 */ + +/* Define this if your CPU architecture is big endian, i.e. it + * stores the most-significant byte first. */ +/* #define __BIG_ENDIAN__ 1 */ + +/* Increase the number of required fields that are tracked. + * A compiler warning will tell if you need this. */ +/* #define PB_MAX_REQUIRED_FIELDS 256 */ + +/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ +/* #define PB_FIELD_16BIT 1 */ + +/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ +/* #define PB_FIELD_32BIT 1 */ + +/* Disable support for error messages in order to save some code space. */ +/* #define PB_NO_ERRMSG 1 */ + +/* Disable support for custom streams (support only memory buffers). */ +/* #define PB_BUFFER_ONLY 1 */ + +/* Switch back to the old-style callback function signature. + * This was the default until nanopb-0.2.1. */ +/* #define PB_OLD_CALLBACK_STYLE */ + + +/****************************************************************** + * You usually don't need to change anything below this line. * + * Feel free to look around and use the defined macros, though. * + ******************************************************************/ + + +/* Version of the nanopb library. Just in case you want to check it in + * your own program. */ +#define NANOPB_VERSION nanopb-0.2.7 + +/* Include all the system headers needed by nanopb. You will need the + * definitions of the following: + * - strlen, memcpy, memset functions + * - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t + * - size_t + * - bool + * + * If you don't have the standard header files, you can instead provide + * a custom header that defines or includes all this. In that case, + * define PB_SYSTEM_HEADER to the path of this file. + */ +#ifdef PB_SYSTEM_HEADER +#include PB_SYSTEM_HEADER +#else +#include +#include +#include +#include + +#ifdef PB_ENABLE_MALLOC +#include +#endif +#endif + +/* Macro for defining packed structures (compiler dependent). + * This just reduces memory requirements, but is not required. + */ +#if defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed __attribute__((packed)) +#elif defined(__ICCARM__) + /* For IAR ARM compiler */ +# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +# define pb_packed +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) + /* For Microsoft Visual C++ */ +# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +# define PB_PACKED_STRUCT_END __pragma(pack(pop)) +# define pb_packed +#else + /* Unknown compiler */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#endif + +/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ +#ifndef UNUSED +#define UNUSED(x) (void)(x) +#endif + +/* Compile-time assertion, used for checking compatible compilation options. + * If this does not work properly on your compiler, use #define STATIC_ASSERT + * to disable it. + * + * But before doing that, check carefully the error message / place where it + * comes from to see if the error has a real cause. Unfortunately the error + * message is not always very clear to read, but you can see the reason better + * in the place where the STATIC_ASSERT macro was called. + */ +#ifndef STATIC_ASSERT +#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER +#endif + +/* Number of required fields to keep track of. */ +#ifndef PB_MAX_REQUIRED_FIELDS +#define PB_MAX_REQUIRED_FIELDS 64 +#endif + +#if PB_MAX_REQUIRED_FIELDS < 64 +#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). +#endif + +/* List of possible field types. These are used in the autogenerated code. + * Least-significant 4 bits tell the scalar type + * Most-significant 4 bits specify repeated/required/packed etc. + */ + +typedef uint8_t pb_type_t; + +/**** Field data types ****/ + +/* Numeric types */ +#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ + +/* Marker for last packable field type. */ +#define PB_LTYPE_LAST_PACKABLE 0x04 + +/* Byte array with pre-allocated buffer. + * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ +#define PB_LTYPE_BYTES 0x05 + +/* String with pre-allocated buffer. + * data_size is the maximum length. */ +#define PB_LTYPE_STRING 0x06 + +/* Submessage + * submsg_fields is pointer to field descriptions */ +#define PB_LTYPE_SUBMESSAGE 0x07 + +/* Extension pseudo-field + * The field contains a pointer to pb_extension_t */ +#define PB_LTYPE_EXTENSION 0x08 + +/* Number of declared LTYPES */ +#define PB_LTYPES_COUNT 9 +#define PB_LTYPE_MASK 0x0F + +/**** Field repetition rules ****/ + +#define PB_HTYPE_REQUIRED 0x00 +#define PB_HTYPE_OPTIONAL 0x10 +#define PB_HTYPE_REPEATED 0x20 +#define PB_HTYPE_MASK 0x30 + +/**** Field allocation types ****/ + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 +#define PB_ATYPE_CALLBACK 0x40 +#define PB_ATYPE_MASK 0xC0 + +#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) + +/* Data type used for storing sizes of struct fields + * and array counts. + */ +#if defined(PB_FIELD_32BIT) + typedef uint32_t pb_size_t; + typedef int32_t pb_ssize_t; +#elif defined(PB_FIELD_16BIT) + typedef uint16_t pb_size_t; + typedef int16_t pb_ssize_t; +#else + typedef uint8_t pb_size_t; + typedef int8_t pb_ssize_t; +#endif + +/* This structure is used in auto-generated constants + * to specify struct fields. + * You can change field sizes if you need structures + * larger than 256 bytes or field tags larger than 256. + * The compiler should complain if your .proto has such + * structures. Fix that by defining PB_FIELD_16BIT or + * PB_FIELD_32BIT. + */ +PB_PACKED_STRUCT_START +typedef struct _pb_field_t pb_field_t; +struct _pb_field_t { + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; +} pb_packed; +PB_PACKED_STRUCT_END + +/* Make sure that the standard integer types are of the expected sizes. + * All kinds of things may break otherwise.. atleast all fixed* types. + * + * If you get errors here, it probably means that your stdint.h is not + * correct for your platform. + */ +STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) + +/* This structure is used for 'bytes' arrays. + * It has the number of bytes in the beginning, and after that an array. + * Note that actual structs used will have a different length of bytes array. + */ +#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) + +struct _pb_bytes_array_t { + size_t size; + uint8_t bytes[1]; +}; +typedef struct _pb_bytes_array_t pb_bytes_array_t; + +/* This structure is used for giving the callback function. + * It is stored in the message structure and filled in by the method that + * calls pb_decode. + * + * The decoding callback will be given a limited-length stream + * If the wire type was string, the length is the length of the string. + * If the wire type was a varint/fixed32/fixed64, the length is the length + * of the actual value. + * The function may be called multiple times (especially for repeated types, + * but also otherwise if the message happens to contain the field multiple + * times.) + * + * The encoding callback will receive the actual output stream. + * It should write all the data in one call, including the field tag and + * wire type. It can write multiple fields. + * + * The callback can be null if you want to skip a field. + */ +typedef struct _pb_istream_t pb_istream_t; +typedef struct _pb_ostream_t pb_ostream_t; +typedef struct _pb_callback_t pb_callback_t; +struct _pb_callback_t { +#ifdef PB_OLD_CALLBACK_STYLE + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); + } funcs; +#else + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; +}; + +/* Wire types. Library user needs these only in encoder callbacks. */ +typedef enum { + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 +} pb_wire_type_t; + +/* Structure for defining the handling of unknown/extension fields. + * Usually the pb_extension_type_t structure is automatically generated, + * while the pb_extension_t structure is created by the user. However, + * if you want to catch all unknown fields, you can also create a custom + * pb_extension_type_t with your own callback. + */ +typedef struct _pb_extension_type_t pb_extension_type_t; +typedef struct _pb_extension_t pb_extension_t; +struct _pb_extension_type_t { + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, + uint32_t tag, pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; +}; + +struct _pb_extension_t { + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; +}; + +/* Memory allocation functions to use. You can define pb_realloc and + * pb_free to custom functions if you want. */ +#ifdef PB_ENABLE_MALLOC +# ifndef pb_realloc +# define pb_realloc(ptr, size) realloc(ptr, size) +# endif +# ifndef pb_free +# define pb_free(ptr) free(ptr) +# endif +#endif + +/* These macros are used to declare pb_field_t's in the constant array. */ +/* Size of a structure member, in bytes. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +/* Number of entries in an array. */ +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +/* Delta from start of one member to the start of another member. */ +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +/* Marks the end of the field list */ +#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} + +/* Macros for filling in the data_offset field */ +/* data_offset for first field in a message */ +#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) +/* data_offset for subsequent fields */ +#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) + +/* Required fields are the simplest. They just have delta (padding) from + * previous field end, and the size of the field. Pointer is used for + * submessages and default values. + */ +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional fields add the delta to the has_ variable. */ +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, \ + pb_delta(st, has_ ## m, m), \ + pb_membersize(st, m), 0, ptr} + +/* Repeated fields have a _count field and also the maximum number of entries. */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ + fd, \ + pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr} + +/* Allocated fields carry the size of the actual data, not the pointer */ +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Optional fields don't need a has_ variable, as information would be redundant */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Repeated fields have a _count field and a pointer to array of pointers */ +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ + fd, pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), 0, ptr} + +/* Callbacks are much like required fields except with special datatype. */ +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional extensions don't have the has_ field, as that would be redundant. */ +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + 0, \ + 0, \ + pb_membersize(st, m), 0, ptr} + +#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + 0, 0, pb_membersize(st, m), 0, ptr} + +/* The mapping from protobuf types to LTYPEs is done using these macros. */ +#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION + +/* This is the actual macro used in field descriptions. + * It takes these arguments: + * - Field tag number + * - Field type: BOOL, BYTES, DOUBLE, ENUM, FIXED32, FIXED64, + * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 + * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION + * - Field rules: REQUIRED, OPTIONAL or REPEATED + * - Allocation: STATIC or CALLBACK + * - Message name + * - Field name + * - Previous field name (or field name again for first field) + * - Pointer to default value or submsg fields. + */ + +#define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_CHOOSE(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* This is a new version of the macro used by nanopb generator from + * version 0.2.3 onwards. It avoids the use of a ternary expression in + * the initialization, which confused some compilers. + * + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * + */ +#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + + +/* These macros are used for giving out error messages. + * They are mostly a debugging aid; the main error information + * is the true/false return value from functions. + * Some code space can be saved by disabling the error + * messages if not used. + */ +#ifdef PB_NO_ERRMSG +#define PB_RETURN_ERROR(stream,msg) \ + do {\ + UNUSED(stream); \ + return false; \ + } while(0) +#define PB_GET_ERROR(stream) "(errmsg disabled)" +#else +#define PB_RETURN_ERROR(stream,msg) \ + do {\ + if ((stream)->errmsg == NULL) \ + (stream)->errmsg = (msg); \ + return false; \ + } while(0) +#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") +#endif + +#endif diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c new file mode 100644 index 0000000000..9a48c60fcd --- /dev/null +++ b/firmware/protob/pb_decode.c @@ -0,0 +1,1178 @@ +/* pb_decode.c -- decode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +#include "pb.h" +#include "pb_decode.h" + +/************************************** + * Declarations internal to this file * + **************************************/ + +/* Iterator for pb_field_t list */ +typedef struct { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned field_index; /* Zero-based index of the field. */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to the destination structure to decode to */ + void *pData; /* Pointer where to store current field value */ + void *pSize; /* Pointer where to store the size of current array field */ +} pb_field_iterator_t; + +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); +static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); +static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); +static bool pb_field_next(pb_field_iterator_t *iter); +static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn find_extension_field(pb_field_iterator_t *iter); +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_skip_varint(pb_istream_t *stream); +static bool checkreturn pb_skip_string(pb_istream_t *stream); + +/* --- Function pointers to field decoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_varint, + &pb_dec_uvarint, + &pb_dec_svarint, + &pb_dec_fixed32, + &pb_dec_fixed64, + + &pb_dec_bytes, + &pb_dec_string, + &pb_dec_submessage, + NULL /* extensions */ +}; + +/******************************* + * pb_istream_t implementation * + *******************************/ + +static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) +{ + uint8_t *source = (uint8_t*)stream->state; + stream->state = source + count; + + if (buf != NULL) + { + while (count--) + *buf++ = *source++; + } + + return true; +} + +bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) +{ +#ifndef PB_BUFFER_ONLY + if (buf == NULL && stream->callback != buf_read) + { + /* Skip input bytes */ + uint8_t tmp[16]; + while (count > 16) + { + if (!pb_read(stream, tmp, 16)) + return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } +#endif + + if (stream->bytes_left < count) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!buf_read(stream, buf, count)) + return false; +#endif + + stream->bytes_left -= count; + return true; +} + +/* Read a single byte from input stream. buf may not be NULL. + * This is an optimization for the varint decoding. */ +static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) +{ + if (stream->bytes_left == 0) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, 1)) + PB_RETURN_ERROR(stream, "io error"); +#else + *buf = *(uint8_t*)stream->state; + stream->state = (uint8_t*)stream->state + 1; +#endif + + stream->bytes_left--; + + return true; +} + +pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) +{ + pb_istream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = NULL; +#else + stream.callback = &buf_read; +#endif + stream.state = buf; + stream.bytes_left = bufsize; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +/******************** + * Helper functions * + ********************/ + +static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + uint8_t byte; + uint32_t result; + + if (!pb_readbyte(stream, &byte)) + return false; + + if ((byte & 0x80) == 0) + { + /* Quick case, 1 byte value */ + result = byte; + } + else + { + /* Multibyte case */ + uint8_t bitpos = 7; + result = byte & 0x7F; + + do + { + if (bitpos >= 32) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint32_t)(byte & 0x7F) << bitpos; + bitpos = (uint8_t)(bitpos + 7); + } while (byte & 0x80); + } + + *dest = result; + return true; +} + +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) +{ + uint8_t byte; + uint8_t bitpos = 0; + uint64_t result = 0; + + do + { + if (bitpos >= 64) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; +} + +bool checkreturn pb_skip_varint(pb_istream_t *stream) +{ + uint8_t byte; + do + { + if (!pb_read(stream, &byte, 1)) + return false; + } while (byte & 0x80); + return true; +} + +bool checkreturn pb_skip_string(pb_istream_t *stream) +{ + uint32_t length; + if (!pb_decode_varint32(stream, &length)) + return false; + + return pb_read(stream, NULL, length); +} + +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) +{ + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t) 0; + *tag = 0; + + if (!pb_decode_varint32(stream, &temp)) + { + if (stream->bytes_left == 0) + *eof = true; + + return false; + } + + if (temp == 0) + { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; +} + +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) +{ + switch (wire_type) + { + case PB_WT_VARINT: return pb_skip_varint(stream); + case PB_WT_64BIT: return pb_read(stream, NULL, 8); + case PB_WT_STRING: return pb_skip_string(stream); + case PB_WT_32BIT: return pb_read(stream, NULL, 4); + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Read a raw value to buffer, for the purpose of passing it to callback as + * a substream. Size is maximum size on call, and actual size on return. + */ +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) +{ + size_t max_size = *size; + switch (wire_type) + { + case PB_WT_VARINT: + *size = 0; + do + { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Decode string length from stream and return a substream with limited length. + * Remember to close the substream using pb_close_string_substream(). + */ +bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + uint32_t size; + if (!pb_decode_varint32(stream, &size)) + return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; +} + +void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + stream->state = substream->state; + +#ifndef PB_NO_ERRMSG + stream->errmsg = substream->errmsg; +#endif +} + +static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = iter->pos = fields; + iter->field_index = 0; + iter->required_field_index = 0; + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + iter->dest_struct = dest_struct; +} + +static bool pb_field_next(pb_field_iterator_t *iter) +{ + bool notwrapped = true; + size_t prev_size = iter->pos->data_size; + + if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && + PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) + { + prev_size *= iter->pos->array_size; + } + else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + prev_size = sizeof(void*); + } + + if (iter->pos->tag == 0) + return false; /* Only happens with empty message types */ + + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) + iter->required_field_index++; + + iter->pos++; + iter->field_index++; + if (iter->pos->tag == 0) + { + iter->pos = iter->start; + iter->field_index = 0; + iter->required_field_index = 0; + iter->pData = iter->dest_struct; + prev_size = 0; + notwrapped = false; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return notwrapped; +} + +static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) +{ + unsigned start = iter->field_index; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + return true; + } + (void)pb_field_next(iter); + } while (iter->field_index != start); + + return false; +} + +/************************* + * Decode a single field * + *************************/ + +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_OPTIONAL: + *(bool*)iter->pSize = true; + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array */ + bool status = true; + size_t *size = (size_t*)iter->pSize; + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) + { + void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + pb_close_string_substream(stream, &substream); + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + + return status; + } + else + { + /* Repeated field */ + size_t *size = (size_t*)iter->pSize; + void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); + if (*size >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + (*size)++; + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + size_t size = array_size * data_size; + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + UNUSED(wire_type); + UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + size_t *size = (size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if (*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size); + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + pb_close_string_substream(stream, &substream); + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + size_t *size = (size_t*)iter->pSize; + void *pItem; + + (*size)++; + if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) + return false; + + pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1); + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ + pb_callback_t *pCallback = (pb_callback_t*)iter->pData; + +#ifdef PB_OLD_CALLBACK_STYLE + void *arg = pCallback->arg; +#else + void **arg = &(pCallback->arg); +#endif + + if (pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); + + if (wire_type == PB_WT_STRING) + { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + do + { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + pb_close_string_substream(stream, &substream); + return true; + } + else + { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + uint8_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) + return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } +} + +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ + switch (PB_ATYPE(iter->pos->type)) + { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects a pb_field_t structure + * in extension->type->arg. */ +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + pb_field_iterator_t iter; + + if (field->tag != tag) + return true; + + iter.start = field; + iter.pos = field; + iter.field_index = 0; + iter.required_field_index = 0; + iter.dest_struct = extension->dest; + iter.pData = extension->dest; + iter.pSize = &extension->found; + + return decode_field(stream, wire_type, &iter); +} + +/* Try to decode an unknown field as an extension field. Tries each extension + * decoder in turn, until one of them handles the field or loop ends. */ +static bool checkreturn decode_extension(pb_istream_t *stream, + uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +{ + pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; + size_t pos = stream->bytes_left; + + while (extension != NULL && pos == stream->bytes_left) + { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/* Step through the iterator until an extension field is found or until all + * entries have been checked. There can be only one extension field per + * message. Returns false if no extension field is found. */ +static bool checkreturn find_extension_field(pb_field_iterator_t *iter) +{ + unsigned start = iter->field_index; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) + return true; + (void)pb_field_next(iter); + } while (iter->field_index != start); + + return false; +} + +/* Initialize message fields to default values, recursively */ +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); + + do + { + pb_type_t type; + type = iter.pos->type; + + /* Avoid crash on empty message types (zero fields) */ + if (iter.pos->tag == 0) + continue; + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) + { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool*)iter.pSize = false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* Set array count to 0, no need to initialize contents. */ + *(size_t*)iter.pSize = 0; + continue; + } + + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData); + } + else if (iter.pos->ptr != NULL) + { + /* Initialize to default value */ + memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size); + } + else + { + /* Initialize to zeros */ + memset(iter.pData, 0, iter.pos->data_size); + } + } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter.pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + *(size_t*)iter.pSize = 0; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + /* Don't overwrite callback */ + } + } while (pb_field_next(&iter)); +} + +/********************* + * Decode all fields * + *********************/ + +bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t extension_range_start = 0; + pb_field_iterator_t iter; + + pb_field_init(&iter, fields, dest_struct); + + while (stream->bytes_left) + { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) + { + if (eof) + break; + else + return false; + } + + if (!pb_field_find(&iter, tag)) + { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) + { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; + + if (tag >= extension_range_start) + { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) + return false; + + if (pos != stream->bytes_left) + { + /* The field was handled */ + continue; + } + } + } + + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) + return false; + continue; + } + + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED + && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) + { + fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); + } + + if (!decode_field(stream, wire_type, &iter)) + return false; + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + /* Check the whole bytes */ + for (i = 0; i < (req_field_count >> 3); i++) + { + if (fields_seen[i] != 0xFF) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits */ + if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) + PB_RETURN_ERROR(stream, "missing required field"); + } + + return true; +} + +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; +} + +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode(&substream, fields, dest_struct); + pb_close_string_substream(stream, &substream); + return status; +} + +#ifdef PB_ENABLE_MALLOC +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); + + do + { + pb_type_t type; + type = iter.pos->type; + + /* Avoid crash on empty message types (zero fields) */ + if (iter.pos->tag == 0) + continue; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter.pData; + size_t count = *(size_t*)iter.pSize; + while (count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessages */ + void *pItem = *(void**)iter.pData; + size_t count = (pItem ? 1 : 0); + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(size_t*)iter.pSize; + } + + while (count--) + { + pb_release((const pb_field_t*)iter.pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter.pos->data_size; + } + } + + /* Release main item */ + pb_free(*(void**)iter.pData); + *(void**)iter.pData = NULL; + } + } while (pb_field_next(&iter)); +} +#endif + +/* Field decoders */ + +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + if (value & 1) + *dest = (int64_t)(~(value >> 1)); + else + *dest = (int64_t)(value >> 1); + + return true; +} + +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) +{ + #ifdef __BIG_ENDIAN__ + uint8_t *bytes = (uint8_t*)dest; + uint8_t lebytes[4]; + + if (!pb_read(stream, lebytes, 4)) + return false; + + bytes[0] = lebytes[3]; + bytes[1] = lebytes[2]; + bytes[2] = lebytes[1]; + bytes[3] = lebytes[0]; + return true; + #else + return pb_read(stream, (uint8_t*)dest, 4); + #endif +} + +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) +{ + #ifdef __BIG_ENDIAN__ + uint8_t *bytes = (uint8_t*)dest; + uint8_t lebytes[8]; + + if (!pb_read(stream, lebytes, 8)) + return false; + + bytes[0] = lebytes[7]; + bytes[1] = lebytes[6]; + bytes[2] = lebytes[5]; + bytes[3] = lebytes[4]; + bytes[4] = lebytes[3]; + bytes[5] = lebytes[2]; + bytes[6] = lebytes[1]; + bytes[7] = lebytes[0]; + return true; + #else + return pb_read(stream, (uint8_t*)dest, 8); + #endif +} + +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + switch (field->data_size) + { + case 1: *(int8_t*)dest = (int8_t)value; break; + case 2: *(int16_t*)dest = (int16_t)value; break; + case 4: *(int32_t*)dest = (int32_t)value; break; + case 8: *(int64_t*)dest = (int64_t)value; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + switch (field->data_size) + { + case 4: *(uint32_t*)dest = (uint32_t)value; break; + case 8: *(uint64_t*)dest = value; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return true; +} + +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + int64_t value; + if (!pb_decode_svarint(stream, &value)) + return false; + + switch (field->data_size) + { + case 4: *(int32_t*)dest = (int32_t)value; break; + case 8: *(int64_t*)dest = value; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return true; +} + +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + UNUSED(field); + return pb_decode_fixed32(stream, dest); +} + +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + UNUSED(field); + return pb_decode_fixed64(stream, dest); +} + +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } + + bdest->size = size; + return pb_read(stream, bdest->bytes, size); +} + +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) + return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (uint8_t*)dest, size); + *((uint8_t*)dest + size) = 0; + return status; +} + +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + bool status; + pb_istream_t substream; + const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + pb_close_string_substream(stream, &substream); + return status; +} diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h new file mode 100644 index 0000000000..8dc67408a8 --- /dev/null +++ b/firmware/protob/pb_decode.h @@ -0,0 +1,149 @@ +/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. + * The main function is pb_decode. You also need an input stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef _PB_DECODE_H_ +#define _PB_DECODE_H_ + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom input streams. You will need to provide + * a callback function to read the bytes from your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause decoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer), + * and rely on pb_read to verify that no-body reads past bytes_left. + * 3) Your callback may be used with substreams, in which case bytes_left + * is different than from the main stream. Don't use bytes_left to compute + * any pointers. + */ +struct _pb_istream_t +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; +#else + bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count); +#endif + + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main decoding functions * + ***************************/ + +/* Decode a single protocol buffers message from input stream into a C structure. + * Returns true on success, false on any failure. + * The actual struct pointed to by dest must match the description in fields. + * Callback fields of the destination structure must be initialized by caller. + * All other fields will be initialized by this function. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_istream_t stream; + * + * // ... read some data into buffer ... + * + * stream = pb_istream_from_buffer(buffer, count); + * pb_decode(&stream, MyMessage_fields, &msg); + */ +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except does not initialize the destination structure + * to default values. This is slightly faster if you need no default values + * and just do memset(struct, 0, sizeof(struct)) yourself. + * + * This can also be used for 'merging' two messages, i.e. update only the + * fields that exist in the new message. + * + * Note: If this function returns with an error, it will not release any + * dynamically allocated fields. You will need to call pb_release() yourself. + */ +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except expects the stream to start with the message size + * encoded as varint. Corresponds to parseDelimitedFrom() in Google's + * protobuf API. + */ +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +#ifdef PB_ENABLE_MALLOC +/* Release any allocated pointer fields. If you use dynamic allocation, you should + * call this for any successfully decoded message when you are done with it. If + * pb_decode() returns with an error, the message is already released. + */ +void pb_release(const pb_field_t fields[], void *dest_struct); +#endif + + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an input stream for reading from a memory buffer. + * + * Alternatively, you can use a custom stream that reads directly from e.g. + * a file or a network socket. + */ +pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize); + +/* Function to read from a pb_istream_t. You can use this if you need to + * read some custom header data, or to read data in field callbacks. + */ +bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Decode the tag for the next field in the stream. Gives the wire type and + * field tag. At end of the message, returns false and sets eof to true. */ +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); + +/* Skip the field payload data, given the wire type. */ +bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); + +/* Decode an integer in the varint format. This works for bool, enum, int32, + * int64, uint32 and uint64 field types. */ +bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); + +/* Decode an integer in the zig-zagged svarint format. This works for sint32 + * and sint64. */ +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); + +/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to + * a 4-byte wide C variable. */ +bool pb_decode_fixed32(pb_istream_t *stream, void *dest); + +/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to + * a 8-byte wide C variable. */ +bool pb_decode_fixed64(pb_istream_t *stream, void *dest); + +/* Make a limited-length substream for reading a PB_WT_STRING field. */ +bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); +void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c new file mode 100644 index 0000000000..dc5a273493 --- /dev/null +++ b/firmware/protob/pb_encode.c @@ -0,0 +1,667 @@ +/* pb_encode.c -- encode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +#include "pb.h" +#include "pb_encode.h" + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +/************************************** + * Declarations internal to this file * + **************************************/ +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); + +/* --- Function pointers to field encoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_varint, + &pb_enc_uvarint, + &pb_enc_svarint, + &pb_enc_fixed32, + &pb_enc_fixed64, + + &pb_enc_bytes, + &pb_enc_string, + &pb_enc_submessage, + NULL /* extensions */ +}; + +/******************************* + * pb_ostream_t implementation * + *******************************/ + +static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + uint8_t *dest = (uint8_t*)stream->state; + stream->state = dest + count; + + while (count--) + *dest++ = *buf++; + + return true; +} + +pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize) +{ + pb_ostream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = (void*)1; /* Just a marker value */ +#else + stream.callback = &buf_write; +#endif + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) +{ + if (stream->callback != NULL) + { + if (stream->bytes_written + count > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + +#ifdef PB_BUFFER_ONLY + if (!buf_write(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#endif + } + + stream->bytes_written += count; + return true; +} + +/************************* + * Encode a single field * + *************************/ + +/* Encode a static array. Handles the size calculations and possible packing. */ +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, + const void *pData, size_t count, pb_encoder_t func) +{ + size_t i; + const void *p; + size_t size; + + if (count == 0) + return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); + + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) + { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) + return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) + { + size = 4 * count; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) + { + size = 8 * count; + } + else + { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) + { + if (!func(&sizestream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + size = sizestream.bytes_written; + } + + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) + { + if (!func(stream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + } + else + { + p = pData; + for (i = 0; i < count; i++) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) + { + if (!func(stream, field, *(const void* const*)p)) + return false; + } + else + { + if (!func(stream, field, p)) + return false; + } + p = (const char*)p + field->data_size; + } + } + + return true; +} + +/* Encode a field with static or pointer allocation, i.e. one whose data + * is available to the encoder directly. */ +static bool checkreturn encode_basic_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + pb_encoder_t func; + const void *pSize; + bool implicit_has = true; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) + pSize = (const char*)pData + field->size_offset; + else + pSize = &implicit_has; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + + pData = *(const void* const*)pData; + implicit_has = (pData != NULL); + } + + switch (PB_HTYPE(field->type)) + { + case PB_HTYPE_REQUIRED: + if (!pData) + PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) + return false; + if (!func(stream, field, pData)) + return false; + break; + + case PB_HTYPE_OPTIONAL: + if (*(const bool*)pSize) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + case PB_HTYPE_REPEATED: + if (!encode_array(stream, field, pData, *(const size_t*)pSize, func)) + return false; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; +} + +/* Encode a field with callback semantics. This means that a user function is + * called to provide and encode the actual data. */ +static bool checkreturn encode_callback_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_callback_t *callback = (const pb_callback_t*)pData; + +#ifdef PB_OLD_CALLBACK_STYLE + const void *arg = callback->arg; +#else + void * const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) + { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; +} + +/* Encode a single field of any callback or static type. */ +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + switch (PB_ATYPE(field->type)) + { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects to have a pb_field_t + * pointer in the extension->type->arg field. */ +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, + const pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + return encode_field(stream, field, extension->dest); +} + +/* Walk through all the registered extensions and give them a chance + * to encode themselves. */ +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_extension_t *extension = *(const pb_extension_t* const *)pData; + UNUSED(field); + + while (extension) + { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/********************* + * Encode all fields * + *********************/ + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_field_t *field = fields; + const void *pData = src_struct; + size_t prev_size = 0; + + while (field->tag != 0) + { + pData = (const char*)pData + prev_size + field->data_offset; + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + prev_size = sizeof(const void*); + else + prev_size = field->data_size; + + /* Special case for static arrays */ + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + { + prev_size *= field->array_size; + } + + if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION) + { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, field, pData)) + return false; + } + else + { + /* Regular field */ + if (!encode_field(stream, field, pData)) + return false; + } + + field++; + } + + return true; +} + +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + return pb_encode_submessage(stream, fields, src_struct); +} + +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) +{ + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) + return false; + + *size = stream.bytes_written; + return true; +} + +/******************** + * Helper functions * + ********************/ +bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) +{ + uint8_t buffer[10]; + size_t i = 0; + + if (value == 0) + return pb_write(stream, (uint8_t*)&value, 1); + + while (value) + { + buffer[i] = (uint8_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} + +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) +{ + uint64_t zigzagged; + if (value < 0) + zigzagged = ~((uint64_t)value << 1); + else + zigzagged = (uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); +} + +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) +{ + #ifdef __BIG_ENDIAN__ + const uint8_t *bytes = value; + uint8_t lebytes[4]; + lebytes[0] = bytes[3]; + lebytes[1] = bytes[2]; + lebytes[2] = bytes[1]; + lebytes[3] = bytes[0]; + return pb_write(stream, lebytes, 4); + #else + return pb_write(stream, (const uint8_t*)value, 4); + #endif +} + +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) +{ + #ifdef __BIG_ENDIAN__ + const uint8_t *bytes = value; + uint8_t lebytes[8]; + lebytes[0] = bytes[7]; + lebytes[1] = bytes[6]; + lebytes[2] = bytes[5]; + lebytes[3] = bytes[4]; + lebytes[4] = bytes[3]; + lebytes[5] = bytes[2]; + lebytes[6] = bytes[1]; + lebytes[7] = bytes[0]; + return pb_write(stream, lebytes, 8); + #else + return pb_write(stream, (const uint8_t*)value, 8); + #endif +} + +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) +{ + uint64_t tag = ((uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) +{ + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) + { + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); +} + +bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) +{ + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + return pb_write(stream, buffer, size); +} + +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + substream.errmsg = NULL; +#endif + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; +} + +/* Field encoders */ + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + int64_t value = 0; + + /* Cases 1 and 2 are for compilers that have smaller types for bool + * or enums. */ + switch (field->data_size) + { + case 1: value = *(const int8_t*)src; break; + case 2: value = *(const int16_t*)src; break; + case 4: value = *(const int32_t*)src; break; + case 8: value = *(const int64_t*)src; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return pb_encode_varint(stream, (uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint64_t value = 0; + + switch (field->data_size) + { + case 4: value = *(const uint32_t*)src; break; + case 8: value = *(const uint64_t*)src; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + int64_t value = 0; + + switch (field->data_size) + { + case 4: value = *(const int32_t*)src; break; + case 8: value = *(const int64_t*)src; break; + default: PB_RETURN_ERROR(stream, "invalid data_size"); + } + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + UNUSED(field); + return pb_encode_fixed64(stream, src); +} + +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + UNUSED(field); + return pb_encode_fixed32(stream, src); +} + +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; + + if (src == NULL) + { + /* Threat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } + + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) + { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); +} + +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + /* strnlen() is not always available, so just use a loop */ + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char*)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + max_size = (size_t)-1; + + if (src == NULL) + { + size = 0; /* Threat null pointer as an empty string */ + } + else + { + while (size < max_size && *p != '\0') + { + size++; + p++; + } + } + + return pb_encode_string(stream, (const uint8_t*)src, size); +} + +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +} + diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h new file mode 100644 index 0000000000..f82bac8f86 --- /dev/null +++ b/firmware/protob/pb_encode.h @@ -0,0 +1,154 @@ +/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. + * The main function is pb_encode. You also need an output stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef _PB_ENCODE_H_ +#define _PB_ENCODE_H_ + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom output streams. You will need to provide + * a callback function to write the bytes to your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause encoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer). + * 3) pb_write will update bytes_written after your callback runs. + * 4) Substreams will modify max_size and bytes_written. Don't use them + * to calculate any pointers. + */ +struct _pb_ostream_t +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; +#else + bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count); +#endif + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main encoding functions * + ***************************/ + +/* Encode a single protocol buffers message from C structure into a stream. + * Returns true on success, false on any failure. + * The actual struct pointed to by src_struct must match the description in fields. + * All required fields in the struct are assumed to have been filled in. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_ostream_t stream; + * + * msg.field1 = 42; + * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + * pb_encode(&stream, MyMessage_fields, &msg); + */ +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but prepends the length of the message as a varint. + * Corresponds to writeDelimitedTo() in Google's protobuf API. + */ +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Encode the message to get the size of the encoded data, but do not store + * the data. */ +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an output stream for writing into a memory buffer. + * The number of bytes written can be found in stream.bytes_written after + * encoding the message. + * + * Alternatively, you can use a custom stream that writes directly to e.g. + * a file or a network socket. + */ +pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize); + +/* Pseudo-stream for measuring the size of a message without actually storing + * the encoded data. + * + * Example usage: + * MyMessage msg = {}; + * pb_ostream_t stream = PB_OSTREAM_SIZING; + * pb_encode(&stream, MyMessage_fields, &msg); + * printf("Message size is %d\n", stream.bytes_written); + */ +#ifndef PB_NO_ERRMSG +#define PB_OSTREAM_SIZING {0,0,0,0,0} +#else +#define PB_OSTREAM_SIZING {0,0,0,0} +#endif + +/* Function to write into a pb_ostream_t stream. You can use this if you need + * to append or prepend some custom headers to the message. + */ +bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Encode field header based on type and field number defined in the field + * structure. Call this from the callback before writing out field contents. */ +bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); + +/* Encode field header by manually specifing wire type. You need to use this + * if you want to write out packed arrays from a callback field. */ +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); + +/* Encode an integer in the varint format. + * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); + +/* Encode an integer in the zig-zagged svarint format. + * This works for sint32 and sint64. */ +bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); + +/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ +bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size); + +/* Encode a fixed32, sfixed32 or float value. + * You need to pass a pointer to a 4-byte wide C variable. */ +bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); + +/* Encode a fixed64, sfixed64 or double value. + * You need to pass a pointer to a 8-byte wide C variable. */ +bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); + +/* Encode a submessage field. + * You need to pass the pb_field_t array and pointer to struct, just like + * with pb_encode(). This internally encodes the submessage twice, first to + * calculate message size and then to actually write it out. + */ +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/protob/storage.options b/firmware/protob/storage.options new file mode 100644 index 0000000000..eb495de973 --- /dev/null +++ b/firmware/protob/storage.options @@ -0,0 +1,4 @@ +Storage.mnemonic max_size:241 +Storage.pin max_size:10 +Storage.language max_size:17 +Storage.label max_size:33 diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c new file mode 100644 index 0000000000..ac40b48b32 --- /dev/null +++ b/firmware/protob/storage.pb.c @@ -0,0 +1,44 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.2.7 */ + +#include "storage.pb.h" + + + +const pb_field_t Storage_fields[9] = { + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), + PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), + PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) +#endif + + diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h new file mode 100644 index 0000000000..3e7824c97a --- /dev/null +++ b/firmware/protob/storage.pb.h @@ -0,0 +1,55 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.2.7 */ + +#ifndef _PB_STORAGE_PB_H_ +#define _PB_STORAGE_PB_H_ +#include "pb.h" +#include "types.pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +/* Struct definitions */ +typedef struct _Storage { + uint32_t version; + bool has_node; + HDNodeType node; + bool has_mnemonic; + char mnemonic[241]; + bool has_passphrase_protection; + bool passphrase_protection; + bool has_pin_failed_attempts; + uint32_t pin_failed_attempts; + bool has_pin; + char pin[10]; + bool has_language; + char language[17]; + bool has_label; + char label[33]; +} Storage; + +/* Default values for struct fields */ + +/* Field tags (for use in manual encoding/decoding) */ +#define Storage_version_tag 1 +#define Storage_node_tag 2 +#define Storage_mnemonic_tag 3 +#define Storage_passphrase_protection_tag 4 +#define Storage_pin_failed_attempts_tag 5 +#define Storage_pin_tag 6 +#define Storage_language_tag 7 +#define Storage_label_tag 8 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t Storage_fields[9]; + +/* Maximum encoded size of messages (where known) */ +#define Storage_size (330 + HDNodeType_size) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/protob/storage.proto b/firmware/protob/storage.proto new file mode 120000 index 0000000000..b7b890d7bf --- /dev/null +++ b/firmware/protob/storage.proto @@ -0,0 +1 @@ +../../trezor-common/protob/storage.proto \ No newline at end of file diff --git a/firmware/protob/types.options b/firmware/protob/types.options new file mode 100644 index 0000000000..9c29909b98 --- /dev/null +++ b/firmware/protob/types.options @@ -0,0 +1,26 @@ +HDNodeType.chain_code max_size:32 +HDNodeType.private_key max_size:32 +HDNodeType.public_key max_size:33 + +CoinType.coin_name max_size:17 +CoinType.coin_shortcut max_size:9 + +TxInputType.address_n max_count:8 +TxInputType.prev_hash max_size:32 +TxInputType.script_sig max_size:256 + +TxOutputType.address max_size:35 +TxOutputType.address_n max_count:8 +TxOutputType.script_args max_count:3 +TxOutputType.script_args max_size:16 + +TxOutputBinType.script_pubkey max_size:256 + +TransactionType.inputs max_count:8 +TransactionType.bin_outputs max_count:4 +TransactionType.outputs max_count:4 + +TxRequestDetailsType.tx_hash max_size:32 + +TxRequestSerializedType.signature max_size:80 +TxRequestSerializedType.serialized_tx max_size:1024 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c new file mode 100644 index 0000000000..587f391dac --- /dev/null +++ b/firmware/protob/types.pb.c @@ -0,0 +1,144 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.2.7 */ + +#include "types.pb.h" + +const uint32_t TxInputType_sequence_default = 4294967295u; + + +const pb_field_t HDNodeType_fields[7] = { + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), + PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), + PB_FIELD2( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), + PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), + PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t CoinType_fields[5] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, 0), + PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxInputType_fields[6] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), + PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_LAST_FIELD +}; + +const pb_field_t TxOutputType_fields[6] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), + PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), + PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), + PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), + PB_FIELD2( 5, BYTES , REPEATED, STATIC , OTHER, TxOutputType, script_args, script_type, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxOutputBinType_fields[3] = { + PB_FIELD2( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), + PB_LAST_FIELD +}; + +const pb_field_t TransactionType_fields[8] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), + PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), + PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), + PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), + PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), + PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxRequestDetailsType_fields[3] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxRequestSerializedType_fields[4] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), + PB_LAST_FIELD +}; + +typedef struct { + bool wire_in; +} wire_in_struct; + +static const pb_field_t wire_in_field = + PB_FIELD2(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); + +const pb_extension_type_t wire_in = { + NULL, + NULL, + &wire_in_field +}; + +typedef struct { + bool wire_out; +} wire_out_struct; + +static const pb_field_t wire_out_field = + PB_FIELD2(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); + +const pb_extension_type_t wire_out = { + NULL, + NULL, + &wire_out_field +}; + +typedef struct { + bool wire_debug_in; +} wire_debug_in_struct; + +static const pb_field_t wire_debug_in_field = + PB_FIELD2(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); + +const pb_extension_type_t wire_debug_in = { + NULL, + NULL, + &wire_debug_in_field +}; + +typedef struct { + bool wire_debug_out; +} wire_debug_out_struct; + +static const pb_field_t wire_debug_out_field = + PB_FIELD2(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); + +const pb_extension_type_t wire_debug_out = { + NULL, + NULL, + &wire_debug_out_field +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +STATIC_ASSERT((pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +#error Field descriptor for TxRequestSerializedType.serialized_tx is too large. Define PB_FIELD_16BIT to fix this. +#endif + + diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h new file mode 100644 index 0000000000..9c2b7225c0 --- /dev/null +++ b/firmware/protob/types.pb.h @@ -0,0 +1,262 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.2.7 */ + +#ifndef _PB_TYPES_PB_H_ +#define _PB_TYPES_PB_H_ +#include "pb.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +typedef enum _FailureType { + FailureType_Failure_UnexpectedMessage = 1, + FailureType_Failure_ButtonExpected = 2, + FailureType_Failure_SyntaxError = 3, + FailureType_Failure_ActionCancelled = 4, + FailureType_Failure_PinExpected = 5, + FailureType_Failure_PinCancelled = 6, + FailureType_Failure_PinInvalid = 7, + FailureType_Failure_InvalidSignature = 8, + FailureType_Failure_Other = 9, + FailureType_Failure_NotEnoughFunds = 10, + FailureType_Failure_NotInitialized = 11, + FailureType_Failure_FirmwareError = 99 +} FailureType; + +typedef enum _ScriptType { + ScriptType_PAYTOADDRESS = 0, + ScriptType_PAYTOSCRIPTHASH = 1 +} ScriptType; + +typedef enum _RequestType { + RequestType_TXINPUT = 0, + RequestType_TXOUTPUT = 1, + RequestType_TXMETA = 2, + RequestType_TXFINISHED = 3 +} RequestType; + +typedef enum _ButtonRequestType { + ButtonRequestType_ButtonRequest_Other = 1, + ButtonRequestType_ButtonRequest_FeeOverThreshold = 2, + ButtonRequestType_ButtonRequest_ConfirmOutput = 3, + ButtonRequestType_ButtonRequest_ResetDevice = 4, + ButtonRequestType_ButtonRequest_ConfirmWord = 5, + ButtonRequestType_ButtonRequest_WipeDevice = 6, + ButtonRequestType_ButtonRequest_ProtectCall = 7, + ButtonRequestType_ButtonRequest_SignTx = 8 +} ButtonRequestType; + +typedef enum _PinMatrixRequestType { + PinMatrixRequestType_PinMatrixRequestType_Current = 1, + PinMatrixRequestType_PinMatrixRequestType_NewFirst = 2, + PinMatrixRequestType_PinMatrixRequestType_NewSecond = 3 +} PinMatrixRequestType; + +/* Struct definitions */ +typedef struct _CoinType { + bool has_coin_name; + char coin_name[17]; + bool has_coin_shortcut; + char coin_shortcut[9]; + bool has_address_type; + uint32_t address_type; + bool has_maxfee_kb; + uint64_t maxfee_kb; +} CoinType; + +typedef struct { + size_t size; + uint8_t bytes[32]; +} HDNodeType_chain_code_t; + +typedef struct { + size_t size; + uint8_t bytes[32]; +} HDNodeType_private_key_t; + +typedef struct { + size_t size; + uint8_t bytes[33]; +} HDNodeType_public_key_t; + +typedef struct _HDNodeType { + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + HDNodeType_chain_code_t chain_code; + bool has_private_key; + HDNodeType_private_key_t private_key; + bool has_public_key; + HDNodeType_public_key_t public_key; +} HDNodeType; + +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxInputType_prev_hash_t; + +typedef struct { + size_t size; + uint8_t bytes[256]; +} TxInputType_script_sig_t; + +typedef struct _TxInputType { + size_t address_n_count; + uint32_t address_n[8]; + TxInputType_prev_hash_t prev_hash; + uint32_t prev_index; + bool has_script_sig; + TxInputType_script_sig_t script_sig; + bool has_sequence; + uint32_t sequence; +} TxInputType; + +typedef struct { + size_t size; + uint8_t bytes[256]; +} TxOutputBinType_script_pubkey_t; + +typedef struct _TxOutputBinType { + uint64_t amount; + TxOutputBinType_script_pubkey_t script_pubkey; +} TxOutputBinType; + +typedef struct { + size_t size; + uint8_t bytes[16]; +} TxOutputType_script_args_t; + +typedef struct _TxOutputType { + bool has_address; + char address[35]; + size_t address_n_count; + uint32_t address_n[8]; + uint64_t amount; + ScriptType script_type; + size_t script_args_count; + TxOutputType_script_args_t script_args[3]; +} TxOutputType; + +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxRequestDetailsType_tx_hash_t; + +typedef struct _TxRequestDetailsType { + bool has_request_index; + uint32_t request_index; + bool has_tx_hash; + TxRequestDetailsType_tx_hash_t tx_hash; +} TxRequestDetailsType; + +typedef struct { + size_t size; + uint8_t bytes[80]; +} TxRequestSerializedType_signature_t; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} TxRequestSerializedType_serialized_tx_t; + +typedef struct _TxRequestSerializedType { + bool has_signature_index; + uint32_t signature_index; + bool has_signature; + TxRequestSerializedType_signature_t signature; + bool has_serialized_tx; + TxRequestSerializedType_serialized_tx_t serialized_tx; +} TxRequestSerializedType; + +typedef struct _TransactionType { + bool has_version; + uint32_t version; + size_t inputs_count; + TxInputType inputs[8]; + size_t bin_outputs_count; + TxOutputBinType bin_outputs[4]; + bool has_lock_time; + uint32_t lock_time; + size_t outputs_count; + TxOutputType outputs[4]; + bool has_inputs_cnt; + uint32_t inputs_cnt; + bool has_outputs_cnt; + uint32_t outputs_cnt; +} TransactionType; + +/* Extensions */ +extern const pb_extension_type_t wire_in; +extern const pb_extension_type_t wire_out; +extern const pb_extension_type_t wire_debug_in; +extern const pb_extension_type_t wire_debug_out; + +/* Default values for struct fields */ +extern const uint32_t TxInputType_sequence_default; + +/* Field tags (for use in manual encoding/decoding) */ +#define CoinType_coin_name_tag 1 +#define CoinType_coin_shortcut_tag 2 +#define CoinType_address_type_tag 3 +#define CoinType_maxfee_kb_tag 4 +#define HDNodeType_depth_tag 1 +#define HDNodeType_fingerprint_tag 2 +#define HDNodeType_child_num_tag 3 +#define HDNodeType_chain_code_tag 4 +#define HDNodeType_private_key_tag 5 +#define HDNodeType_public_key_tag 6 +#define TxInputType_address_n_tag 1 +#define TxInputType_prev_hash_tag 2 +#define TxInputType_prev_index_tag 3 +#define TxInputType_script_sig_tag 4 +#define TxInputType_sequence_tag 5 +#define TxOutputBinType_amount_tag 1 +#define TxOutputBinType_script_pubkey_tag 2 +#define TxOutputType_address_tag 1 +#define TxOutputType_address_n_tag 2 +#define TxOutputType_amount_tag 3 +#define TxOutputType_script_type_tag 4 +#define TxOutputType_script_args_tag 5 +#define TxRequestDetailsType_request_index_tag 1 +#define TxRequestDetailsType_tx_hash_tag 2 +#define TxRequestSerializedType_signature_index_tag 1 +#define TxRequestSerializedType_signature_tag 2 +#define TxRequestSerializedType_serialized_tx_tag 3 +#define TransactionType_version_tag 1 +#define TransactionType_inputs_tag 2 +#define TransactionType_bin_outputs_tag 3 +#define TransactionType_outputs_tag 5 +#define TransactionType_lock_time_tag 4 +#define TransactionType_inputs_cnt_tag 6 +#define TransactionType_outputs_cnt_tag 7 +#define wire_in_tag 50002 +#define wire_out_tag 50003 +#define wire_debug_in_tag 50004 +#define wire_debug_out_tag 50005 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t HDNodeType_fields[7]; +extern const pb_field_t CoinType_fields[5]; +extern const pb_field_t TxInputType_fields[6]; +extern const pb_field_t TxOutputType_fields[6]; +extern const pb_field_t TxOutputBinType_fields[3]; +extern const pb_field_t TransactionType_fields[8]; +extern const pb_field_t TxRequestDetailsType_fields[3]; +extern const pb_field_t TxRequestSerializedType_fields[4]; + +/* Maximum encoded size of messages (where known) */ +#define HDNodeType_size 121 +#define CoinType_size 47 +#define TxInputType_size 353 +#define TxOutputType_size 156 +#define TxOutputBinType_size 270 +#define TransactionType_size 4600 +#define TxRequestDetailsType_size 40 +#define TxRequestSerializedType_size 1115 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/protob/types.proto b/firmware/protob/types.proto new file mode 120000 index 0000000000..6f8a7a998f --- /dev/null +++ b/firmware/protob/types.proto @@ -0,0 +1 @@ +../../trezor-common/protob/types.proto \ No newline at end of file diff --git a/firmware/recovery.c b/firmware/recovery.c new file mode 100644 index 0000000000..18b383edef --- /dev/null +++ b/firmware/recovery.c @@ -0,0 +1,179 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "recovery.h" +#include "fsm.h" +#include "storage.h" +#include "layout2.h" +#include "protect.h" +#include "types.pb.h" +#include "messages.h" +#include "rng.h" +#include "bip39.h" + +static uint32_t word_count; +static bool awaiting_word = false; +static bool enforce_wordlist; +static char fake_word[12]; +static uint32_t word_pos; +static uint32_t word_index; +static char word_order[36]; +static char words[24][12]; + +void next_word(void) { + word_pos = word_order[word_index]; + if (word_pos == 0) { + const char **wl = mnemonic_wordlist(); + strlcpy(fake_word, wl[random32() & 0x7FF], sizeof(fake_word)); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); + } else { + fake_word[0] = 0; + char descbuf[] = "__. word"; + char *desc = descbuf; + if (word_pos < 10) { + desc++; + } else { + descbuf[0] = '0' + word_pos / 10; + } + descbuf[1] = '0' + word_pos % 10; + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the", NULL, desc, NULL, "of your mnemonic", NULL); + } + WordRequest resp; + memset(&resp, 0, sizeof(WordRequest)); + msg_write(MessageType_MessageType_WordRequest, &resp); +} + +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist) +{ + if (_word_count != 12 && _word_count != 18 && _word_count != 24) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (has to be 12, 18 or 24 bits)"); + layoutHome(); + return; + } + + word_count = _word_count; + enforce_wordlist = _enforce_wordlist; + + if (pin_protection && !protectChangePin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + layoutHome(); + return; + } + + storage.has_passphrase_protection = true; + storage.passphrase_protection = passphrase_protection; + storage_setLanguage(language); + storage_setLabel(label); + + uint32_t i, j, k; + char t; + for (i = 0; i < word_count; i++) { + word_order[i] = i + 1; + } + for (i = word_count; i < word_count + word_count / 2; i++) { + word_order[i] = 0; + } + for (i = 0; i < 10000; i++) { + j = random32() % (word_count + word_count / 2); + k = random32() % (word_count + word_count / 2); + t = word_order[j]; + word_order[j] = word_order[k]; + word_order[k] = t; + } + awaiting_word = true; + word_index = 0; + next_word(); +} + +void recovery_word(const char *word) +{ + if (!awaiting_word) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); + layoutHome(); + return; + } + + if (word_pos == 0) { // fake word + if (strcmp(word, fake_word) != 0) { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Wrong word retyped"); + layoutHome(); + return; + } + } else { // real word + if (enforce_wordlist) { // check if word is valid + const char **wl = mnemonic_wordlist(); + bool found = false; + while (*wl) { + if (strcmp(word, *wl) == 0) { + found = true; + break; + } + wl++; + } + if (!found) { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Word not found in a wordlist"); + layoutHome(); + return; + } + } + strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); + } + + if (word_index + 1 == word_count + word_count / 2) { // last one + uint32_t i; + strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + for (i = 1; i < word_count; i++) { + strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); + strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + } + if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { + storage.has_mnemonic = true; + storage_commit(); + fsm_sendSuccess("Device recovered"); + } else { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); + } + awaiting_word = false; + layoutHome(); + } else { + word_index++; + next_word(); + } +} + +void recovery_abort(void) +{ + if (awaiting_word) { + layoutHome(); + awaiting_word = false; + } +} + +const char *recovery_get_fake_word(void) +{ + return fake_word; +} + +uint32_t recovery_get_word_pos(void) +{ + return word_pos; +} diff --git a/firmware/recovery.h b/firmware/recovery.h new file mode 100644 index 0000000000..4d581138ba --- /dev/null +++ b/firmware/recovery.h @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __RECOVERY_H__ +#define __RECOVERY_H__ + +#include +#include + +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist); +void recovery_word(const char *word); +void recovery_abort(void); +const char *recovery_get_fake_word(void); +uint32_t recovery_get_word_pos(void); + +#endif diff --git a/firmware/reset.c b/firmware/reset.c new file mode 100644 index 0000000000..4bc5ba0ad1 --- /dev/null +++ b/firmware/reset.c @@ -0,0 +1,151 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "reset.h" +#include "storage.h" +#include "rng.h" +#include "sha2.h" +#include "messages.h" +#include "fsm.h" +#include "layout2.h" +#include "types.pb.h" +#include "protect.h" +#include "bip39.h" +#include "util.h" + +static uint32_t strength; +static uint8_t int_entropy[32]; +static bool awaiting_entropy = false; + +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label) +{ + if (_strength != 128 && _strength != 192 && _strength != 256) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid strength (has to be 128, 192 or 256 bits)"); + layoutHome(); + return; + } + + strength = _strength; + + random_buffer(int_entropy, 32); + + char ent_str[4][17]; + data2hex(int_entropy , 8, ent_str[0]); + data2hex(int_entropy + 8, 8, ent_str[1]); + data2hex(int_entropy + 16, 8, ent_str[2]); + data2hex(int_entropy + 24, 8, ent_str[3]); + + if (display_random) { + layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled"); + layoutHome(); + return; + } + } + + if (pin_protection && !protectChangePin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + layoutHome(); + return; + } + + storage.has_passphrase_protection = true; + storage.passphrase_protection = passphrase_protection; + storage_setLanguage(language); + storage_setLabel(label); + + EntropyRequest resp; + memset(&resp, 0, sizeof(EntropyRequest)); + msg_write(MessageType_MessageType_EntropyRequest, &resp); + awaiting_entropy = true; +} + +static char current_word[10]; + +void reset_entropy(const uint8_t *ext_entropy, uint32_t len) +{ + if (!awaiting_entropy) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Reset mode"); + return; + } + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, int_entropy, 32); + sha256_Update(&ctx, ext_entropy, len); + sha256_Final(int_entropy, &ctx); + strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic)); + memset(int_entropy, 0, 32); + awaiting_entropy = false; + + int pass, idx, i = 0, j; + + for (pass = 0; pass < 2; pass++) { + i = 0; + for (idx = 0; idx < (int)strength/32*3; idx++) { + // copy current_word + j = 0; + while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { + current_word[j] = storage.mnemonic[i]; + i++; j++; + } + current_word[j] = 0; if (storage.mnemonic[i] != 0) i++; + char descbuf[] = "__. word is:"; + char *desc = descbuf; + if (idx + 1 < 10) { + desc++; + } else { + descbuf[0] = '0' + (idx + 1) / 10; + } + descbuf[1] = '0' + (idx + 1) % 10; + if (idx + 1 == (int)strength/32*3) { // last word + if (pass == 1) { + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, desc, NULL, current_word, NULL); + } else { + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, desc, NULL, current_word, NULL); + } + } else { + if (pass == 1) { + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, desc, NULL, current_word, NULL); + } else { + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, desc, NULL, current_word, NULL); + } + } + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { + storage_reset(); + layoutHome(); + return; + } + } + } + + storage.has_mnemonic = true; + storage_commit(); + fsm_sendSuccess("Device reset"); + layoutHome(); +} + +uint32_t reset_get_int_entropy(uint8_t *entropy) { + memcpy(entropy, int_entropy, 32); + return 32; +} + +const char *reset_get_word(void) { + return current_word; +} diff --git a/firmware/reset.h b/firmware/reset.h new file mode 100644 index 0000000000..157d94ce16 --- /dev/null +++ b/firmware/reset.h @@ -0,0 +1,31 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __RESET_H__ +#define __RESET_H__ + +#include +#include + +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label); +void reset_entropy(const uint8_t *ext_entropy, uint32_t len); +uint32_t reset_get_int_entropy(uint8_t *entropy); +const char *reset_get_word(void); + +#endif diff --git a/firmware/signing.c b/firmware/signing.c new file mode 100644 index 0000000000..5b5cf9d1c3 --- /dev/null +++ b/firmware/signing.c @@ -0,0 +1,426 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "signing.h" +#include "fsm.h" +#include "layout2.h" +#include "messages.h" +#include "transaction.h" +#include "ecdsa.h" +#include "protect.h" + +static uint32_t inputs_count; +static uint32_t outputs_count; +static const CoinType *coin; +static const HDNode *root; +static HDNode node; +static bool signing = false; +enum { + STAGE_REQUEST_1_INPUT, + STAGE_REQUEST_2_PREV_META, + STAGE_REQUEST_2_PREV_INPUT, + STAGE_REQUEST_2_PREV_OUTPUT, + STAGE_REQUEST_3_INPUT, + STAGE_REQUEST_3_OUTPUT, + STAGE_REQUEST_4_OUTPUT +} signing_stage; +static uint32_t idx1i, idx2i, idx2o, idx3i, idx3o, idx4o; +static TxRequest resp; +static TxInputType input; +static TxOutputBinType bin_output; +static TxStruct to, tp, ti, tc; +static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; +static uint64_t to_spend, spending, change_spend; +const uint32_t version = 1; +const uint32_t lock_time = 0; +static uint32_t progress, progress_total; + +/* +Workflow of streamed signing + +I - input +O - output + +foreach I: + Request I STAGE_REQUEST_1_INPUT + + Calculate amount of I: + Request prevhash I, META STAGE_REQUEST_2_PREV_META + foreach prevhash I: STAGE_REQUEST_2_PREV_INPUT + Request prevhash I + foreach prevhash O: STAGE_REQUEST_2_PREV_OUTPUT + Request prevhash O + Store amount of I + Calculate hash of streamed tx, compare to prevhash I + + foreach I: STAGE_REQUEST_3_INPUT + Request I + If I == I-to-be-signed: + Fill scriptsig + Add I to StreamTransactionSign + foreach O: + Request O STAGE_REQUEST_3_OUTPUT + If I=0: + Display output + Ask for confirmation + Add O to StreamTransactionSign + + If I=0: + Check tx fee + Calculate txhash + else: + Compare current hash with txhash + If different: + Failure + + Sign StreamTransactionSign + Return signed chunk + */ + +void send_req_1_input(void) +{ + idx2i = idx2o = idx3i = idx3o = 0; + signing_stage = STAGE_REQUEST_1_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1i; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_2_prev_meta(void) +{ + signing_stage = STAGE_REQUEST_2_PREV_META; + resp.has_request_type = true; + resp.request_type = RequestType_TXMETA; + resp.has_details = true; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, input.prev_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_2_prev_input(void) +{ + signing_stage = STAGE_REQUEST_2_PREV_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2i; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_2_prev_output(void) +{ + signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2o; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_3_input(void) +{ + signing_stage = STAGE_REQUEST_3_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx3i; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_3_output(void) +{ + signing_stage = STAGE_REQUEST_3_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx3o; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_4_output(void) +{ + signing_stage = STAGE_REQUEST_4_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx4o; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_finished(void) +{ + resp.has_request_type = true; + resp.request_type = RequestType_TXFINISHED; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, HDNode *_root) +{ + inputs_count = _inputs_count; + outputs_count = _outputs_count; + coin = _coin; + root = _root; + + idx1i = idx2i = idx2o = idx3i = idx3o = idx4o = 0; + to_spend = 0; + spending = 0; + change_spend = 0; + memset(&input, 0, sizeof(TxInputType)); + memset(&resp, 0, sizeof(TxRequest)); + + signing = true; + progress = 1; + progress_total = inputs_count * (1 + inputs_count + outputs_count) + outputs_count; + + tx_init(&to, inputs_count, outputs_count, version, lock_time, false); + + send_req_1_input(); +} + +void signing_txack(TransactionType *tx) +{ + if (!signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); + layoutHome(); + return; + } + + int co; + + memset(&resp, 0, sizeof(TxRequest)); + + switch (signing_stage) { + case STAGE_REQUEST_1_INPUT: + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + memcpy(&input, tx->inputs, sizeof(TxInputType)); + send_req_2_prev_meta(); + return; + case STAGE_REQUEST_2_PREV_META: + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false); + send_req_2_prev_input(); + return; + case STAGE_REQUEST_2_PREV_INPUT: + if (!tx_hash_input(&tp, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + signing_abort(); + return; + } + if (idx2i < tp.inputs_len - 1) { + idx2i++; + send_req_2_prev_input(); + } else { + send_req_2_prev_output(); + } + return; + case STAGE_REQUEST_2_PREV_OUTPUT: + if (!tx_hash_output(&tp, tx->bin_outputs)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + signing_abort(); + return; + } + if (idx2o == input.prev_index) { + to_spend += tx->bin_outputs[0].amount; + } + if (idx2o < tp.outputs_len - 1) { + idx2o++; + send_req_2_prev_output(); + } else { + tx_hash_final(&tp, hash, true); + if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); + signing_abort(); + return; + } + tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); + tx_init(&tc, inputs_count, outputs_count, version, lock_time, true); + memset(privkey, 0, 32); + memset(pubkey, 0, 33); + send_req_3_input(); + } + return; + case STAGE_REQUEST_3_INPUT: + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + if (!tx_hash_input(&tc, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + signing_abort(); + return; + } + if (idx3i == idx1i) { + memcpy(&node, root, sizeof(HDNode)); + uint32_t k; + for (k = 0; k < tx->inputs[0].address_n_count; k++) { + hdnode_private_ckd(&node, tx->inputs[0].address_n[k]); + } + ecdsa_get_pubkeyhash(node.public_key, hash); + tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); + if (tx->inputs[0].script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + signing_abort(); + return; + } + memcpy(privkey, node.private_key, 32); + memcpy(pubkey, node.public_key, 33); + } else { + tx->inputs[0].script_sig.size = 0; + } + if (!tx_hash_input(&ti, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + signing_abort(); + return; + } + if (idx3i < inputs_count - 1) { + idx3i++; + send_req_3_input(); + } else { + send_req_3_output(); + } + return; + case STAGE_REQUEST_3_OUTPUT: + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + co = compile_output(coin, root, tx->outputs, &bin_output, idx1i == 0); + if (co < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); + signing_abort(); + return; + } else if (co == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + signing_abort(); + return; + } + if (!tx_hash_output(&tc, &bin_output)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + signing_abort(); + return; + } + if (!tx_hash_output(&ti, &bin_output)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + signing_abort(); + return; + } + if (idx1i == 0) { + if (tx->outputs[0].address_n_count > 0) { // address_n set -> change address + if (change_spend == 0) { // not set + change_spend = tx->outputs[0].amount; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + signing_abort(); + return; + } + } + spending += tx->outputs[0].amount; + } + if (idx3o < outputs_count - 1) { + idx3o++; + send_req_3_output(); + } else { + if (idx1i == 0) { + tx_hash_final(&tc, hash_check, false); + } else { + tx_hash_final(&tc, hash, false); + if (memcmp(hash, hash_check, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return; + } + } + tx_hash_final(&ti, hash, false); + resp.has_serialized = true; + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1i; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + ecdsa_sign_digest(privkey, hash, sig); + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); + resp.serialized.serialized_tx.size = tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, resp.serialized.serialized_tx.bytes); + if (idx1i < inputs_count - 1) { + idx1i++; + send_req_1_input(); + } else { + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); + layoutHome(); + return; + } + uint64_t fee = to_spend - spending; + if (fee > (((uint64_t)tc.size + 999) / 1000) * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee, ((uint64_t)tc.size + 999) / 1000); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); + layoutHome(); + return; + } + } + // last confirmation + layoutConfirmTx(coin, to_spend - change_spend - fee, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + signing_abort(); + return; + } + send_req_4_output(); + } + } + return; + case STAGE_REQUEST_4_OUTPUT: + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + signing_abort(); + return; + } + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output(&to, bin_output.amount, bin_output.script_pubkey.bytes, bin_output.script_pubkey.size, resp.serialized.serialized_tx.bytes); + if (idx4o < outputs_count - 1) { + idx4o++; + send_req_4_output(); + } else { + send_req_finished(); + signing_abort(); + } + return; + } + + fsm_sendFailure(FailureType_Failure_Other, "Signing error"); + signing_abort(); +} + +void signing_abort(void) +{ + if (signing) { + layoutHome(); + signing = false; + } +} diff --git a/firmware/signing.h b/firmware/signing.h new file mode 100644 index 0000000000..84d609b877 --- /dev/null +++ b/firmware/signing.h @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SIGNING_H__ +#define __SIGNING_H__ + +#include +#include +#include "bip32.h" +#include "types.pb.h" + +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, HDNode *_root); +void signing_abort(void); +void signing_txack(TransactionType *tx); + +#endif diff --git a/firmware/ssp.c b/firmware/ssp.c new file mode 100644 index 0000000000..089a77af11 --- /dev/null +++ b/firmware/ssp.c @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "ssp.h" +#include "rng.h" +#include "layout.h" + +void *__stack_chk_guard = 0; + +void __stack_chk_guard_setup(void) +{ + unsigned char * p; + p = (unsigned char *) &__stack_chk_guard; + p[0] = 0; + p[1] = 0; + p[2] = '\n'; + p[3] = 0xFF; // random32() & 0xFF; +} + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever +} diff --git a/firmware/ssp.h b/firmware/ssp.h new file mode 100644 index 0000000000..c1cb260209 --- /dev/null +++ b/firmware/ssp.h @@ -0,0 +1,26 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SSP_H_ +#define __SSP_H_ + +void __stack_chk_guard_setup(void); +void __attribute__((noreturn)) __stack_chk_fail(void); + +#endif diff --git a/firmware/storage.c b/firmware/storage.c new file mode 100644 index 0000000000..3351d1482b --- /dev/null +++ b/firmware/storage.c @@ -0,0 +1,327 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include + +#include "messages.pb.h" +#include "storage.pb.h" + +#include "trezor.h" +#include "aes.h" +#include "bip32.h" +#include "bip39.h" +#include "util.h" +#include "memory.h" +#include "rng.h" +#include "storage.h" +#include "debug.h" +#include "protect.h" +#include "layout2.h" + +Storage storage; + +uint8_t storage_uuid[12]; +char storage_uuid_str[25]; + +static bool sessionRootNodeCached; +static HDNode sessionRootNode; + +static bool sessionPinCached; +static char sessionPin[17]; + +static bool sessionPassphraseCached; +static char sessionPassphrase[51]; + +/* + storage layout: + + offset | type/length | description +--------+-------------+------------------------------- + 0x0000 | 4 bytes | magic = 'stor' + 0x0004 | 12 bytes | uuid + 0x0010 | ? | Storage structure + */ + +#define STORAGE_VERSION 1 + +void storage_from_flash(uint32_t version) +{ + switch (version) { + case 1: + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + break; + } + storage.version = STORAGE_VERSION; +} + +void storage_init(void) +{ + storage_reset(); + // if magic is ok + if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) == 0) { + // load uuid + memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + 4), sizeof(storage_uuid)); + data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); + // load storage struct + uint32_t version = ((Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)))->version; + if (version && version <= STORAGE_VERSION) { + storage_from_flash(version); + } + if (version != STORAGE_VERSION) { + storage_commit(); + } + } else { + storage_reset_uuid(); + storage_commit(); + } +} + +void storage_reset_uuid(void) +{ + // set random uuid + random_buffer(storage_uuid, sizeof(storage_uuid)); + data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); +} + +void storage_reset(void) +{ + // reset storage struct + memset(&storage, 0, sizeof(storage)); + storage.version = STORAGE_VERSION; + sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); + sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); + sessionPinCached = false; memset(&sessionPin, 0, sizeof(sessionPin)); +} + +static uint8_t meta_backup[FLASH_META_LEN]; + +void storage_commit(void) +{ + int i; + uint32_t *w; + // backup meta + memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); + flash_unlock(); + // erase storage + for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // modify storage + memcpy(meta_backup + FLASH_META_DESC_LEN, "stor", 4); + memcpy(meta_backup + FLASH_META_DESC_LEN + 4, storage_uuid, sizeof(storage_uuid)); + memcpy(meta_backup + FLASH_META_DESC_LEN + 4 + sizeof(storage_uuid), &storage, sizeof(Storage)); + // copy it back + for (i = 0; i < FLASH_META_LEN / 4; i++) { + w = (uint32_t *)(meta_backup + i * 4); + flash_program_word(FLASH_META_START + i * 4, *w); + } + flash_lock(); +} + +void storage_loadDevice(LoadDevice *msg) +{ + storage_reset(); + + if (msg->has_pin > 0) { + storage_setPin(msg->pin); + } + + if (msg->has_passphrase_protection) { + storage.has_passphrase_protection = true; + storage.passphrase_protection = msg->passphrase_protection; + } else { + storage.has_passphrase_protection = false; + } + + if (msg->has_node) { + storage.has_node = true; + storage.has_mnemonic = false; + memcpy(&storage.node, &(msg->node), sizeof(HDNodeType)); + sessionRootNodeCached = false; + memset(&sessionRootNode, 0, sizeof(sessionRootNode)); + } else if (msg->has_mnemonic) { + storage.has_mnemonic = true; + storage.has_node = false; + strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic)); + sessionRootNodeCached = false; + memset(&sessionRootNode, 0, sizeof(sessionRootNode)); + } + + if (msg->has_language) { + storage_setLanguage(msg->language); + } + + if (msg->has_label) { + storage_setLabel(msg->label); + } +} + +void storage_setLabel(const char *label) +{ + if (!label) return; + storage.has_label = true; + strlcpy(storage.label, label, sizeof(storage.label)); +} + +void storage_setLanguage(const char *lang) +{ + if (!lang) return; + // sanity check + if (strcmp(lang, "english") == 0) { + storage.has_language = true; + strlcpy(storage.language, lang, sizeof(storage.language)); + } +} + +void get_root_node_callback(uint32_t iter, uint32_t total) +{ + static uint8_t i; + layoutProgress("Waking up", 1000 * iter / total, i++); +} + +bool storage_getRootNode(HDNode *node) +{ + // root node is properly cached + if (sessionRootNodeCached) { + memcpy(node, &sessionRootNode, sizeof(HDNode)); + return true; + } + + // if storage has node, decrypt and use it + if (storage.has_node) { + if (!protectPassphrase()) { + return false; + } + hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode); + if (storage.has_passphrase_protection > 0) { + // decrypt hd node + aes_ctx ctx; + aes_enc_key((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), &ctx); + aes_enc_blk(sessionRootNode.chain_code, sessionRootNode.chain_code, &ctx); + aes_enc_blk(sessionRootNode.chain_code + 16, sessionRootNode.chain_code + 16, &ctx); + aes_enc_blk(sessionRootNode.private_key, sessionRootNode.private_key, &ctx); + aes_enc_blk(sessionRootNode.private_key + 16, sessionRootNode.private_key + 16, &ctx); + } + memcpy(node, &sessionRootNode, sizeof(HDNode)); + sessionRootNodeCached = true; + return true; + } + + // if storage has mnemonic, convert it to node and use it + if (storage.has_mnemonic) { + if (!protectPassphrase()) { + return false; + } + uint8_t seed[64]; + layoutProgressSwipe("Waking up", 0, 0); + mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039 + hdnode_from_seed(seed, sizeof(seed), &sessionRootNode); + memcpy(node, &sessionRootNode, sizeof(HDNode)); + sessionRootNodeCached = true; + return true; + } + + return false; +} + +const char *storage_getLabel(void) +{ + return storage.has_label ? storage.label : 0; +} + +const char *storage_getLanguage(void) +{ + return storage.has_language ? storage.language : 0; +} + +bool storage_isPinCorrect(const char *pin) +{ + return strcmp(storage.pin, pin) == 0; +} + +bool storage_hasPin(void) +{ + return storage.has_pin && strlen(storage.pin) > 0; +} + +void storage_setPin(const char *pin) +{ + if (pin && strlen(pin) > 0) { + storage.has_pin = true; + strlcpy(storage.pin, pin, sizeof(storage.pin)); + } else { + storage.has_pin = false; + storage.pin[0] = 0; + } + storage_commit(); + sessionPinCached = false; +} + +void session_cachePassphrase(const char *passphrase) +{ + strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); + sessionPassphraseCached = true; +} + +bool session_isPassphraseCached(void) +{ + return sessionPassphraseCached; +} + +void session_cachePin(const char *pin) +{ + strlcpy(sessionPin, pin, sizeof(sessionPin)); + sessionPinCached = true; +} + +bool session_isPinCached(void) +{ + return sessionPinCached && strcmp(sessionPin, storage.pin) == 0; +} + +void storage_resetPinFails(void) +{ + storage.has_pin_failed_attempts = true; + storage.pin_failed_attempts = 0; + storage_commit(); +} + +void storage_increasePinFails(void) +{ + if (!storage.has_pin_failed_attempts) { + storage.has_pin_failed_attempts = true; + storage.pin_failed_attempts = 1; + } else { + storage.pin_failed_attempts++; + } + storage_commit(); +} + +uint32_t storage_getPinFails(void) +{ + return storage.has_pin_failed_attempts ? storage.pin_failed_attempts : 0; +} + +bool storage_isInitialized(void) +{ + return storage.has_node || storage.has_mnemonic; +} diff --git a/firmware/storage.h b/firmware/storage.h new file mode 100644 index 0000000000..0efe52f132 --- /dev/null +++ b/firmware/storage.h @@ -0,0 +1,61 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __STORAGE_H__ +#define __STORAGE_H__ + +#include "types.pb.h" +#include "storage.pb.h" +#include "messages.pb.h" +#include "bip32.h" + +void storage_init(void); +void storage_reset_uuid(void); +void storage_reset(void); +void storage_commit(void); + +void storage_loadDevice(LoadDevice *msg); + +bool storage_getRootNode(HDNode *node); + +const char *storage_getLabel(void); +void storage_setLabel(const char *label); + +const char *storage_getLanguage(void); +void storage_setLanguage(const char *lang); + +void session_cachePassphrase(const char *passphrase); +bool session_isPassphraseCached(void); + +bool storage_isPinCorrect(const char *pin); +bool storage_hasPin(void); +void storage_setPin(const char *pin); +void session_cachePin(const char *pin); +bool session_isPinCached(void); +void storage_resetPinFails(void); +void storage_increasePinFails(void); +uint32_t storage_getPinFails(void); + +bool storage_isInitialized(void); + +extern Storage storage; + +extern char storage_uuid_str[25]; + +#endif diff --git a/firmware/transaction.c b/firmware/transaction.c new file mode 100644 index 0000000000..38d1480779 --- /dev/null +++ b/firmware/transaction.c @@ -0,0 +1,459 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include "transaction.h" +#include "ecdsa.h" +#include "coins.h" +#include "util.h" +#include "debug.h" +#include "protect.h" +#include "layout2.h" +#include "messages.pb.h" + +// aux methods + +uint32_t ser_length(uint32_t len, uint8_t *out) { + if (len < 253) { + out[0] = len & 0xFF; + return 1; + } + if (len < 0x10000) { + out[0] = 253; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + return 3; + } + out[0] = 254; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + out[3] = (len >> 16) & 0xFF; + out[4] = (len >> 24) & 0xFF; + return 5; +} + +uint32_t op_push(uint32_t i, uint8_t *out) { + if (i < 0x4C) { + out[0] = i & 0xFF; + return 1; + } + if (i < 0xFF) { + out[0] = 0x4C; + out[1] = i & 0xFF; + return 2; + } + if (i < 0xFFFF) { + out[0] = 0x4D; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + return 3; + } + out[0] = 0x4E; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + out[3] = (i >> 16) & 0xFF; + out[4] = (i >> 24) & 0xFF; + return 5; +} + +int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) +{ + // address_n provided-> change address -> calculate from address_n + if (in->address_n_count > 0) { + HDNode node; + uint32_t k; + memcpy(&node, root, sizeof(HDNode)); + for (k = 0; k < in->address_n_count; k++) { + hdnode_private_ckd(&node, in->address_n[k]); + } + ecdsa_get_address(node.public_key, coin->address_type, in->address); + } else + if (in->has_address) { // address provided -> regular output + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; + } + } + } else { // does not have address_n neither address + return 0; + } + + memset(out, 0, sizeof(TxOutputBinType)); + out->amount = in->amount; + + if (in->script_type == ScriptType_PAYTOADDRESS) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + uint8_t decoded[21]; + if (!ecdsa_address_decode(in->address, decoded)) { + return 0; + } + memcpy(out->script_pubkey.bytes + 3, decoded + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + return 25; + } + + if (in->script_type == ScriptType_PAYTOSCRIPTHASH) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + uint8_t decoded[21]; + if (!ecdsa_address_decode(in->address, decoded)) { + return 0; + } + memcpy(out->script_pubkey.bytes + 2, decoded + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + return 23; + } + + return 0; +} + +uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out) +{ + if (coinByAddressType(address_type)) { // valid coin type + out[0] = 0x76; // OP_DUP + out[1] = 0xA9; // OP_HASH_160 + out[2] = 0x14; // pushing 20 bytes + memcpy(out + 3, pubkeyhash, 20); + out[23] = 0x88; // OP_EQUALVERIFY + out[24] = 0xAC; // OP_CHECKSIG + return 25; + } else { + return 0; // unsupported + } +} + +int serialize_script_sig(uint8_t *signature, uint32_t signature_len, uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out) +{ + uint32_t r = 0; + r += op_push(signature_len + 1, out + r); + memcpy(out + r, signature, signature_len); r += signature_len; + out[r] = 0x01; r++; + r += op_push(pubkey_len, out + r); + memcpy(out + r, pubkey, pubkey_len); r += pubkey_len; + return r; +} + +// tx methods + +uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) +{ + memcpy(out, &(tx->version), 4); + return 4 + ser_length(tx->inputs_len, out + 4); +} + +uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out) +{ + int i; + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header(tx, out + r); + } + for (i = 0; i < 32; i++) { + *(out + r + i) = prev_hash[31 - i]; + } + r += 32; + memcpy(out + r, &prev_index, 4); r += 4; + r += ser_length(script_sig_len, out + r); + memcpy(out + r, script_sig, script_sig_len); r+= script_sig_len; + memcpy(out + r, &sequence, 4); r += 4; + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) +{ + return ser_length(tx->outputs_len, out); +} + +uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) +{ + memcpy(out, &(tx->lock_time), 4); + if (tx->add_hash_type) { + uint32_t ht = 1; + memcpy(out + 4, &ht, 4); + return 8; + } else { + return 4; + } +} + +uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out) +{ + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle(tx, out + r); + } + memcpy(out + r, &amount, 8); r += 8; + r += ser_length(script_pubkey_len, out + r); + memcpy(out + r, script_pubkey, script_pubkey_len); r+= script_pubkey_len; + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len) { + r += tx_serialize_footer(tx, out + r); + } + tx->size += r; + return r; +} + +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type) +{ + tx->inputs_len = inputs_len; + tx->outputs_len = outputs_len; + tx->version = version; + tx->lock_time = lock_time; + tx->add_hash_type = add_hash_type; + tx->have_inputs = 0; + tx->have_outputs = 0; + tx->size = 0; + sha256_Init(&(tx->ctx)); +} + +bool tx_hash_input(TxStruct *t, TxInputType *input) +{ + uint8_t buf[512]; + uint32_t r = tx_serialize_input(t, input->prev_hash.bytes, input->prev_index, input->script_sig.bytes, input->script_sig.size, input->sequence, buf); + if (!r) return false; + sha256_Update(&(t->ctx), buf, r); + return true; +} + +bool tx_hash_output(TxStruct *t, TxOutputBinType *output) +{ + uint8_t buf[512]; + uint32_t r = tx_serialize_output(t, output->amount, output->script_pubkey.bytes, output->script_pubkey.size, buf); + if (!r) return false; + sha256_Update(&(t->ctx), buf, r); + return true; +} + +void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) +{ + sha256_Final(hash, &(t->ctx)); + sha256_Raw(hash, 32, hash); + if (!reverse) return; + uint8_t i, k; + for (i = 0; i < 16; i++) { + k = hash[31 - i]; + hash[31 - i] = hash[i]; + hash[i] = k; + } +} + +bool transactionHash(TransactionType *tx, uint8_t *hash) +{ + TxStruct t; + uint32_t i; + tx_init(&t, tx->inputs_count, tx->bin_outputs_count, tx->version, tx->lock_time, false); + for (i = 0; i < tx->inputs_count; i++) { + if (!tx_hash_input(&t, &(tx->inputs[i]))) return false; + } + for (i = 0; i < tx->bin_outputs_count; i++) { + if (!tx_hash_output(&t, &(tx->bin_outputs[i]))) return false; + } + tx_hash_final(&t, hash, true); + return true; +} + +int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out) +{ + uint32_t idx, i, k, r = 0; + TxStruct ti, to; + uint8_t buf[512]; + TxInputType input; + TxOutputBinType output; + HDNode node; + uint8_t privkey[32], pubkey[33], hash[32], sig[64]; + + layoutProgressSwipe("Signing", 0, 0); + tx_init(&to, inputs_count, outputs_count, version, lock_time, false); + for (idx = 0; idx < inputs_count; idx++) { + // compute inner transaction + memcpy(&input, &(inputs[idx]), sizeof(TxInputType)); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); + memset(privkey, 0, 32); + memset(pubkey, 0, 33); + for (i = 0; i < inputs_count; i++) { + if (i == idx) { + memcpy(&node, root, sizeof(HDNode)); + for (k = 0; k < inputs[i].address_n_count; k++) { + hdnode_private_ckd(&node, inputs[i].address_n[k]); + } + ecdsa_get_pubkeyhash(node.public_key, hash); + inputs[i].script_sig.size = compile_script_sig(coin->address_type, hash, inputs[i].script_sig.bytes); + if (inputs[i].script_sig.size == 0) { + return 0; + } + memcpy(privkey, node.private_key, 32); + memcpy(pubkey, node.public_key, 33); + } else { + inputs[i].script_sig.size = 0; + } + if (!tx_hash_input(&ti, &(inputs[i]))) return 0; + } + for (i = 0; i < outputs_count; i++) { + int co = compile_output(coin, root, &(outputs[i]), &output, idx == 0); + if (co <= 0) { + return co; + } + if (!tx_hash_output(&ti, &output)) return 0; + } + tx_hash_final(&ti, hash, false); + ecdsa_sign_digest(privkey, hash, sig); + int der_len = ecdsa_sig_to_der(sig, buf); + input.script_sig.size = serialize_script_sig(buf, der_len, pubkey, 33, input.script_sig.bytes); + r += tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, out + r); + layoutProgress("Signing", 1000 * idx / inputs_count, idx); + } + for (i = 0; i < outputs_count; i++) { + if (compile_output(coin, root, &(outputs[i]), &output, false) <= 0) { + return 0; + } + r += tx_serialize_output(&to, output.amount, output.script_pubkey.bytes, output.script_pubkey.size, out + r); + } + return r; +} + +uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs) +{ + return 10 + inputs * 149 + outputs * 35; +} + +uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs) +{ + return (transactionEstimateSize(inputs, outputs) + 999) / 1000; +} + +bool transactionMessageSign(uint8_t *message, uint32_t message_len, uint8_t *privkey, const char *address, uint8_t *signature) +{ + if (message_len >= 256) { + return false; + } + + SHA256_CTX ctx; + uint8_t i, hash[32]; + + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + i = message_len; + sha256_Update(&ctx, &i, 1); + sha256_Update(&ctx, message, message_len); + sha256_Final(hash, &ctx); + sha256_Raw(hash, 32, hash); + + ecdsa_sign_digest(privkey, hash, signature + 1); + for (i = 27 + 4; i < 27 + 4 + 4; i++) { + signature[0] = i; + if (transactionMessageVerify(message, message_len, signature, address)) { + return true; + } + } + + return false; +} + +bool transactionMessageVerify(uint8_t *message, uint32_t message_len, uint8_t *signature, const char *address) +{ + if (message_len >= 256) { + return false; + } + + bool compressed; + uint8_t nV = signature[0]; + bignum256 r, s, e; + curve_point cp, cp2; + SHA256_CTX ctx; + uint8_t i, pubkey[65], decoded[21], hash[32]; + char addr[35]; + + if (nV < 27 || nV >= 35) { + return false; + } + compressed = (nV >= 31); + if (compressed) { + nV -= 4; + } + uint8_t recid = nV - 27; + // read r and s + bn_read_be(signature + 1, &r); + bn_read_be(signature + 33, &s); + // x = r + (recid / 2) * order + bn_zero(&cp.x); + for (i = 0; i < recid / 2; i++) { + bn_addmod(&cp.x, &order256k1, &prime256k1); + } + bn_addmod(&cp.x, &r, &prime256k1); + // compute y from x + uncompress_coords(recid % 2, &cp.x, &cp.y); + // calculate hash + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + i = message_len; + sha256_Update(&ctx, &i, 1); + sha256_Update(&ctx, message, message_len); + sha256_Final(hash, &ctx); + sha256_Raw(hash, 32, hash); + // e = -hash + bn_read_be(hash, &e); + bn_substract_noprime(&order256k1, &e, &e); + // r = r^-1 + bn_inverse(&r, &order256k1); + point_multiply(&s, &cp, &cp); + scalar_multiply(&e, &cp2); + point_add(&cp2, &cp); + point_multiply(&r, &cp, &cp); + pubkey[0] = 0x04; + bn_write_be(&cp.x, pubkey + 1); + bn_write_be(&cp.y, pubkey + 33); + // check if the address is correct when provided + if (address) { + ecdsa_address_decode(address, decoded); + if (compressed) { + pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); + } + ecdsa_get_address(pubkey, decoded[0], addr); + if (strcmp(addr, address) != 0) { + return false; + } + } + // check if signature verifies the digest + if (ecdsa_verify_digest(pubkey, signature + 1, hash) != 0) { + return false; + } + return true; +} diff --git a/firmware/transaction.h b/firmware/transaction.h new file mode 100644 index 0000000000..c63e7ce0cc --- /dev/null +++ b/firmware/transaction.h @@ -0,0 +1,67 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __TRANSACTION_H__ +#define __TRANSACTION_H__ + +#include +#include +#include "sha2.h" +#include "bip32.h" +#include "types.pb.h" + +typedef struct { + uint32_t inputs_len; + uint32_t outputs_len; + + uint32_t version; + uint32_t lock_time; + bool add_hash_type; + + uint32_t have_inputs; + uint32_t have_outputs; + uint32_t size; + + SHA256_CTX ctx; +} TxStruct; + +uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out); +int serialize_script_sig(uint8_t *signature, uint32_t signature_len, uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); +int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); +uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out); + +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type); +bool tx_hash_input(TxStruct *t, TxInputType *input); +bool tx_hash_output(TxStruct *t, TxOutputBinType *output); +void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); + +bool transactionHash(TransactionType *tx, uint8_t *hash); + +int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out); + +uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); + +uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs); + +bool transactionMessageSign(uint8_t *message, uint32_t message_len, uint8_t *privkey, const char *address, uint8_t *signature); + +bool transactionMessageVerify(uint8_t *message, uint32_t message_len, uint8_t *signature, const char *address); + +#endif diff --git a/firmware/trezor.c b/firmware/trezor.c new file mode 100644 index 0000000000..9298285aed --- /dev/null +++ b/firmware/trezor.c @@ -0,0 +1,53 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "trezor.h" +#include "oled.h" +#include "bitmaps.h" +#include "util.h" +#include "usb.h" +#include "setup.h" +#include "storage.h" +#include "layout2.h" +#include "ssp.h" + +int main(void) +{ + setup(); + oledInit(); +// __stack_chk_guard_setup(); +#if DEBUG_LINK + oledSetDebug(1); + storage_reset(); // wipe storage if debug link + storage_reset_uuid(); + storage_commit(); +#endif + + oledDrawBitmap(40, 0, &bmp_logo64); + oledRefresh(); + + storage_init(); + layoutHome(); + usbInit(); + for (;;) { + usbPoll(); + } + + return 0; +} diff --git a/firmware/trezor.h b/firmware/trezor.h new file mode 100644 index 0000000000..c6ecbb1d38 --- /dev/null +++ b/firmware/trezor.h @@ -0,0 +1,38 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __TREZOR_H__ +#define __TREZOR_H__ + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 +#define VERSION_PATCH 0 + +#define STR(X) #X +#define VERSTR(X) STR(X) + +#ifndef DEBUG_LINK +#define DEBUG_LINK 0 +#endif + +#ifndef DEBUG_LOG +#define DEBUG_LOG 0 +#endif + +#endif diff --git a/firmware/usb.c b/firmware/usb.c new file mode 100644 index 0000000000..43c7bd9018 --- /dev/null +++ b/firmware/usb.c @@ -0,0 +1,334 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include "trezor.h" +#include "usb.h" +#include "debug.h" +#include "messages.h" +#include "storage.h" +#include "util.h" + +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) +#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) + +static const struct usb_device_descriptor dev_descr = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x534c, + .idProduct = 0x0001, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* got via usbhid-dump from CP2110 */ +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, + 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, + 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, + 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, + 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, + 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, + 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, + 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, + 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, + 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, + 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, + 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, + 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, + 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, + 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, + 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, + 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, + 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, + 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, + 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, + 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, + 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, +}; + +static const struct { + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) hid_function = { + .hid_descriptor = { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + } +}; + +static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor hid_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), +}}; + +#if DEBUG_LINK +static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor hid_iface_debug[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints_debug, + .extra = &hid_function, + .extralen = sizeof(hid_function), +}}; +#endif + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = hid_iface, +#if DEBUG_LINK +}, { + .num_altsetting = 1, + .altsetting = hid_iface_debug, +#endif +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, +#if DEBUG_LINK + .bNumInterfaces = 2, +#else + .bNumInterfaces = 1, +#endif + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SatoshiLabs", + "TREZOR", + (const char *)storage_uuid_str, +}; + +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *, struct usb_setup_data *)) +{ + (void)complete; + (void)dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) + return 0; + + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + + return 1; +} + +static volatile char tiny = 0; + +static void hid_rx_callback(usbd_device *dev, uint8_t ep) +{ + (void)ep; + static uint8_t buf[64] __attribute__ ((aligned(4))); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; + debugLog(0, "", "hid_rx_callback"); + if (!tiny) { + msg_read(buf, 64); + } else { + msg_read_tiny(buf, 64); + } +} + +#if DEBUG_LINK +static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) +{ + (void)ep; + static uint8_t buf[64] __attribute__ ((aligned(4))); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; + debugLog(0, "", "hid_debug_rx_callback"); + if (!tiny) { + msg_debug_read(buf, 64); + } else { + msg_read_tiny(buf, 64); + } +} +#endif + +static void hid_set_config(usbd_device *dev, uint16_t wValue) +{ + (void)wValue; + + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); +#if DEBUG_LINK + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); +#endif + + usbd_register_control_callback( + dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + hid_control_request); +} + +static usbd_device *usbd_dev; +static uint8_t usbd_control_buffer[128]; + +void usbInit(void) +{ + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); +} + +void usbPoll(void) +{ + static uint8_t *data; + // poll read buffer + usbd_poll(usbd_dev); + // write pending data + data = msg_out_data(); + if (data) { + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} + } +#if DEBUG_LINK + // write pending debug data + data = msg_debug_out_data(); + if (data) { + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data, 64) != 64 ) {} + } +#endif +} + +void usbReconnect(void) +{ + usbd_disconnect(usbd_dev, 1); + delay(1000); + usbd_disconnect(usbd_dev, 0); +} + +void usbTiny(char set) +{ + tiny = set; +} diff --git a/firmware/usb.h b/firmware/usb.h new file mode 100644 index 0000000000..eec42e34e9 --- /dev/null +++ b/firmware/usb.h @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __USB_H__ +#define __USB_H__ + +void usbInit(void); +void usbPoll(void); +void usbReconnect(void); +void usbTiny(char set); + +#endif diff --git a/gen/bitmaps.c b/gen/bitmaps.c new file mode 100644 index 0000000000..64808987fa --- /dev/null +++ b/gen/bitmaps.c @@ -0,0 +1,49 @@ +#include "bitmaps.h" + +const uint8_t bmp_digit0_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_digit1_data[] = { 0xff, 0xff, 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xff, 0xff, }; +const uint8_t bmp_digit2_data[] = { 0xff, 0xff, 0xe0, 0x1f, 0xe0, 0x0f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xf8, 0x0f, 0xf0, 0x1f, 0xe1, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0x07, 0xe0, 0x07, 0xff, 0xff, }; +const uint8_t bmp_digit3_data[] = { 0xff, 0xff, 0xe0, 0x1f, 0xe0, 0x0f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xf8, 0x0f, 0xf8, 0x0f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xe0, 0x0f, 0xe0, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_digit4_data[] = { 0xff, 0xff, 0xff, 0x0f, 0xfe, 0x0f, 0xfc, 0x0f, 0xf8, 0x0f, 0xf1, 0x0f, 0xe3, 0x0f, 0xc7, 0x0f, 0xcf, 0x0f, 0xc0, 0x0f, 0xc0, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0xff, }; +const uint8_t bmp_digit5_data[] = { 0xff, 0xff, 0xe0, 0x1f, 0xe0, 0x1f, 0xe7, 0xff, 0xe7, 0xff, 0xe0, 0x1f, 0xe0, 0x0f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xe0, 0x0f, 0xe0, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_digit6_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x1f, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0x1f, 0xe0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_digit7_data[] = { 0xff, 0xff, 0xe0, 0x07, 0xe0, 0x07, 0xff, 0x87, 0xff, 0x87, 0xff, 0x0f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfc, 0x3f, 0xf8, 0x7f, 0xf8, 0x7f, 0xf8, 0x7f, 0xf8, 0x7f, 0xf8, 0x7f, 0xf8, 0x7f, 0xff, 0xff, }; +const uint8_t bmp_digit8_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_digit9_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x07, 0xf8, 0x07, 0xff, 0x87, 0xff, 0x87, 0xf8, 0x0f, 0xf8, 0x1f, 0xff, 0xff, }; +const uint8_t bmp_gears0_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x1e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xc0, 0x18, 0x00, 0x00, 0x7f, 0xfd, 0xe0, 0x3c, 0x00, 0x00, 0x7f, 0xfd, 0xe0, 0x7c, 0x00, 0x00, 0xff, 0xfd, 0xff, 0xf8, 0x00, 0x00, 0xf8, 0x7e, 0xff, 0xf8, 0x00, 0x00, 0xf0, 0x1e, 0xff, 0xf0, 0x00, 0x00, 0x60, 0x0d, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_gears1_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xcf, 0x80, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x01, 0xf8, 0x3f, 0xe1, 0xc0, 0x00, 0x00, 0xff, 0xfc, 0xc1, 0xc0, 0x00, 0x00, 0xff, 0xfb, 0x03, 0xc0, 0x00, 0x01, 0xff, 0xf7, 0xc3, 0xc0, 0x00, 0x03, 0xff, 0xf7, 0xff, 0xc0, 0x00, 0x03, 0xc7, 0xf7, 0xff, 0xe0, 0x00, 0x01, 0x81, 0xf3, 0xff, 0xf0, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0x80, 0x00, 0x00, 0xe1, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x3f, 0x80, 0x00, 0x00, 0x03, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_gears2_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc1, 0x80, 0x00, 0x00, 0x07, 0x3f, 0xf7, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x3e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x3f, 0x0e, 0x00, 0x00, 0x07, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x06, 0x1f, 0xe1, 0x9f, 0x83, 0x00, 0x00, 0x0f, 0xce, 0x7f, 0xef, 0x80, 0x00, 0x07, 0x9f, 0xff, 0xff, 0x80, 0x00, 0x07, 0x9f, 0xff, 0xff, 0x00, 0x00, 0x03, 0x8f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x7e, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x0c, 0x3f, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_gears3_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x01, 0x81, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x1e, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x3e, 0x70, 0x00, 0x00, 0x00, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x7f, 0xff, 0x78, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x7c, 0x0e, 0x00, 0x00, 0x1f, 0xff, 0x7f, 0x9f, 0x00, 0x00, 0x1f, 0x87, 0x7f, 0xff, 0x00, 0x00, 0x1e, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x1e, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x0c, 0x1f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x3c, 0x00, 0x00, 0x00, 0x3f, 0xe0, 0x3e, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x3f, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0x7f, 0xc0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x07, 0x8f, 0xe0, 0x00, 0x00, 0x00, 0x03, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_icon_error_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7b, 0xde, 0xf1, 0x8f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf1, 0x8f, 0x7b, 0xde, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, }; +const uint8_t bmp_icon_info_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3e, 0x7c, 0x7e, 0x7e, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0x7e, 0x7e, 0x3e, 0x7c, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, }; +const uint8_t bmp_icon_ok_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xbf, 0xf9, 0x3f, 0xf8, 0x7f, 0xfc, 0xff, 0x7e, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, }; +const uint8_t bmp_icon_question_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x79, 0x9e, 0xf3, 0xcf, 0xff, 0xcf, 0xff, 0x9f, 0xff, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0x7f, 0xfe, 0x3e, 0x7c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, }; +const uint8_t bmp_icon_warning_data[] = { 0x01, 0x80, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0e, 0x70, 0x0e, 0x70, 0x1e, 0x78, 0x1e, 0x78, 0x3e, 0x7c, 0x3f, 0xfc, 0x7e, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, }; +const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0x81, 0xfc, 0x00, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x00, 0x78, 0x00, 0x1e, 0x00, 0x00, 0xf8, 0x00, 0x1f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0xe0, 0x00, 0x07, 0xf0, 0x0f, 0xfc, 0x00, 0x3f, 0xf0, 0x0f, 0xff, 0x81, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x81, 0x80, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x7e, 0x08, 0x00, 0x00, 0x21, 0x81, 0x84, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x22, 0x00, 0x00, 0x48, 0x00, 0x12, 0x00, 0x00, 0x88, 0x00, 0x11, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x03, 0x9f, 0xff, 0xf9, 0xc0, 0x04, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x3f, 0xff, 0xfc, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x60, 0x00, 0x06, 0x10, 0x08, 0x1c, 0x00, 0x38, 0x10, 0x08, 0x03, 0x81, 0xc0, 0x10, 0x07, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data}; +const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data}; +const BITMAP bmp_digit2 = {16, 16, bmp_digit2_data}; +const BITMAP bmp_digit3 = {16, 16, bmp_digit3_data}; +const BITMAP bmp_digit4 = {16, 16, bmp_digit4_data}; +const BITMAP bmp_digit5 = {16, 16, bmp_digit5_data}; +const BITMAP bmp_digit6 = {16, 16, bmp_digit6_data}; +const BITMAP bmp_digit7 = {16, 16, bmp_digit7_data}; +const BITMAP bmp_digit8 = {16, 16, bmp_digit8_data}; +const BITMAP bmp_digit9 = {16, 16, bmp_digit9_data}; +const BITMAP bmp_gears0 = {48, 48, bmp_gears0_data}; +const BITMAP bmp_gears1 = {48, 48, bmp_gears1_data}; +const BITMAP bmp_gears2 = {48, 48, bmp_gears2_data}; +const BITMAP bmp_gears3 = {48, 48, bmp_gears3_data}; +const BITMAP bmp_icon_error = {16, 16, bmp_icon_error_data}; +const BITMAP bmp_icon_info = {16, 16, bmp_icon_info_data}; +const BITMAP bmp_icon_ok = {16, 16, bmp_icon_ok_data}; +const BITMAP bmp_icon_question = {16, 16, bmp_icon_question_data}; +const BITMAP bmp_icon_warning = {16, 16, bmp_icon_warning_data}; +const BITMAP bmp_logo48 = {40, 48, bmp_logo48_data}; +const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data}; +const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; +const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h new file mode 100644 index 0000000000..9eff4cd592 --- /dev/null +++ b/gen/bitmaps.h @@ -0,0 +1,35 @@ +#ifndef __BITMAPS_H__ +#define __BITMAPS_H__ + +#include + +typedef struct { + uint8_t width, height; + const uint8_t *data; +} BITMAP; + +extern const BITMAP bmp_digit0; +extern const BITMAP bmp_digit1; +extern const BITMAP bmp_digit2; +extern const BITMAP bmp_digit3; +extern const BITMAP bmp_digit4; +extern const BITMAP bmp_digit5; +extern const BITMAP bmp_digit6; +extern const BITMAP bmp_digit7; +extern const BITMAP bmp_digit8; +extern const BITMAP bmp_digit9; +extern const BITMAP bmp_gears0; +extern const BITMAP bmp_gears1; +extern const BITMAP bmp_gears2; +extern const BITMAP bmp_gears3; +extern const BITMAP bmp_icon_error; +extern const BITMAP bmp_icon_info; +extern const BITMAP bmp_icon_ok; +extern const BITMAP bmp_icon_question; +extern const BITMAP bmp_icon_warning; +extern const BITMAP bmp_logo48; +extern const BITMAP bmp_logo48_empty; +extern const BITMAP bmp_logo64; +extern const BITMAP bmp_logo64_empty; + +#endif diff --git a/gen/bitmaps/.gitignore b/gen/bitmaps/.gitignore new file mode 100644 index 0000000000..68359a7869 --- /dev/null +++ b/gen/bitmaps/.gitignore @@ -0,0 +1,2 @@ +*.c +*.h diff --git a/gen/bitmaps/digit0.png b/gen/bitmaps/digit0.png new file mode 100644 index 0000000000000000000000000000000000000000..9dfc0a41cb6d476032f20def389587ae9511821b GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|4xTQKAsXl323hhk7;p$(`d>eD z-7)RL*8ygZ5e$=ZnuYTi8aX@X>^D9cG~r3}UYF=c()SD&WN(=*+&*`z%C^t@%mt;z UKWA*c4m69w)78&qol`;+0Nsr!6951J literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit1.png b/gen/bitmaps/digit1.png new file mode 100644 index 0000000000000000000000000000000000000000..8645ae6f1ede04cc5e23d8e80c843e81f325883f GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|=AJH&AsXkC|NQ@N&#c+N8r(5) zqTsn>CVia!S!)_PRjx+lDEJ=!|NlQ{8)K?jPnLuMZ_g67e1_cB{L=q9d%ppVVDNPH Kb6Mw<&;$UlZ6jj< literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit2.png b/gen/bitmaps/digit2.png new file mode 100644 index 0000000000000000000000000000000000000000..81f206e79a393468481c80bf96b4cd0904b5292d GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|9-c0aAsXkC|NQ@N&#c+NdM+s? z<;W_gvo2~)Zi^(3bR73Q;q~y;3<(dGE!Ph;-S3{kc+_Q5)|`(G>MzQ}JYD@<);T3K0RS1ZE+hZ| literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit3.png b/gen/bitmaps/digit3.png new file mode 100644 index 0000000000000000000000000000000000000000..eef5494406771d1d84f07eb38789bef29a9192d9 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|E}kxqAsXkC|NQ@N&#c+NdM+s? z<;W_gvo2~)Zi^(3bR73Q;q~y;3<(dGE!Ph;-S3{k=(>sbu=bRKrK*#hIdwxMJbmvm Yoc$mt{wRxoCeS9&b?%k={uS)bS#UOGu=eD+s=1vHz%)78&qol`;+0Ce{)O#lD@ literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit5.png b/gen/bitmaps/digit5.png new file mode 100644 index 0000000000000000000000000000000000000000..aafcd3c54549d02e8494ca4bdd4e80fcc25404cb GIT binary patch literal 128 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|?w&4=AsXkC|NQ@N&#c+NdM+s? z<;W_gvo30ELX6yXpA8s~nkD>dNwHrbd9dU7#S>l+PkDShTyVj`LU*AnYohdpLvtry bdBV$}q9rZ0_f^9oppguou6{1-oD!M literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit6.png b/gen/bitmaps/digit6.png new file mode 100644 index 0000000000000000000000000000000000000000..0b0c59eac082a76c225dcf8c35df264cf0d9ce55 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|KAtX)AsXlJ203yu7;wzG_<#SK zb&5}4?8@s*YgMQ;n|g^^z(uVs-MamhS@p5Vux%>}tF2EY?rlhsjWK;KT_=$6>zK%L g1Iuj3oX53{yH_hpl&vti3N)9&)78&qol`;+091c1g8%>k literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit7.png b/gen/bitmaps/digit7.png new file mode 100644 index 0000000000000000000000000000000000000000..e4eea9e0a41ae441f3bbb289aabbee9512cb3aa5 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|Zk{fVAsXkC|NQ@N&#c+NdM+s? z<;Y^bJUwCN&IZ=YJb%h2Z4)*Go0?Ba~}32iLGANv-TY49rY_AF7$ ZXK36lA!~C#rU_^wgQu&X%Q~loCIFfKCei=^ literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit8.png b/gen/bitmaps/digit8.png new file mode 100644 index 0000000000000000000000000000000000000000..de021652a1a37f7860abb4e01013d6e3f892505f GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|E}kxqAsXkC|NQ@N&#c+N+I#-Q zi4L`t23H>B2@qV|KFcuut`LixwGM$ltkf9(Qt>r2TLYOc|`>4%~DWac~Y98 Xtx8>ZrR?u!pm_|Qu6{1-oD!M<;p-^n literal 0 HcmV?d00001 diff --git a/gen/bitmaps/digit9.png b/gen/bitmaps/digit9.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7458aae68d597f726d214f9c837d94ea18e9bd GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|-kvUwAsXlJ23hhk7;p$({$D?H zU0c}N?3;TOx)d^nbvhY6+$8qCvzuI}JE7;u#wTV+_?b_vo4E5~tGmD7_NK?Ozv6{% f#yN@|{<7Dcxld7A?VYhE&{zgfS3j3^P6l$`hU_9=$O?}J6FrV3A^?c$tEa)z0ARC~ zWEDRTNsJRXt3Z9(t~p@_n{^khw*6ZG6+bM<(PH_V{lAYNexS2ZY`I$)EyebpS*5xU z*~gD9<6^ta`Pi_fs5ksNiom`%W;{qX8UuU)C*qkf)q+{d00000NkvXXu0mjf!2^Ao literal 0 HcmV?d00001 diff --git a/gen/bitmaps/gears1.png b/gen/bitmaps/gears1.png new file mode 100644 index 0000000000000000000000000000000000000000..9fa6a8102a06ed63ff8369bb6a157c819da78e32 GIT binary patch literal 326 zcmV-M0lEH(P)g(z@U>8!I4?+PV`GC08GkONeAbD?5YokUmDy7WJx;PS z;oLP9OsV(rQ@Q{$wv883;&m!rvRl}+l7;2=5}`4h#s@s=iYdY?+&+cT(P4Tt+G4jC zC&3Ezv}XQJFH=m8MS;o}p@s3-*UqZLx{lczgCbojaG0ybJ(W#WhtlmW|Fv_{sSk|x z>2gF4_D{p2JEj?j05HGF?7rf9+p|fVTynoUw36rcVOUV4a;YG>mW_B z`Y639gy31lEz1D;h(Yas2@$GTfDIZJtw9sxC6+5L6kduAddR?+(XAuw@wC1Aq>aD9 Y3+@u1Hl08`n*aa+07*qoM6N<$f~#kdUH||9 literal 0 HcmV?d00001 diff --git a/gen/bitmaps/gears2.png b/gen/bitmaps/gears2.png new file mode 100644 index 0000000000000000000000000000000000000000..56c199862071f6b90092964214e5d0a17677afe7 GIT binary patch literal 293 zcmV+=0owkFP)brhvQck!c||kw%Zh!^6Wi(3uxw{1yPFfP%E(LbeMa>jZ}n@BMQB3Tr!x3?d;k*Ga)o>MajBCn$ILl#~I1N!JWes~@)(@>4F zFkG*huZ>#m(58EpK<~V=mp<+P4iMd|@H>=4OjaH)^i}Oq%`zjh_8J|Al!?5`qr1ff rQHySBlMhgur~cWS+WJqe$5wFyoXdeqtB%bx00000NkvXXu0mjf15ki0 literal 0 HcmV?d00001 diff --git a/gen/bitmaps/gears3.png b/gen/bitmaps/gears3.png new file mode 100644 index 0000000000000000000000000000000000000000..9aa384062fe95c8549a9254a74ae602f724de024 GIT binary patch literal 330 zcmV-Q0k!^#P)v@LnS<0e*bow)g8;Y**h`>7p7M3Nggwm#n~U2C8mO zH=Y$kxloW@26Q8~HS=ur`o|y47>VfqiB$ zRpqE-Xd$95>--#y524UV*Pw4c)W8P-(o(X9z6ONf%ldpO`$$+6*X**H2DojyY6$YY z9De*KyFIob%7 literal 0 HcmV?d00001 diff --git a/gen/bitmaps/generate.py b/gen/bitmaps/generate.py new file mode 100755 index 0000000000..54b3ac2cbe --- /dev/null +++ b/gen/bitmaps/generate.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +import glob +import os +from PIL import Image + +hdrs = [] +data = [] +imgs = [] + +def encode_pixels(img): + r = '' + img = [ (x[0] + x[1] + x[2] > 384 and '1' or '0') for x in img] + for i in range(len(img) / 8): + c = ''.join(img[i * 8 : i * 8 + 8]) + r += '0x%02x, ' % int(c, 2) + return r + +cnt = 0 +for fn in sorted(glob.glob('*.png')): + print 'Processing:', fn + im = Image.open(fn) + name = os.path.splitext(fn)[0] + w, h = im.size + if w % 8 != 0: + raise Exception('Width must be divisable by 8! (%s is %dx%d)' % (fn, w, h)) + img = list(im.getdata()) + hdrs.append('extern const BITMAP bmp_%s;\n' % name) + imgs.append('const BITMAP bmp_%s = {%d, %d, bmp_%s_data};\n' % (name, w, h, name)) + data.append('const uint8_t bmp_%s_data[] = { %s};\n' % (name, encode_pixels(img))) + cnt += 1 + +with open('../bitmaps.c', 'wt') as f: + f.write('#include "bitmaps.h"\n\n') + for i in range(cnt): + f.write(data[i]) + f.write('\n') + for i in range(cnt): + f.write(imgs[i]) + f.close() + +with open('../bitmaps.h', 'wt') as f: + f.write('''#ifndef __BITMAPS_H__ +#define __BITMAPS_H__ + +#include + +typedef struct { + uint8_t width, height; + const uint8_t *data; +} BITMAP; + +''') + + for i in range(cnt): + f.write(hdrs[i]) + + f.write('\n#endif\n') + f.close() diff --git a/gen/bitmaps/icon_error.png b/gen/bitmaps/icon_error.png new file mode 100644 index 0000000000000000000000000000000000000000..f23a1e79459682b18fdb9be90153f566bc6931d2 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|@t!V@AsXlBPVyEyV8G$@dC&j3 zFPB};ykIC_&L&}aXomNsy$r#(H*aoJy>0Sl!~aA6@!(@vm<`3btR|!FfMzk9>ZzlfW(y%TqwB7(8A5T-G@yGywok C=sQ#Z literal 0 HcmV?d00001 diff --git a/gen/bitmaps/icon_info.png b/gen/bitmaps/icon_info.png new file mode 100644 index 0000000000000000000000000000000000000000..2044c7622f608eda67691abc280b20fff1fb5a76 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|fu1goAsXk823hhkC~$24^Z&fX zj2Q*W-8l}YBXu&*tWjcUnY~z-T{Wuk!6N@#yg`xCy$x!=q+EqpKNe|u&R5TQvFM`V liB+og-$JB>Kbk(>%UJeJQ7PL0;Vhux44$rjF6*2UngHOLF8}}l literal 0 HcmV?d00001 diff --git a/gen/bitmaps/icon_ok.png b/gen/bitmaps/icon_ok.png new file mode 100644 index 0000000000000000000000000000000000000000..36fcee2a2e86775be4a2b82be2aebf4e854bc848 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`d7dtgAr_~nPWBdKaAaYgeCPkU zv{bPz@%n+cxD^?kE7CMs7!+nE-8vNN7rkTEMb^5juegq@?K%+XVtiVu?1RQ5Q9bDi ze~#C_t+Q=BJlAj5HIvRYSx3&6c{IIieXaZB_^X~xJK25nX7_nYpDx?U-&k)Uwf$$# QLZHnIp00i_>zopr0PST!LjV8( literal 0 HcmV?d00001 diff --git a/gen/bitmaps/icon_question.png b/gen/bitmaps/icon_question.png new file mode 100644 index 0000000000000000000000000000000000000000..b3ef441620f429ce82d8e33acf69222c0811a2c2 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|37#&FAsXkGPO|1ZV8G%0TI2hE zBUz&-hr7E&wn@yENU^PUJ<{lLYu>!MrcU1yQc}1!wC^~R^T%COUHg)@_xh_o`u*ih zDe98+E*DY-J2dD-QQIt$OR?f57Vd~rw0tphE`zeX%Qv6Zp^V+L0Q$1X;1jfY&- kYaT5*&g^(Sc-AxqEnh8`9p^4z1{%)b>FVdQ&MBb@08-^M?*IS* literal 0 HcmV?d00001 diff --git a/gen/bitmaps/logo48.png b/gen/bitmaps/logo48.png new file mode 100644 index 0000000000000000000000000000000000000000..86ec6867677e5b00585df4da64093b472c4f89bf GIT binary patch literal 283 zcmV+$0p$LPP)Q1H?PlUe!tHD;F^ufOeY*8mZeQ~uLa2}oXK>`wxfCMBU0SQRJ`xn;d za+!56^b}?dRqTaDtHqXK1*8QWD%@|?#-oico9L%umwj$=405tyUHxqVM`7-H2bcju hv$_@R^NOwLM1>c@}U7>w#GPBTYP8 zj5>~h!hovkUJ=h&2(ae>i9r-{7_ep78-obs7C9i6lf6F@7S#g-ZGtJ zKtX_!?a2VHccmEbD%P@iBOn2n)q}m$=E-FdrPKTu&&qwC6joP&`5BTO+p=^aVsA)M9}AJFWN%#=kg-sO^;*QV97ZN& z-ir~#k%t`1msv#5ScQm9_!;8v7<9cfJsyJ*SkL8rI^fLq1EHR-VeHkGSO5S307*qo IM6N<$g0sPd%>V!Z literal 0 HcmV?d00001 diff --git a/gen/bitmaps/logo64.png b/gen/bitmaps/logo64.png new file mode 100644 index 0000000000000000000000000000000000000000..d07a745fbbab8e2ba847b369c4e376ff3aa74b26 GIT binary patch literal 317 zcmV-D0mA-?P)j^YhI|l+g#T?^(IQ;DasW~lUksK%RcG|>jHUh4v3uO$6w~W z$Kcx3q!vgZfdmprAb|uD=#R3F<3JvGvYyF9+I%at%#;tAuVYLsA~kEC?sAz|eCB#J zW-;&i0y`IyIwCMF4@qGWJ}aH6^oB2iowCFa2~09Nih8$&FImP7&co#c?QCp=x*-a> P00000NkvXXu0mjf^WK6C literal 0 HcmV?d00001 diff --git a/gen/bitmaps/logo64_empty.png b/gen/bitmaps/logo64_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..ec8ba1da415ff5d10e317c8d5d5d39da3eeecd7e GIT binary patch literal 444 zcmV;t0YmVXj(2TM7zMx378YprU=dM2m5AS`^ zEAubI0;FW6tBYrvSL|1y9<5L5DcWTf9l**e30r@p0@R~BY^W%TXUdJGa`Or`W5_u) z4uo2qREN#C44A8hQpb6y0Tj;G6@|p_uuU4~rCzK7F*D{52nA%Vb{3|kR!4n2A^76phDX)jA^OG@g) mYanbY%qJhAl2mCE>>odGabf*O0ohLg0000 FONT_END)) { + c = '?'; + } + return font_data[(int)(c - FONT_START)][0]; +} + +int fontStringWidth(const char *s) { + if (!s) return 0; + int l = 0; + char *c; + for (c = (char *)s; *c; c++) { + l += fontCharWidth(*c) + 1; + } + return l; +} diff --git a/gen/fonts.h b/gen/fonts.h new file mode 100644 index 0000000000..0cd6b62200 --- /dev/null +++ b/gen/fonts.h @@ -0,0 +1,15 @@ +#ifndef __FONTS_H__ +#define __FONTS_H__ + +#include + +#define FONT_START 32 +#define FONT_END 128 +#define FONT_HEIGHT 8 + +int fontCharWidth(char c); +int fontStringWidth(const char *s); + +extern const uint8_t *font_data[FONT_END - FONT_START + 1]; + +#endif diff --git a/gen/fonts/font.png b/gen/fonts/font.png new file mode 100644 index 0000000000000000000000000000000000000000..efc88495d6dc5fc311dc2323589921237abf321f GIT binary patch literal 1079 zcmV-71jze|P)<9}F+Y19Ur+cIa*hUZp8~um{-mL!>e#w1&@*_d+~2c6ydi(S2SCVIsA7;z(8zC*!)Qij!xr6&LtNsUpxzz>rdPbD=aup$!f_ z@b0LcU}{DJP$wP4nOF~Rh71g?7cVkHM{{bASNTUu=L``qIub6Zrr?Luf;>;AQzZ&aD59a0k5TP^a{s=vsSAgVW>l)QB`VH*t&}(?K8s zJ(`;f5eOxjd@`w$Pmy>>7~eOW*mD7AMI0zqTOB>YTmoEYpfot|I$At^`;Q}@!X<}G zAkc&z^0MjepKQkFw}kxXMs(dnKNHnMvA7=c0~PKaPIC=tu_(HmhTzoY9T;I~u`2Q` z3h^%UXn{AbpG6A~DKn;JXBz7kakWB|FyB<}38OovDHpFGD>>BdrNElFpw?wslsjkwgl?J(FdDUT&{Ops zFU=Lx5amoPD>D|cPmtk2HG_rtLPE2kx6v(RY7?z8^VPkBbWnnkdlC`W>WKNx#TFz@z2CL($7edlyfX>SDUH5JdGD4~pzNBuOZTrb|Rb zSlF-iZ_$~jqx)AzY-sDLv!Z(-DNzNvFcu9P`P#iH)& zL_e*9u-tax6Dk38OxZslzki7Sny20i)fL?I7NJ3FRC1kVA?#B=TTd?-)P7)oC`$Fb z4~g9L6}(R3nJ5V)utCRFQHgDEyhs>`J+7=qfvpv>>k>mq_B^FAN<7c%I0Zk7g*!Fg zPt&VC647CKt^|0AnM1saCd))aJKCJ?O4qi@fG>RKoqpi xJHh1MGgb^Dga_^ftKzbRuk6nBq~f_)@DH^x^cbajO1J<3002ovPDHLkV1g+<|GfYJ literal 0 HcmV?d00001 diff --git a/gen/fonts/generate.py b/gen/fonts/generate.py new file mode 100755 index 0000000000..b7a1dd7cf6 --- /dev/null +++ b/gen/fonts/generate.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +from PIL import Image + +class Img(object): + + def __init__(self, fn): + im = Image.open(fn) + self.w, self.h = im.size + self.data = list(im.getdata()) + + def pixel(self, r, c): + p = self.data[ r + c * self.w ] + if p == (255, 255, 255): + return '0' + if p == (0, 0, 0): + return '1' + if p == (255, 0, 255): + return None + raise Exception('Unknown color', p) + +img = Img('font.png') +cur = '' + +for i in range(img.w): + if img.pixel(i, 0) == None: + cur = '\\x%02x' % (len(cur) / 4) + cur + print '\t(uint8_t *)"%s",' % cur + cur = '' + continue + val = img.pixel(i, 0) + img.pixel(i, 1) + img.pixel(i, 2) + img.pixel(i, 3) + img.pixel(i, 4) + img.pixel(i, 5) + img.pixel(i, 6) + img.pixel(i, 7) + cur += '\\x%02x' % int(val, 2) diff --git a/gen/handlers/handlers.py b/gen/handlers/handlers.py new file mode 100755 index 0000000000..d74a64afe6 --- /dev/null +++ b/gen/handlers/handlers.py @@ -0,0 +1,99 @@ +#!/usr/bin/python + +handlers = [ + 'hard_fault_handler', + 'mem_manage_handler', + 'bus_fault_handler', + 'usage_fault_handler', + 'nvic_wwdg_isr', + 'pvd_isr', + 'tamp_stamp_isr', + 'rtc_wkup_isr', + 'flash_isr', + 'rcc_isr', + 'exti0_isr', + 'exti1_isr', + 'exti2_isr', + 'exti3_isr', + 'exti4_isr', + 'dma1_stream0_isr', + 'dma1_stream1_isr', + 'dma1_stream2_isr', + 'dma1_stream3_isr', + 'dma1_stream4_isr', + 'dma1_stream5_isr', + 'dma1_stream6_isr', + 'adc_isr', + 'can1_tx_isr', + 'can1_rx0_isr', + 'can1_rx1_isr', + 'can1_sce_isr', + 'exti9_5_isr', + 'tim1_brk_tim9_isr', + 'tim1_up_tim10_isr', + 'tim1_trg_com_tim11_isr', + 'tim1_cc_isr', + 'tim2_isr', + 'tim3_isr', + 'tim4_isr', + 'i2c1_ev_isr', + 'i2c1_er_isr', + 'i2c2_ev_isr', + 'i2c2_er_isr', + 'spi1_isr', + 'spi2_isr', + 'usart1_isr', + 'usart2_isr', + 'usart3_isr', + 'exti15_10_isr', + 'rtc_alarm_isr', + 'usb_fs_wkup_isr', + 'tim8_brk_tim12_isr', + 'tim8_up_tim13_isr', + 'tim8_trg_com_tim14_isr', + 'tim8_cc_isr', + 'dma1_stream7_isr', + 'fsmc_isr', + 'sdio_isr', + 'tim5_isr', + 'spi3_isr', + 'uart4_isr', + 'uart5_isr', + 'tim6_dac_isr', + 'tim7_isr', + 'dma2_stream0_isr', + 'dma2_stream1_isr', + 'dma2_stream2_isr', + 'dma2_stream3_isr', + 'dma2_stream4_isr', + 'eth_isr', + 'eth_wkup_isr', + 'can2_tx_isr', + 'can2_rx0_isr', + 'can2_rx1_isr', + 'can2_sce_isr', + 'otg_fs_isr', + 'dma2_stream5_isr', + 'dma2_stream6_isr', + 'dma2_stream7_isr', + 'usart6_isr', + 'i2c3_ev_isr', + 'i2c3_er_isr', + 'otg_hs_ep1_out_isr', + 'otg_hs_ep1_in_isr', + 'otg_hs_wkup_isr', + 'otg_hs_isr', + 'dcmi_isr', + 'cryp_isr', + 'hash_rng_isr', +] + +with open('handlers.c', 'wt') as f: + f.write('#include "layout.h"\n') + f.write('#include "oled.h"\n\n') + for i in handlers: + f.write('void __attribute__((noreturn)) %s(void)\n' % i) + f.write('{\n') + f.write('\tlayoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Encountered", NULL, "%s", NULL, "Please restart", "the device.");\n' % i.upper()) + f.write('\tfor (;;) {} // loop forever\n') + f.write('}\n\n') diff --git a/layout.c b/layout.c new file mode 100644 index 0000000000..6513c7cf5b --- /dev/null +++ b/layout.c @@ -0,0 +1,105 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "layout.h" +#include "oled.h" + +void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) +{ + int left = 0; + oledClear(); + switch (icon) { + case DIALOG_NOICON: + break; + case DIALOG_ICON_ERROR: + oledDrawBitmap(0, 0, &bmp_icon_error); + left = 20; + break; + case DIALOG_ICON_INFO: + oledDrawBitmap(0, 0, &bmp_icon_info); + left = 20; + break; + case DIALOG_ICON_QUESTION: + oledDrawBitmap(0, 0, &bmp_icon_question); + left = 20; + break; + case DIALOG_ICON_WARNING: + oledDrawBitmap(0, 0, &bmp_icon_warning); + left = 20; + break; + case DIALOG_ICON_OK: + oledDrawBitmap(0, 0, &bmp_icon_ok); + left = 20; + break; + } + if (line1) oledDrawString(left, 0 * 9, line1); + if (line2) oledDrawString(left, 1 * 9, line2); + if (line3) oledDrawString(left, 2 * 9, line3); + if (line4) oledDrawString(left, 3 * 9, line4); + if (desc) { + oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc); + if (btnYes || btnNo) { + oledHLine(OLED_HEIGHT - 21); + } + } else { + if (line5) oledDrawString(left, 4 * 9, line5); + if (line6) oledDrawString(left, 5 * 9, line6); + if (btnYes || btnNo) { + oledHLine(OLED_HEIGHT - 13); + } + } + if (btnNo) { + oledDrawString(1, OLED_HEIGHT - 8, "{"); + oledDrawString(fontCharWidth('{') + 3, OLED_HEIGHT - 8, btnNo); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('{') + fontStringWidth(btnNo) + 2, OLED_HEIGHT - 1); + } + if (btnYes) { + oledDrawString(OLED_WIDTH - fontCharWidth('}') - 1, OLED_HEIGHT - 8, "}"); + oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + } + oledRefresh(); +} + +void layoutProgress(const char *desc, int permil, int gearstep) +{ + const BITMAP *bmp_gears[4] = { &bmp_gears0, &bmp_gears1, &bmp_gears2, &bmp_gears3 }; + oledClear(); + oledDrawBitmap(40, 0, bmp_gears[gearstep % 4]); + // progressbar + oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); + permil = permil * (OLED_WIDTH - 4) / 1000; + if (permil < 0) { + permil = 0; + } + if (permil > OLED_WIDTH - 4) { + permil = OLED_WIDTH - 4; + } + oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); + + // text + oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); + if (desc) { + oledDrawStringCenter(OLED_HEIGHT - 16, desc); + } + oledRefresh(); +} diff --git a/layout.h b/layout.h new file mode 100644 index 0000000000..71e8191890 --- /dev/null +++ b/layout.h @@ -0,0 +1,37 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __LAYOUT_H__ +#define __LAYOUT_H__ + +#include + +typedef enum { + DIALOG_NOICON = 0, + DIALOG_ICON_ERROR, + DIALOG_ICON_INFO, + DIALOG_ICON_QUESTION, + DIALOG_ICON_WARNING, + DIALOG_ICON_OK, +} LayoutDialogIcon; + +void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutProgress(const char *desc, int permil, int gearstep); + +#endif diff --git a/memory.c b/memory.c new file mode 100644 index 0000000000..c82f9cf36b --- /dev/null +++ b/memory.c @@ -0,0 +1,45 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include "memory.h" +#include "sha2.h" + +#define OPTION_BYTES_1 ((uint64_t *)0x1FFFC000) +#define OPTION_BYTES_2 ((uint64_t *)0x1FFFC008) + +void memory_protect(void) +{ + // set RDP level 2 WRP for sectors 0 and 1 + if ((((*OPTION_BYTES_1) & 0xFFFF) == 0xCCFF) && (((*OPTION_BYTES_2) & 0xFFFF) == 0xFFFC)) { + return; // already set up correctly - bail out + } + flash_unlock_option_bytes(); + // WRP + RDP + flash_program_option_bytes( 0xFFFC0000 + 0xCCFF); + flash_lock_option_bytes(); +} + +int memory_bootloader_hash(uint8_t *hash) +{ + sha256_Raw((const uint8_t *)FLASH_BOOT_START, FLASH_BOOT_LEN, hash); + sha256_Raw(hash, 32, hash); + return 32; +} diff --git a/memory.h b/memory.h new file mode 100644 index 0000000000..3d9c8914a2 --- /dev/null +++ b/memory.h @@ -0,0 +1,104 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +/* + + flash memory layout: + + name | range | size | function +-----------+-------------------------+---------+------------------ + Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader code + Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader code +-----------+-------------------------+---------+------------------ + Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | metadata area + Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | metadata area +-----------+-------------------------+---------+------------------ + Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | application code + Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | application code + Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | application code + Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | application code +===========+=========================+============================ + Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | N/A + Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | N/A + Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | N/A + Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | N/A + + metadata area: + + offset | type/length | description +--------+-------------+------------------------------- + 0x0000 | 4 bytes | magic = 'TRZR' + 0x0004 | uint32 | length of the code (codelen) + 0x0008 | uint8 | signature index #1 + 0x0009 | uint8 | signature index #2 + 0x000A | uint8 | signature index #3 + 0x000B | uint8 | flags + 0x000C | 52 bytes | reserved + 0x0040 | 64 bytes | signature #1 + 0x0080 | 64 bytes | signature #2 + 0x00C0 | 64 bytes | signature #3 + 0x0100 | 32K-256 B | persistent storage + + flags & 0x01 -> restore storage after flashing (if signatures are ok) + + */ + +#define FLASH_ORIGIN (0x08000000) + +#define FLASH_TOTAL_SIZE (512 * 1024) + +#define FLASH_BOOT_START (FLASH_ORIGIN) +#define FLASH_BOOT_LEN (0x8000) + +#define FLASH_META_START (FLASH_BOOT_START + FLASH_BOOT_LEN) +#define FLASH_META_LEN (0x8000) + +#define FLASH_APP_START (FLASH_META_START + FLASH_META_LEN) + +#define FLASH_META_MAGIC (FLASH_META_START) +#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) +#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) +#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) +#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) +#define FLASH_META_FLAGS (FLASH_META_START + 0x000B) +#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) +#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) +#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) + +#define FLASH_META_DESC_LEN (0x100) + +#define FLASH_STORAGE_START (FLASH_META_START + FLASH_META_DESC_LEN) +#define FLASH_STORAGE_LEN (FLASH_APP_START - FLASH_STORAGE_START) + +#define FLASH_BOOT_SECTOR_FIRST 0 +#define FLASH_BOOT_SECTOR_LAST 1 + +#define FLASH_META_SECTOR_FIRST 2 +#define FLASH_META_SECTOR_LAST 3 + +#define FLASH_CODE_SECTOR_FIRST 4 +#define FLASH_CODE_SECTOR_LAST 7 + +void memory_protect(void); +int memory_bootloader_hash(uint8_t *hash); + +#endif diff --git a/memory.ld b/memory.ld new file mode 100644 index 0000000000..539837839b --- /dev/null +++ b/memory.ld @@ -0,0 +1,9 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +INCLUDE libopencm3_stm32f2.ld diff --git a/memory_app_0.0.0.ld b/memory_app_0.0.0.ld new file mode 100644 index 0000000000..ce3f3f7cc3 --- /dev/null +++ b/memory_app_0.0.0.ld @@ -0,0 +1,9 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ +/* program starts at 0x08010000 */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08004000, LENGTH = 512K - 16K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +INCLUDE libopencm3_stm32f2.ld diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld new file mode 100644 index 0000000000..a8188fb606 --- /dev/null +++ b/memory_app_1.0.0.ld @@ -0,0 +1,9 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ +/* program starts at 0x08010000 */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +INCLUDE libopencm3_stm32f2.ld diff --git a/oled.c b/oled.c new file mode 100644 index 0000000000..d207a1419e --- /dev/null +++ b/oled.c @@ -0,0 +1,331 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include + +#include "oled.h" +#include "util.h" + +#define OLED_SETCONTRAST 0x81 +#define OLED_DISPLAYALLON_RESUME 0xA4 +#define OLED_DISPLAYALLON 0xA5 +#define OLED_NORMALDISPLAY 0xA6 +#define OLED_INVERTDISPLAY 0xA7 +#define OLED_DISPLAYOFF 0xAE +#define OLED_DISPLAYON 0xAF +#define OLED_SETDISPLAYOFFSET 0xD3 +#define OLED_SETCOMPINS 0xDA +#define OLED_SETVCOMDETECT 0xDB +#define OLED_SETDISPLAYCLOCKDIV 0xD5 +#define OLED_SETPRECHARGE 0xD9 +#define OLED_SETMULTIPLEX 0xA8 +#define OLED_SETLOWCOLUMN 0x00 +#define OLED_SETHIGHCOLUMN 0x10 +#define OLED_SETSTARTLINE 0x40 +#define OLED_MEMORYMODE 0x20 +#define OLED_COMSCANINC 0xC0 +#define OLED_COMSCANDEC 0xC8 +#define OLED_SEGREMAP 0xA0 +#define OLED_CHARGEPUMP 0x8D + +#define SPI_BASE SPI1 +#define OLED_DC_PORT GPIOB +#define OLED_DC_PIN GPIO0 // PB0 | Data/Command +#define OLED_CS_PORT GPIOA +#define OLED_CS_PIN GPIO4 // PA4 | SPI Select +#define OLED_RST_PORT GPIOB +#define OLED_RST_PIN GPIO1 // PB1 | Reset display + +#define OLED_BUFSET(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] |= (1 << (7 - (Y)%8)) +#define OLED_BUFCLR(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] &= ~(1 << (7 - (Y)%8)) +#define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8)) + +static uint8_t _oledbuffer[OLED_BUFSIZE]; +static char is_debug_mode = 0; + +inline void SPISend(uint32_t base, uint8_t *data, int len) +{ + int i; + delay(400); + for (i = 0; i < len; i++) { + spi_send(base, data[i]); + } + delay(800); +} + +void oledInit() +{ + static uint8_t s[25] = { + OLED_DISPLAYOFF, + OLED_SETDISPLAYCLOCKDIV, + 0x80, + OLED_SETMULTIPLEX, + 0x3F, // 128x64 + OLED_SETDISPLAYOFFSET, + 0x00, + OLED_SETSTARTLINE | 0x00, + OLED_CHARGEPUMP, + 0x14, + OLED_MEMORYMODE, + 0x00, + OLED_SEGREMAP | 0x01, + OLED_COMSCANDEC, + OLED_SETCOMPINS, + 0x12, // 128x64 + OLED_SETCONTRAST, + 0xCF, + OLED_SETPRECHARGE, + 0xF1, + OLED_SETVCOMDETECT, + 0x40, + OLED_DISPLAYALLON_RESUME, + OLED_NORMALDISPLAY, + OLED_DISPLAYON + }; + + gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + + // Reset the LCD + gpio_set(OLED_RST_PORT, OLED_RST_PIN); + delay(40); + gpio_clear(OLED_RST_PORT, OLED_RST_PIN); + delay(400); + gpio_set(OLED_RST_PORT, OLED_RST_PIN); + + // init + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, s, 25); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + + oledClear(); + oledRefresh(); +} + +void oledClear() +{ + memset(_oledbuffer, 0, sizeof(_oledbuffer)); +} + +void oledRefresh() +{ + static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; + + // draw triangle in upper right corner + if (is_debug_mode) { + OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); + OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); + OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); + OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3); + OLED_BUFTGL(OLED_WIDTH - 1, 4); + } + + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, s, 3); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + + gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer)); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD + + // return it back + if (is_debug_mode) { + OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); + OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); + OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); + OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3); + OLED_BUFTGL(OLED_WIDTH - 1, 4); + } +} + +const uint8_t *oledGetBuffer() +{ + return _oledbuffer; +} + +void oledSetDebug(char set) +{ + is_debug_mode = set; + oledRefresh(); +} + +void oledSetBuffer(uint8_t *buf) +{ + memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); +} + +void oledDrawPixel(int x, int y) +{ + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; + OLED_BUFSET(x,y); +} + +void oledClearPixel(int x, int y) +{ + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; + OLED_BUFCLR(x,y); +} + +void oledDrawChar(int x, int y, char c) +{ + uint8_t width, *column; + + if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; + + if ((c < FONT_START) || (c > FONT_END)) { + c = '_'; + } + + width = font_data[(int)(c - FONT_START)][0]; + column = (uint8_t *)(font_data[(int)(c - FONT_START)] + 1); + + int xoffset, yoffset; + for (xoffset = 0; xoffset < width; xoffset++) { + for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { + if (column[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { + oledDrawPixel(x + xoffset, y + yoffset); + } + } + } +} + +void oledDrawString(int x, int y, const char* text) +{ + if (!text) return; + const char *c; + int l = 0; + for (c = text; *c; c++) { + oledDrawChar(x + l, y, *c); + l += fontCharWidth(*c) + 1; + } +} + +void oledDrawStringCenter(int y, const char* text) +{ + int x = ( OLED_WIDTH - fontStringWidth(text) ) / 2; + oledDrawString(x, y, text); +} + +void oledDrawStringRight(int x, int y, const char* text) +{ + x -= fontStringWidth(text); + oledDrawString(x, y, text); +} + +#define min(X,Y) ((X) < (Y) ? (X) : (Y)) + +void oledDrawBitmap(int x, int y, const BITMAP *bmp) +{ + int i, j; + for (i = 0; i < min(bmp->width, OLED_WIDTH - x); i++) { + for (j = 0; j < min(bmp->height, OLED_HEIGHT - y); j++) { + if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { + OLED_BUFSET(x + i, y + j); + } else { + OLED_BUFCLR(x + i, y + j); + } + } + } +} + +void oledInvert(int x1, int y1, int x2, int y2) +{ + if ((x1 >= OLED_WIDTH) || (y1 >= OLED_HEIGHT) || (x2 >= OLED_WIDTH) || (y2 >= OLED_HEIGHT)) return; + int x, y; + for (x = x1; x <= x2; x++) { + for (y = y1; y <= y2; y++) { + OLED_BUFTGL(x,y); + } + } +} + +void oledBox(int x1, int y1, int x2, int y2, char val) +{ + int x, y; + for (x = x1; x <= x2; x++) { + for (y = y1; y <= y2; y++) { + val ? oledDrawPixel(x, y) : oledClearPixel(x, y); + } + } +} + +void oledHLine(int y) { + int x; + for (x = 0; x < OLED_WIDTH; x++) { + oledDrawPixel(x, y); + } +} + +void oledFrame(int x1, int y1, int x2, int y2) +{ + int x, y; + for (x = x1; x <= x2; x++) { + oledDrawPixel(x, y1); + oledDrawPixel(x, y2); + } + for (y = y1 + 1; y < y2; y++) { + oledDrawPixel(x1, y); + oledDrawPixel(x2, y); + } +} + +void oledSwipeLeft(void) +{ + int i, j, k; + for (i = 0; i < OLED_WIDTH / 4; i++) { + for (j = 0; j < OLED_HEIGHT / 8; j++) { + for (k = OLED_WIDTH / 4 - 1; k > 0; k--) { + _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 1 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 2 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 3 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 4 + j * OLED_WIDTH]; + } + _oledbuffer[j * OLED_WIDTH] = 0; + _oledbuffer[j * OLED_WIDTH + 1] = 0; + _oledbuffer[j * OLED_WIDTH + 2] = 0; + _oledbuffer[j * OLED_WIDTH + 3] = 0; + } + oledRefresh(); + } +} + +void oledSwipeRight(void) +{ + int i, j, k; + for (i = 0; i < OLED_WIDTH / 4; i++) { + for (j = 0; j < OLED_HEIGHT / 8; j++) { + for (k = 0; k < OLED_WIDTH / 4 - 1; k++) { + _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 5 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 7 + j * OLED_WIDTH]; + } + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0; + } + oledRefresh(); + } +} diff --git a/oled.h b/oled.h new file mode 100644 index 0000000000..f23728cfd6 --- /dev/null +++ b/oled.h @@ -0,0 +1,57 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __OLED_H__ +#define __OLED_H__ + +#include + +#include "bitmaps.h" +#include "fonts.h" + +#define OLED_WIDTH 128 +#define OLED_HEIGHT 64 +#define OLED_BUFSIZE (OLED_WIDTH * OLED_HEIGHT / 8) + +#ifdef APPVER +#define oledInit() do{}while(0) +#else +void oledInit(void); +#endif +void oledClear(void); +void oledRefresh(void); + +void oledSetDebug(char set); +void oledSetBuffer(uint8_t *buf); +const uint8_t *oledGetBuffer(void); +void oledDrawPixel(int x, int y); +void oledClearPixel(int x, int y); +void oledDrawChar(int x, int y, char c); +void oledDrawString(int x, int y, const char* text); +void oledDrawStringCenter(int y, const char* text); +void oledDrawStringRight(int x, int y, const char* text); +void oledDrawBitmap(int x, int y, const BITMAP *bmp); +void oledInvert(int x1, int y1, int x2, int y2); +void oledBox(int x1, int y1, int x2, int y2, char val); +void oledHLine(int y); +void oledFrame(int x1, int y1, int x2, int y2); +void oledSwipeLeft(void); +void oledSwipeRight(void); + +#endif diff --git a/rng.c b/rng.c new file mode 100644 index 0000000000..7bf275ac39 --- /dev/null +++ b/rng.c @@ -0,0 +1,45 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "rng.h" + +uint32_t random32(void) +{ + static uint32_t last = 0, new = 0; + while (new == last) { + if (((RNG_SR & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) && ((RNG_SR & RNG_SR_DRDY) > 0)) { + new = RNG_DR; + } + } + last = new; + return new; +} + +void random_buffer(uint8_t *buf, uint32_t len) +{ + uint32_t i, r = 0; + for (i = 0; i < len; i++) { + if (i % 4 == 0) { + r = random32(); + } + buf[i] = (r >> ((i % 4) * 8)) & 0xFF; + } +} diff --git a/rng.h b/rng.h new file mode 100644 index 0000000000..c8e02e3987 --- /dev/null +++ b/rng.h @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __RNG_H__ +#define __RNG_H__ + +#include + +uint32_t random32(void); +void random_buffer(uint8_t *buf, uint32_t len); + +#endif diff --git a/serialno.c b/serialno.c new file mode 100644 index 0000000000..024d6ed49a --- /dev/null +++ b/serialno.c @@ -0,0 +1,46 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +#include "serialno.h" +#include "util.h" +#include "sha2.h" + +#if defined(STM32F4) || defined(STM32F2) +#define UNIQUE_SERIAL_ADDR 0x1FFF7A10 +#elif defined(STM32F3) +#define UNIQUE_SERIAL_ADDR 0x1FFFF7AC +#elif defined(STM32L1) +#define UNIQUE_SERIAL_ADDR 0x1FF80050 +#else // STM32F1 +#define UNIQUE_SERIAL_ADDR 0x1FFFF7E8 +#endif + +void fill_serialno_fixed(char *s) +{ + uint8_t uuid[32]; + memcpy(uuid, (uint8_t *)UNIQUE_SERIAL_ADDR, 12); + memcpy(uuid + 12, (uint8_t *)UNIQUE_SERIAL_ADDR, 12); + memcpy(uuid + 24, (uint8_t *)UNIQUE_SERIAL_ADDR, 8); + sha256_Raw(uuid, 32, uuid); + sha256_Raw(uuid, 32, uuid); + data2hex(uuid, 12, s); +} diff --git a/serialno.h b/serialno.h new file mode 100644 index 0000000000..82fe483a25 --- /dev/null +++ b/serialno.h @@ -0,0 +1,26 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SERIALNO_H__ +#define __SERIALNO_H__ + +// buffer has to be (at least) 25 chars long +void fill_serialno_fixed(char *s); + +#endif diff --git a/setup.c b/setup.c new file mode 100644 index 0000000000..310d86bf09 --- /dev/null +++ b/setup.c @@ -0,0 +1,66 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include + +void setup(void) +{ + // setup clock + clock_scale_t clock = hse_8mhz_3v3[CLOCK_3V3_120MHZ]; + rcc_clock_setup_hse_3v3(&clock); + + // enable GPIO clock - A (oled), B(oled), C (buttons) + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN | RCC_AHB1ENR_IOPBEN | RCC_AHB1ENR_IOPCEN); + + // enable SPI clock + rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_SPI1EN); + + // enable OTG FS clock + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + + // enable RNG + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_RNGEN); + RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; + + // set GPIO for buttons + gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5); + + // set GPIO for OLED display + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); + gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1); + + // enable SPI 1 for OLED display + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); + gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); + +// spi_disable_crc(SPI1); + spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); + spi_enable_ss_output(SPI1); +// spi_enable_software_slave_management(SPI1); +// spi_set_nss_high(SPI1); +// spi_clear_mode_fault(SPI1); + spi_enable(SPI1); + + // enable OTG_FS + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); +} diff --git a/setup.h b/setup.h new file mode 100644 index 0000000000..a54c81b95d --- /dev/null +++ b/setup.h @@ -0,0 +1,29 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SETUP_H__ +#define __SETUP_H__ + +#ifdef APPVER +#define setup() do{}while(0) +#else +void setup(void); +#endif + +#endif diff --git a/trezor-common b/trezor-common new file mode 160000 index 0000000000..e4f9dcd7c9 --- /dev/null +++ b/trezor-common @@ -0,0 +1 @@ +Subproject commit e4f9dcd7c966c136bd33ccc58321db8d8b83d09b diff --git a/trezor-crypto b/trezor-crypto new file mode 160000 index 0000000000..94d4a3733e --- /dev/null +++ b/trezor-crypto @@ -0,0 +1 @@ +Subproject commit 94d4a3733ed10c6db9225a23edcdfee6c7fcb2b2 diff --git a/util.c b/util.c new file mode 100644 index 0000000000..7f40f7de44 --- /dev/null +++ b/util.c @@ -0,0 +1,81 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include "util.h" + +inline void delay(uint32_t wait) +{ + while (--wait > 0) __asm__("nop"); +} + +static const char *hexdigits = "0123456789ABCDEF"; + +void uint32hex(uint32_t num, char *str) +{ + uint32_t i; + for (i = 0; i < 8; i++) { + str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; + } +} + +// converts data to hexa +void data2hex(const void *data, uint32_t len, char *str) +{ + uint32_t i; + const uint8_t *cdata = (uint8_t *)data; + for (i = 0; i < len; i++) { + str[i * 2 ] = hexdigits[(cdata[i] >> 4) & 0xF]; + str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; + } + str[len * 2] = 0; +} + +uint32_t readprotobufint(uint8_t **ptr) +{ + uint32_t result = (**ptr & 0x7F); + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128 * 128; + } + } + } + } + (*ptr)++; + return result; +} + +void __attribute__((noreturn)) system_halt(void) +{ + for (;;) {} // loop forever +} + +void __attribute__((noreturn)) system_reset(void) +{ + scb_reset_system(); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000000..d7bb5b4244 --- /dev/null +++ b/util.h @@ -0,0 +1,41 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __UTIL_H_ +#define __UTIL_H_ + +#include + +inline void delay(uint32_t wait); + +// converts uint32 to hexa (8 digits) +void uint32hex(uint32_t num, char *str); + +// converts data to hexa +void data2hex(const void *data, uint32_t len, char *str); + +// read protobuf integer and advance pointer +uint32_t readprotobufint(uint8_t **ptr); + +// halt execution (or do an endless loop) +void __attribute__((noreturn)) system_halt(void); +// reset system +void __attribute__((noreturn)) system_reset(void); + +#endif From d7169a342cdb87b014dc9e1cb87d3ea98895225b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 20 May 2014 15:36:35 +0200 Subject: [PATCH 0002/1154] fix initialize handling in interactive mode --- firmware/fsm.c | 5 +++++ firmware/protect.c | 8 +++++--- firmware/protect.h | 2 ++ trezor-crypto | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index d14e86d19b..1976a8645e 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -57,6 +57,11 @@ void fsm_sendSuccess(const char *text) void fsm_sendFailure(FailureType code, const char *text) { + if (protectAbortedByInitialize) { + fsm_msgInitialize((Initialize *)0); + protectAbortedByInitialize = false; + return; + } RESP_INIT(Failure); resp->has_code = true; resp->code = code; diff --git a/firmware/protect.c b/firmware/protect.c index 57684a2ed7..a473fd226e 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -29,6 +29,8 @@ #include "util.h" #include "debug.h" +bool protectAbortedByInitialize = false; + bool protectButton(ButtonRequestType type, bool confirm_only) { ButtonRequest resp; @@ -66,7 +68,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { if (msg_tiny_id == MessageType_MessageType_Initialize) { - fsm_msgInitialize((Initialize *)msg_tiny); + protectAbortedByInitialize = true; } msg_tiny_id = 0xFFFF; result = false; @@ -115,7 +117,7 @@ const char *requestPin(PinMatrixRequestType type, const char *text) if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { pinmatrix_done(0); if (msg_tiny_id == MessageType_MessageType_Initialize) { - fsm_msgInitialize((Initialize *)msg_tiny); + protectAbortedByInitialize = true; } msg_tiny_id = 0xFFFF; usbTiny(0); @@ -209,7 +211,7 @@ bool protectPassphrase(void) } if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { if (msg_tiny_id == MessageType_MessageType_Initialize) { - fsm_msgInitialize((Initialize *)msg_tiny); + protectAbortedByInitialize = true; } msg_tiny_id = 0xFFFF; result = false; diff --git a/firmware/protect.h b/firmware/protect.h index 07fdb2532c..4a7a361644 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -28,4 +28,6 @@ bool protectPin(bool use_cached); bool protectChangePin(void); bool protectPassphrase(void); +extern bool protectAbortedByInitialize; + #endif diff --git a/trezor-crypto b/trezor-crypto index 94d4a3733e..44116b8a74 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 94d4a3733ed10c6db9225a23edcdfee6c7fcb2b2 +Subproject commit 44116b8a7405299be5de8353e9e624538b4dac92 From 555b56181e75b891438520e0a22de28bc89d82ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 25 May 2014 18:32:12 +0200 Subject: [PATCH 0003/1154] use button confirmation for loaddevice --- firmware/fsm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 1976a8645e..9cc26c3141 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -281,6 +281,13 @@ void fsm_msgLoadDevice(LoadDevice *msg) return; } + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); + layoutHome(); + return; + } + storage_loadDevice(msg); storage_commit(); fsm_sendSuccess("Device loaded"); From 2066f9e95c762dd72ebcc339c7f9fed55e51a225 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 May 2014 00:58:17 +0200 Subject: [PATCH 0004/1154] use imported flag to indicate that storage was imported from an external source --- firmware/fsm.c | 5 +++-- firmware/protob/messages.pb.c | 5 +++-- firmware/protob/messages.pb.h | 9 ++++++--- firmware/protob/storage.pb.c | 5 +++-- firmware/protob/storage.pb.h | 9 ++++++--- firmware/protob/types.pb.c | 2 +- firmware/protob/types.pb.h | 2 +- firmware/storage.c | 5 ++++- trezor-common | 2 +- 9 files changed, 28 insertions(+), 16 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9cc26c3141..97e87957e2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -109,7 +109,7 @@ void fsm_msgInitialize(Initialize *msg) resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = storage.has_pin; - resp->has_passphrase_protection = true; resp->passphrase_protection = storage.passphrase_protection; + resp->has_passphrase_protection = true; resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; #ifdef SCM_REVISION resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, sizeof(resp->revision)); resp->revision.size = SCM_REVISION_LEN; #endif @@ -124,7 +124,8 @@ void fsm_msgInitialize(Initialize *msg) } resp->coins_count = COINS_COUNT; memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType)); - resp->has_initialized = true; resp->initialized = storage_isInitialized(); + resp->has_initialized = true; resp->initialized = storage_isInitialized(); + resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 22578bca68..8a13557efc 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #include "messages.pb.h" @@ -18,7 +18,7 @@ const pb_field_t Initialize_fields[1] = { PB_LAST_FIELD }; -const pb_field_t Features_fields[15] = { +const pb_field_t Features_fields[16] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), @@ -33,6 +33,7 @@ const pb_field_t Features_fields[15] = { PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), + PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 225e8ab092..22713c799c 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #ifndef _PB_MESSAGES_PB_H_ #define _PB_MESSAGES_PB_H_ @@ -240,6 +240,8 @@ typedef struct _Features { Features_revision_t revision; bool has_bootloader_hash; Features_bootloader_hash_t bootloader_hash; + bool has_imported; + bool imported; } Features; typedef struct { @@ -485,6 +487,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Features_initialized_tag 12 #define Features_revision_tag 13 #define Features_bootloader_hash_tag 14 +#define Features_imported_tag 15 #define FirmwareUpload_payload_tag 1 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 @@ -542,7 +545,7 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; -extern const pb_field_t Features_fields[15]; +extern const pb_field_t Features_fields[16]; extern const pb_field_t ApplySettings_fields[3]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; @@ -588,7 +591,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 -#define Features_size (222 + 4*CoinType_size) +#define Features_size (224 + 4*CoinType_size) #define ApplySettings_size 54 #define ChangePin_size 2 #define Ping_size 265 diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index ac40b48b32..7625797cf2 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -1,11 +1,11 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #include "storage.pb.h" -const pb_field_t Storage_fields[9] = { +const pb_field_t Storage_fields[10] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -14,6 +14,7 @@ const pb_field_t Storage_fields[9] = { PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), + PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 3e7824c97a..1814c27c47 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #ifndef _PB_STORAGE_PB_H_ #define _PB_STORAGE_PB_H_ @@ -28,6 +28,8 @@ typedef struct _Storage { char language[17]; bool has_label; char label[33]; + bool has_imported; + bool imported; } Storage; /* Default values for struct fields */ @@ -41,12 +43,13 @@ typedef struct _Storage { #define Storage_pin_tag 6 #define Storage_language_tag 7 #define Storage_label_tag 8 +#define Storage_imported_tag 9 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[9]; +extern const pb_field_t Storage_fields[10]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (330 + HDNodeType_size) +#define Storage_size (332 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 587f391dac..5b6ef600a0 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #include "types.pb.h" diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 9c2b7225c0..b910112621 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.7 */ +/* Generated by nanopb-0.2.8 */ #ifndef _PB_TYPES_PB_H_ #define _PB_TYPES_PB_H_ diff --git a/firmware/storage.c b/firmware/storage.c index 3351d1482b..5a993f5aa9 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -141,6 +141,9 @@ void storage_loadDevice(LoadDevice *msg) { storage_reset(); + storage.has_imported = true; + storage.imported = true; + if (msg->has_pin > 0) { storage_setPin(msg->pin); } @@ -212,7 +215,7 @@ bool storage_getRootNode(HDNode *node) return false; } hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode); - if (storage.has_passphrase_protection > 0) { + if (storage.has_passphrase_protection && storage.passphrase_protection) { // decrypt hd node aes_ctx ctx; aes_enc_key((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), &ctx); diff --git a/trezor-common b/trezor-common index e4f9dcd7c9..1865a0428d 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit e4f9dcd7c966c136bd33ccc58321db8d8b83d09b +Subproject commit 1865a0428d1803416174f31a1d6b53b6632384a9 From efe6e552da00403f22b02cb821a5b2da179afd51 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 28 May 2014 14:56:31 +0200 Subject: [PATCH 0005/1154] rename cmd tool in makefile --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 0efd840479..ac43055be7 100644 --- a/Makefile.include +++ b/Makefile.include @@ -80,7 +80,7 @@ flash2: $(NAME).hex -c "shutdown" upload: - ../../python-trezor/cmd.py firmware_update -f $(NAME).bin + ../../python-trezor/cmdtr.py firmware_update -f $(NAME).bin sign: $(NAME).bin ../bootloader/firmware_sign.py -f $(NAME).bin From c8faf4aeaafc62e25f50ec4c8cb9112bb6abab1a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 2 Jun 2014 20:40:20 +0200 Subject: [PATCH 0006/1154] show verified message & wait for button --- firmware/fsm.c | 5 ++--- firmware/layout2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ firmware/layout2.h | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 97e87957e2..ca94898d6e 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -591,9 +591,8 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) { const char *address = msg->has_address ? msg->address : 0; if (msg->signature.size == 65 && transactionMessageVerify(msg->message.bytes, msg->message.size, msg->signature.bytes, address)) { - // TODO: show verified message & wait for button - // layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", NULL, "Verified message", NULL, NULL, NULL, NULL, NULL); - // protectButton(ButtonRequestType_ButtonRequest_Other, true); + layoutVerifyMessage(msg->message.bytes, msg->message.size); + protectButton(ButtonRequestType_ButtonRequest_Other, true); fsm_sendSuccess("Message verified"); } else { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); diff --git a/firmware/layout2.c b/firmware/layout2.c index 49adcce4c5..e4813ed750 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -189,3 +189,45 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) ascii ? "Sign text message?" : "Sign binary message?", str[0], str[1], str[2], str[3], NULL); } + +void layoutVerifyMessage(const uint8_t *msg, uint32_t len) +{ + bool ascii = true; + uint32_t i; + for (i = 0; i < len; i++) { + if (msg[i] < 0x20 || msg[i] >= 0x80) { + ascii = false; + break; + } + } + + char str[4][17]; + memset(str, 0, sizeof(str)); + if (ascii) { + strlcpy(str[0], (char *)msg, 17); + if (len > 16) { + strlcpy(str[1], (char *)msg + 16, 17); + } + if (len > 32) { + strlcpy(str[2], (char *)msg + 32, 17); + } + if (len > 48) { + strlcpy(str[3], (char *)msg + 48, 17); + } + } else { + data2hex(msg, len > 8 ? 8 : len, str[0]); + if (len > 8) { + data2hex(msg + 8, len > 16 ? 8 : len - 8, str[1]); + } + if (len > 16) { + data2hex(msg + 16, len > 24 ? 8 : len - 16, str[2]); + } + if (len > 24) { + data2hex(msg + 24, len > 32 ? 8 : len - 24, str[3]); + } + } + + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", NULL, + ascii ? "Message contents:" : "Bin message contents:", + str[0], str[1], str[2], str[3], NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index f406ae4158..290b97d481 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -31,5 +31,6 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutSignMessage(const uint8_t *msg, uint32_t len); +void layoutVerifyMessage(const uint8_t *msg, uint32_t len); #endif From 2b68813a4ccb0bd3b6bbc93c0cba6a8b86bc92df Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Jun 2014 17:59:58 +0200 Subject: [PATCH 0007/1154] adjust script_sig size for use with multisig adjust delays used when wrong pin is entered --- firmware/protect.c | 4 ++-- firmware/protob/types.options | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index a473fd226e..4c1596ee26 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -140,12 +140,12 @@ bool protectPin(bool use_cached) const char *pin; uint32_t wait = storage_getPinFails(); if (wait) { - if (wait > 4) { + if (wait > 2) { layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait ...", NULL, NULL, NULL); } wait = (wait < 32) ? (1u << wait) : 0xFFFFFFFF; while (--wait > 0) { - delay(1000000); + delay(10000000); } } pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 9c29909b98..d3297e9dce 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -7,7 +7,7 @@ CoinType.coin_shortcut max_size:9 TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 -TxInputType.script_sig max_size:256 +TxInputType.script_sig max_size:520 TxOutputType.address max_size:35 TxOutputType.address_n max_count:8 From 80ab3b40b4bbd8c6252f0b8f860317710671e485 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Jun 2014 19:42:41 +0200 Subject: [PATCH 0008/1154] show Preparing instead of Signing where trezor is not signing :) --- firmware/signing.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 5b5cf9d1c3..85ca2acb07 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -222,7 +222,7 @@ void signing_txack(TransactionType *tx) switch (signing_stage) { case STAGE_REQUEST_1_INPUT: - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); return; @@ -270,7 +270,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_3_INPUT: - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; if (!tx_hash_input(&tc, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); From 7cba60895d86a934ae3cfa8a6dfd1618accd355d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Jun 2014 23:45:01 +0200 Subject: [PATCH 0009/1154] update protobuf, disable SimpleSignTx --- firmware/fsm.c | 131 +------------------------------ firmware/fsm.h | 1 - firmware/messages.c | 6 -- firmware/messages.h | 4 +- firmware/protob/messages.options | 23 ++++-- firmware/protob/messages.pb.c | 21 ++++- firmware/protob/messages.pb.h | 60 ++++++++++++-- firmware/protob/types.options | 37 +++++---- firmware/protob/types.pb.c | 16 +++- firmware/protob/types.pb.h | 105 +++++++++++++++---------- firmware/transaction.c | 78 +----------------- firmware/transaction.h | 4 - trezor-common | 2 +- 13 files changed, 194 insertions(+), 294 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ca94898d6e..834bdbb3a8 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -343,131 +343,6 @@ void fsm_msgSignTx(SignTx *msg) signing_init(msg->inputs_count, msg->outputs_count, coin, node); } -void fsm_msgSimpleSignTx(SimpleSignTx *msg) -{ - RESP_INIT(TxRequest); - - if (msg->inputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); - layoutHome(); - return; - } - - if (msg->outputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); - layoutHome(); - return; - } - - if (!protectPin(true)) { - layoutHome(); - return; - } - - HDNode *node = fsm_getRootNode(); - if (!node) return; - const CoinType *coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return; - } - - uint32_t version = 1; - uint32_t lock_time = 0; - int tx_size = transactionSimpleSign(coin, node, msg->inputs, msg->inputs_count, msg->outputs, msg->outputs_count, version, lock_time, resp->serialized.serialized_tx.bytes); - if (tx_size < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); - layoutHome(); - return; - } - if (tx_size == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error signing transaction"); - layoutHome(); - return; - } - - size_t i, j; - - // determine change address - uint64_t change_spend = 0; - for (i = 0; i < msg->outputs_count; i++) { - if (msg->outputs[i].address_n_count > 0) { // address_n set -> change address - if (change_spend == 0) { // not set - change_spend = msg->outputs[i].amount; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); - layoutHome(); - return; - } - } - } - - // check origin transactions - uint8_t prev_hashes[ pb_arraysize(SimpleSignTx, transactions) ][32]; - for (i = 0; i < msg->transactions_count; i++) { - if (!transactionHash(&(msg->transactions[i]), prev_hashes[i])) { - memset(prev_hashes[i], 0, 32); - } - } - - // calculate spendings - uint64_t to_spend = 0; - bool found; - for (i = 0; i < msg->inputs_count; i++) { - found = false; - for (j = 0; j < msg->transactions_count; j++) { - if (memcmp(msg->inputs[i].prev_hash.bytes, prev_hashes[j], 32) == 0) { // found prev TX - if (msg->inputs[i].prev_index < msg->transactions[j].bin_outputs_count) { - to_spend += msg->transactions[j].bin_outputs[msg->inputs[i].prev_index].amount; - found = true; - break; - } - } - } - if (!found) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid prevhash"); - layoutHome(); - return; - } - } - - uint64_t spending = 0; - for (i = 0; i < msg->outputs_count; i++) { - spending += msg->outputs[i].amount; - } - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); - layoutHome(); - return; - } - - uint64_t fee = to_spend - spending; - if (fee > (((uint64_t)tx_size + 999) / 1000) * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, ((uint64_t)tx_size + 999) / 1000); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - layoutHome(); - return; - } - } - - // last confirmation - layoutConfirmTx(coin, to_spend - change_spend - fee, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - } else { - resp->has_request_type = true; - resp->request_type = RequestType_TXFINISHED; - resp->has_serialized = true; - resp->serialized.has_serialized_tx = true; - resp->serialized.serialized_tx.size = (uint32_t)tx_size; - msg_write(MessageType_MessageType_TxRequest, resp); - } - - layoutHome(); -} - void fsm_msgCancel(Cancel *msg) { (void)msg; @@ -636,9 +511,9 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) (void)msg; RESP_INIT(DebugLinkState); -// resp->has_layout = true; -// resp->layout.size = OLED_BUFSIZE; -// memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + resp->has_layout = true; + resp->layout.size = OLED_BUFSIZE; + memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); if (storage.has_pin) { resp->has_pin = true; diff --git a/firmware/fsm.h b/firmware/fsm.h index 8344f67b3b..030d7afdce 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -38,7 +38,6 @@ void fsm_msgGetPublicKey(GetPublicKey *msg); void fsm_msgLoadDevice(LoadDevice *msg); void fsm_msgResetDevice(ResetDevice *msg); void fsm_msgSignTx(SignTx *msg); -void fsm_msgSimpleSignTx(SimpleSignTx *msg); //void fsm_msgPinMatrixAck(PinMatrixAck *msg); void fsm_msgCancel(Cancel *msg); void fsm_msgTxAck(TxAck *msg); diff --git a/firmware/messages.c b/firmware/messages.c index 70ff6da835..403d1e8195 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -29,11 +29,6 @@ #include "pb_encode.h" #include "messages.pb.h" -// SimpleSignTx_size is the largest message we operate with -#if MSG_IN_SIZE < SimpleSignTx_size -#error "MSG_IN_SIZE is too small!" -#endif - struct MessagesMap_t { char type; // n = normal, d = debug char dir; // i = in, o = out @@ -55,7 +50,6 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *))fsm_msgLoadDevice}, {'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *))fsm_msgResetDevice}, {'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *))fsm_msgSignTx}, - {'n', 'i', MessageType_MessageType_SimpleSignTx, SimpleSignTx_fields, (void (*)(void *))fsm_msgSimpleSignTx}, // {'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *))fsm_msgPinMatrixAck}, {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, diff --git a/firmware/messages.h b/firmware/messages.h index 6f3b83e2f5..d2a5136040 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -24,7 +24,7 @@ #include #include "trezor.h" -#define MSG_IN_SIZE (24*1024) +#define MSG_IN_SIZE (9*1024) #define MSG_OUT_SIZE (9*1024) @@ -34,7 +34,7 @@ uint8_t *msg_out_data(void); #if DEBUG_LINK -#define MSG_DEBUG_OUT_SIZE (2*1024) +#define MSG_DEBUG_OUT_SIZE (4*1024) #define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) #define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 56c540b5e2..1d80312653 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -9,9 +9,10 @@ Features.bootloader_hash max_size:32 ApplySettings.language max_size:17 ApplySettings.label max_size:33 -Ping.message max_size:256 +Ping.message max_size:256 -Success.message max_size:256 +Success.message max_size:256 +Success.payload max_size:1024 Failure.message max_size:256 @@ -56,16 +57,26 @@ VerifyMessage.message max_size:256 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 +EncryptKeyValue.address_n max_count:8 +EncryptKeyValue.key max_size:256 +EncryptKeyValue.value max_size:1024 + +DecryptKeyValue.address_n max_count:8 +DecryptKeyValue.key max_size:256 +DecryptKeyValue.value max_size:1024 + EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 -SimpleSignTx.inputs max_count:4 -SimpleSignTx.outputs max_count:4 -SimpleSignTx.transactions max_count:4 +# not used in firmware +SimpleSignTx.inputs max_count:0 +SimpleSignTx.outputs max_count:0 +SimpleSignTx.transactions max_count:0 SimpleSignTx.coin_name max_size:17 -FirmwareUpload.payload max_size:0 # not used in firmware +# not used in firmware +FirmwareUpload.payload max_size:0 DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 8a13557efc..077cd7ea38 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -56,8 +56,9 @@ const pb_field_t Ping_fields[5] = { PB_LAST_FIELD }; -const pb_field_t Success_fields[2] = { +const pb_field_t Success_fields[3] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, Success, payload, message, 0), PB_LAST_FIELD }; @@ -204,6 +205,20 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; +const pb_field_t EncryptKeyValue_fields[4] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EncryptKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, EncryptKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptKeyValue, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptKeyValue_fields[4] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptKeyValue, value, key, 0), + PB_LAST_FIELD +}; + const pb_field_t EstimateTxSize_fields[4] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), @@ -296,11 +311,11 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptKeyValue_DecryptKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for Entropy.entropy is too large. Define PB_FIELD_16BIT to fix this. +#error Field descriptor for Success.payload is too large. Define PB_FIELD_16BIT to fix this. #endif diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 22713c799c..c3518d1415 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -34,6 +34,8 @@ typedef enum _MessageType { MessageType_MessageType_Cancel = 20, MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, + MessageType_MessageType_EncryptKeyValue = 23, + MessageType_MessageType_DecryptKeyValue = 24, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, MessageType_MessageType_ButtonAck = 27, @@ -168,6 +170,34 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DecryptKeyValue_value_t; + +typedef struct _DecryptKeyValue { + size_t address_n_count; + uint32_t address_n[8]; + bool has_key; + char key[256]; + bool has_value; + DecryptKeyValue_value_t value; +} DecryptKeyValue; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EncryptKeyValue_value_t; + +typedef struct _EncryptKeyValue { + size_t address_n_count; + uint32_t address_n[8]; + bool has_key; + char key[256]; + bool has_value; + EncryptKeyValue_value_t value; +} EncryptKeyValue; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -378,18 +408,25 @@ typedef struct _SignTx { typedef struct _SimpleSignTx { size_t inputs_count; - TxInputType inputs[4]; + TxInputType inputs[0]; size_t outputs_count; - TxOutputType outputs[4]; + TxOutputType outputs[0]; size_t transactions_count; - TransactionType transactions[4]; + TransactionType transactions[0]; bool has_coin_name; char coin_name[17]; } SimpleSignTx; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} Success_payload_t; + typedef struct _Success { bool has_message; char message[256]; + bool has_payload; + Success_payload_t payload; } Success; typedef struct _TxAck { @@ -466,6 +503,12 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkState_reset_entropy_tag 8 #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 +#define DecryptKeyValue_address_n_tag 1 +#define DecryptKeyValue_key_tag 2 +#define DecryptKeyValue_value_tag 3 +#define EncryptKeyValue_address_n_tag 1 +#define EncryptKeyValue_key_tag 2 +#define EncryptKeyValue_value_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -533,6 +576,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_transactions_tag 3 #define SimpleSignTx_coin_name_tag 4 #define Success_message_tag 1 +#define Success_payload_tag 2 #define TxAck_tx_tag 1 #define TxRequest_request_type_tag 1 #define TxRequest_details_tag 2 @@ -549,7 +593,7 @@ extern const pb_field_t Features_fields[16]; extern const pb_field_t ApplySettings_fields[3]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; -extern const pb_field_t Success_fields[2]; +extern const pb_field_t Success_fields[3]; extern const pb_field_t Failure_fields[3]; extern const pb_field_t ButtonRequest_fields[3]; extern const pb_field_t ButtonAck_fields[1]; @@ -575,6 +619,8 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; +extern const pb_field_t EncryptKeyValue_fields[4]; +extern const pb_field_t DecryptKeyValue_fields[4]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[4]; @@ -595,7 +641,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define ApplySettings_size 54 #define ChangePin_size 2 #define Ping_size 265 -#define Success_size 259 +#define Success_size 1286 #define Failure_size 265 #define ButtonRequest_size 265 #define ButtonAck_size 0 @@ -621,10 +667,12 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 326 #define VerifyMessage_size 363 #define MessageSignature_size 104 +#define EncryptKeyValue_size 1334 +#define DecryptKeyValue_size 1334 #define EstimateTxSize_size 31 #define TxSize_size 6 #define SignTx_size 31 -#define SimpleSignTx_size (91 + 4*TxInputType_size + 4*TxOutputType_size + 4*TransactionType_size) +#define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) #define FirmwareErase_size 0 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index d3297e9dce..477ebb3f66 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -1,26 +1,29 @@ -HDNodeType.chain_code max_size:32 -HDNodeType.private_key max_size:32 -HDNodeType.public_key max_size:33 +HDNodeType.chain_code max_size:32 +HDNodeType.private_key max_size:32 +HDNodeType.public_key max_size:33 -CoinType.coin_name max_size:17 -CoinType.coin_shortcut max_size:9 +CoinType.coin_name max_size:17 +CoinType.coin_shortcut max_size:9 -TxInputType.address_n max_count:8 -TxInputType.prev_hash max_size:32 -TxInputType.script_sig max_size:520 +TxInputType.address_n max_count:8 +TxInputType.prev_hash max_size:32 +TxInputType.script_sig max_size:520 -TxOutputType.address max_size:35 -TxOutputType.address_n max_count:8 -TxOutputType.script_args max_count:3 -TxOutputType.script_args max_size:16 +TxOutputType.address max_size:35 +TxOutputType.address_n max_count:8 -TxOutputBinType.script_pubkey max_size:256 +TxOutputBinType.script_pubkey max_size:256 -TransactionType.inputs max_count:8 -TransactionType.bin_outputs max_count:4 -TransactionType.outputs max_count:4 +TransactionType.inputs max_count:1 +TransactionType.bin_outputs max_count:1 +TransactionType.outputs max_count:1 -TxRequestDetailsType.tx_hash max_size:32 +TxRequestDetailsType.tx_hash max_size:32 TxRequestSerializedType.signature max_size:80 TxRequestSerializedType.serialized_tx max_size:1024 + +MultisigRedeemScriptType.pubkeys max_count:5 +MultisigRedeemScriptType.pubkeys max_size:33 +MultisigRedeemScriptType.signatures max_count:4 +MultisigRedeemScriptType.signatures max_size:80 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 5b6ef600a0..1d9e61f172 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -4,6 +4,7 @@ #include "types.pb.h" const uint32_t TxInputType_sequence_default = 4294967295u; +const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const pb_field_t HDNodeType_fields[7] = { @@ -24,21 +25,28 @@ const pb_field_t CoinType_fields[5] = { PB_LAST_FIELD }; -const pb_field_t TxInputType_fields[6] = { +const pb_field_t MultisigRedeemScriptType_fields[3] = { + PB_FIELD2( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), + PB_FIELD2( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_LAST_FIELD +}; + +const pb_field_t TxInputType_fields[8] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), + PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; -const pb_field_t TxOutputType_fields[6] = { +const pb_field_t TxOutputType_fields[5] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), - PB_FIELD2( 5, BYTES , REPEATED, STATIC , OTHER, TxOutputType, script_args, script_type, 0), PB_LAST_FIELD }; @@ -134,7 +142,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +STATIC_ASSERT((pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index b910112621..fb674eadff 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -24,10 +24,15 @@ typedef enum _FailureType { FailureType_Failure_FirmwareError = 99 } FailureType; -typedef enum _ScriptType { - ScriptType_PAYTOADDRESS = 0, - ScriptType_PAYTOSCRIPTHASH = 1 -} ScriptType; +typedef enum _OutputScriptType { + OutputScriptType_PAYTOADDRESS = 0, + OutputScriptType_PAYTOSCRIPTHASH = 1 +} OutputScriptType; + +typedef enum _InputScriptType { + InputScriptType_SPENDADDRESS = 0, + InputScriptType_SPENDMULTISIG = 1 +} InputScriptType; typedef enum _RequestType { RequestType_TXINPUT = 0, @@ -93,24 +98,20 @@ typedef struct _HDNodeType { typedef struct { size_t size; - uint8_t bytes[32]; -} TxInputType_prev_hash_t; + uint8_t bytes[33]; +} MultisigRedeemScriptType_pubkeys_t; typedef struct { size_t size; - uint8_t bytes[256]; -} TxInputType_script_sig_t; + uint8_t bytes[80]; +} MultisigRedeemScriptType_signatures_t; -typedef struct _TxInputType { - size_t address_n_count; - uint32_t address_n[8]; - TxInputType_prev_hash_t prev_hash; - uint32_t prev_index; - bool has_script_sig; - TxInputType_script_sig_t script_sig; - bool has_sequence; - uint32_t sequence; -} TxInputType; +typedef struct _MultisigRedeemScriptType { + size_t pubkeys_count; + MultisigRedeemScriptType_pubkeys_t pubkeys[5]; + size_t signatures_count; + MultisigRedeemScriptType_signatures_t signatures[4]; +} MultisigRedeemScriptType; typedef struct { size_t size; @@ -122,20 +123,13 @@ typedef struct _TxOutputBinType { TxOutputBinType_script_pubkey_t script_pubkey; } TxOutputBinType; -typedef struct { - size_t size; - uint8_t bytes[16]; -} TxOutputType_script_args_t; - typedef struct _TxOutputType { bool has_address; char address[35]; size_t address_n_count; uint32_t address_n[8]; uint64_t amount; - ScriptType script_type; - size_t script_args_count; - TxOutputType_script_args_t script_args[3]; + OutputScriptType script_type; } TxOutputType; typedef struct { @@ -169,17 +163,42 @@ typedef struct _TxRequestSerializedType { TxRequestSerializedType_serialized_tx_t serialized_tx; } TxRequestSerializedType; +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxInputType_prev_hash_t; + +typedef struct { + size_t size; + uint8_t bytes[520]; +} TxInputType_script_sig_t; + +typedef struct _TxInputType { + size_t address_n_count; + uint32_t address_n[8]; + TxInputType_prev_hash_t prev_hash; + uint32_t prev_index; + bool has_script_sig; + TxInputType_script_sig_t script_sig; + bool has_sequence; + uint32_t sequence; + bool has_script_type; + InputScriptType script_type; + bool has_multisig; + MultisigRedeemScriptType multisig; +} TxInputType; + typedef struct _TransactionType { bool has_version; uint32_t version; size_t inputs_count; - TxInputType inputs[8]; + TxInputType inputs[1]; size_t bin_outputs_count; - TxOutputBinType bin_outputs[4]; + TxOutputBinType bin_outputs[1]; bool has_lock_time; uint32_t lock_time; size_t outputs_count; - TxOutputType outputs[4]; + TxOutputType outputs[1]; bool has_inputs_cnt; uint32_t inputs_cnt; bool has_outputs_cnt; @@ -194,6 +213,7 @@ extern const pb_extension_type_t wire_debug_out; /* Default values for struct fields */ extern const uint32_t TxInputType_sequence_default; +extern const InputScriptType TxInputType_script_type_default; /* Field tags (for use in manual encoding/decoding) */ #define CoinType_coin_name_tag 1 @@ -206,23 +226,26 @@ extern const uint32_t TxInputType_sequence_default; #define HDNodeType_chain_code_tag 4 #define HDNodeType_private_key_tag 5 #define HDNodeType_public_key_tag 6 -#define TxInputType_address_n_tag 1 -#define TxInputType_prev_hash_tag 2 -#define TxInputType_prev_index_tag 3 -#define TxInputType_script_sig_tag 4 -#define TxInputType_sequence_tag 5 +#define MultisigRedeemScriptType_pubkeys_tag 1 +#define MultisigRedeemScriptType_signatures_tag 2 #define TxOutputBinType_amount_tag 1 #define TxOutputBinType_script_pubkey_tag 2 #define TxOutputType_address_tag 1 #define TxOutputType_address_n_tag 2 #define TxOutputType_amount_tag 3 #define TxOutputType_script_type_tag 4 -#define TxOutputType_script_args_tag 5 #define TxRequestDetailsType_request_index_tag 1 #define TxRequestDetailsType_tx_hash_tag 2 #define TxRequestSerializedType_signature_index_tag 1 #define TxRequestSerializedType_signature_tag 2 #define TxRequestSerializedType_serialized_tx_tag 3 +#define TxInputType_address_n_tag 1 +#define TxInputType_prev_hash_tag 2 +#define TxInputType_prev_index_tag 3 +#define TxInputType_script_sig_tag 4 +#define TxInputType_sequence_tag 5 +#define TxInputType_script_type_tag 6 +#define TxInputType_multisig_tag 7 #define TransactionType_version_tag 1 #define TransactionType_inputs_tag 2 #define TransactionType_bin_outputs_tag 3 @@ -238,8 +261,9 @@ extern const uint32_t TxInputType_sequence_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t CoinType_fields[5]; -extern const pb_field_t TxInputType_fields[6]; -extern const pb_field_t TxOutputType_fields[6]; +extern const pb_field_t MultisigRedeemScriptType_fields[3]; +extern const pb_field_t TxInputType_fields[8]; +extern const pb_field_t TxOutputType_fields[5]; extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TxRequestDetailsType_fields[3]; @@ -248,10 +272,11 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define CoinType_size 47 -#define TxInputType_size 353 -#define TxOutputType_size 156 +#define MultisigRedeemScriptType_size 503 +#define TxInputType_size 1129 +#define TxOutputType_size 102 #define TxOutputBinType_size 270 -#define TransactionType_size 4600 +#define TransactionType_size 1533 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 1115 diff --git a/firmware/transaction.c b/firmware/transaction.c index 38d1480779..c97b018ff6 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -98,7 +98,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; - if (in->script_type == ScriptType_PAYTOADDRESS) { + if (in->script_type == OutputScriptType_PAYTOADDRESS) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes @@ -113,7 +113,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 25; } - if (in->script_type == ScriptType_PAYTOSCRIPTHASH) { + if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes uint8_t decoded[21]; @@ -275,80 +275,6 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -bool transactionHash(TransactionType *tx, uint8_t *hash) -{ - TxStruct t; - uint32_t i; - tx_init(&t, tx->inputs_count, tx->bin_outputs_count, tx->version, tx->lock_time, false); - for (i = 0; i < tx->inputs_count; i++) { - if (!tx_hash_input(&t, &(tx->inputs[i]))) return false; - } - for (i = 0; i < tx->bin_outputs_count; i++) { - if (!tx_hash_output(&t, &(tx->bin_outputs[i]))) return false; - } - tx_hash_final(&t, hash, true); - return true; -} - -int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out) -{ - uint32_t idx, i, k, r = 0; - TxStruct ti, to; - uint8_t buf[512]; - TxInputType input; - TxOutputBinType output; - HDNode node; - uint8_t privkey[32], pubkey[33], hash[32], sig[64]; - - layoutProgressSwipe("Signing", 0, 0); - tx_init(&to, inputs_count, outputs_count, version, lock_time, false); - for (idx = 0; idx < inputs_count; idx++) { - // compute inner transaction - memcpy(&input, &(inputs[idx]), sizeof(TxInputType)); - tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); - memset(privkey, 0, 32); - memset(pubkey, 0, 33); - for (i = 0; i < inputs_count; i++) { - if (i == idx) { - memcpy(&node, root, sizeof(HDNode)); - for (k = 0; k < inputs[i].address_n_count; k++) { - hdnode_private_ckd(&node, inputs[i].address_n[k]); - } - ecdsa_get_pubkeyhash(node.public_key, hash); - inputs[i].script_sig.size = compile_script_sig(coin->address_type, hash, inputs[i].script_sig.bytes); - if (inputs[i].script_sig.size == 0) { - return 0; - } - memcpy(privkey, node.private_key, 32); - memcpy(pubkey, node.public_key, 33); - } else { - inputs[i].script_sig.size = 0; - } - if (!tx_hash_input(&ti, &(inputs[i]))) return 0; - } - for (i = 0; i < outputs_count; i++) { - int co = compile_output(coin, root, &(outputs[i]), &output, idx == 0); - if (co <= 0) { - return co; - } - if (!tx_hash_output(&ti, &output)) return 0; - } - tx_hash_final(&ti, hash, false); - ecdsa_sign_digest(privkey, hash, sig); - int der_len = ecdsa_sig_to_der(sig, buf); - input.script_sig.size = serialize_script_sig(buf, der_len, pubkey, 33, input.script_sig.bytes); - r += tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, out + r); - layoutProgress("Signing", 1000 * idx / inputs_count, idx); - } - for (i = 0; i < outputs_count; i++) { - if (compile_output(coin, root, &(outputs[i]), &output, false) <= 0) { - return 0; - } - r += tx_serialize_output(&to, output.amount, output.script_pubkey.bytes, output.script_pubkey.size, out + r); - } - return r; -} - uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs) { return 10 + inputs * 149 + outputs * 35; diff --git a/firmware/transaction.h b/firmware/transaction.h index c63e7ce0cc..0939ea3637 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -52,10 +52,6 @@ bool tx_hash_input(TxStruct *t, TxInputType *input); bool tx_hash_output(TxStruct *t, TxOutputBinType *output); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -bool transactionHash(TransactionType *tx, uint8_t *hash); - -int transactionSimpleSign(const CoinType *coin, HDNode *root, TxInputType *inputs, uint32_t inputs_count, TxOutputType *outputs, uint32_t outputs_count, uint32_t version, uint32_t lock_time, uint8_t *out); - uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs); diff --git a/trezor-common b/trezor-common index 1865a0428d..06f4aee3fd 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 1865a0428d1803416174f31a1d6b53b6632384a9 +Subproject commit 06f4aee3fd45ec533e7e0e5a2ac06c98ae9975d6 From 1a1ba46e2c18cecfeb2b5d9f7d7f17b4cd2cc596 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 6 Jun 2014 02:37:58 +0200 Subject: [PATCH 0010/1154] update protobuf --- firmware/protob/messages.options | 10 ++--- firmware/protob/messages.pb.c | 20 ++++----- firmware/protob/messages.pb.h | 69 ++++++++++++++------------------ trezor-common | 2 +- 4 files changed, 41 insertions(+), 60 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 1d80312653..6e2ffaf64c 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -57,13 +57,9 @@ VerifyMessage.message max_size:256 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 -EncryptKeyValue.address_n max_count:8 -EncryptKeyValue.key max_size:256 -EncryptKeyValue.value max_size:1024 - -DecryptKeyValue.address_n max_count:8 -DecryptKeyValue.key max_size:256 -DecryptKeyValue.value max_size:1024 +CipherKeyValue.address_n max_count:8 +CipherKeyValue.key max_size:256 +CipherKeyValue.value max_size:1024 EstimateTxSize.coin_name max_size:17 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 077cd7ea38..63d11333ef 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -205,17 +205,13 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; -const pb_field_t EncryptKeyValue_fields[4] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EncryptKeyValue, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, EncryptKeyValue, key, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptKeyValue, value, key, 0), - PB_LAST_FIELD -}; - -const pb_field_t DecryptKeyValue_fields[4] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptKeyValue, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptKeyValue, key, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptKeyValue, value, key, 0), +const pb_field_t CipherKeyValue_fields[7] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), + PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), PB_LAST_FIELD }; @@ -311,7 +307,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptKeyValue_DecryptKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index c3518d1415..b4b62261d5 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -34,8 +34,7 @@ typedef enum _MessageType { MessageType_MessageType_Cancel = 20, MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, - MessageType_MessageType_EncryptKeyValue = 23, - MessageType_MessageType_DecryptKeyValue = 24, + MessageType_MessageType_CipherKeyValue = 23, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, MessageType_MessageType_ButtonAck = 27, @@ -124,6 +123,26 @@ typedef struct _ChangePin { bool remove; } ChangePin; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} CipherKeyValue_value_t; + +typedef struct _CipherKeyValue { + size_t address_n_count; + uint32_t address_n[8]; + bool has_key; + char key[256]; + bool has_value; + CipherKeyValue_value_t value; + bool has_encrypt; + bool encrypt; + bool has_ask_on_encrypt; + bool ask_on_encrypt; + bool has_ask_on_decrypt; + bool ask_on_decrypt; +} CipherKeyValue; + typedef struct _DebugLinkDecision { bool yes_no; } DebugLinkDecision; @@ -170,34 +189,6 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DecryptKeyValue_value_t; - -typedef struct _DecryptKeyValue { - size_t address_n_count; - uint32_t address_n[8]; - bool has_key; - char key[256]; - bool has_value; - DecryptKeyValue_value_t value; -} DecryptKeyValue; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EncryptKeyValue_value_t; - -typedef struct _EncryptKeyValue { - size_t address_n_count; - uint32_t address_n[8]; - bool has_key; - char key[256]; - bool has_value; - EncryptKeyValue_value_t value; -} EncryptKeyValue; - typedef struct { size_t size; uint8_t bytes[1024]; @@ -489,6 +480,12 @@ extern const char SimpleSignTx_coin_name_default[17]; #define ButtonRequest_code_tag 1 #define ButtonRequest_data_tag 2 #define ChangePin_remove_tag 1 +#define CipherKeyValue_address_n_tag 1 +#define CipherKeyValue_key_tag 2 +#define CipherKeyValue_value_tag 3 +#define CipherKeyValue_encrypt_tag 4 +#define CipherKeyValue_ask_on_encrypt_tag 5 +#define CipherKeyValue_ask_on_decrypt_tag 6 #define DebugLinkDecision_yes_no_tag 1 #define DebugLinkLog_level_tag 1 #define DebugLinkLog_bucket_tag 2 @@ -503,12 +500,6 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkState_reset_entropy_tag 8 #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 -#define DecryptKeyValue_address_n_tag 1 -#define DecryptKeyValue_key_tag 2 -#define DecryptKeyValue_value_tag 3 -#define EncryptKeyValue_address_n_tag 1 -#define EncryptKeyValue_key_tag 2 -#define EncryptKeyValue_value_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -619,8 +610,7 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; -extern const pb_field_t EncryptKeyValue_fields[4]; -extern const pb_field_t DecryptKeyValue_fields[4]; +extern const pb_field_t CipherKeyValue_fields[7]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[4]; @@ -667,8 +657,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 326 #define VerifyMessage_size 363 #define MessageSignature_size 104 -#define EncryptKeyValue_size 1334 -#define DecryptKeyValue_size 1334 +#define CipherKeyValue_size 1340 #define EstimateTxSize_size 31 #define TxSize_size 6 #define SignTx_size 31 diff --git a/trezor-common b/trezor-common index 06f4aee3fd..f264f01314 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 06f4aee3fd45ec533e7e0e5a2ac06c98ae9975d6 +Subproject commit f264f01314cefed2df4cfac84d7619d713fbc99a From 465ec2104bc0e2fbf700f3535d1ace9cacd369b1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 6 Jun 2014 02:45:15 +0200 Subject: [PATCH 0011/1154] throw UnexpectedMessage failure on unknown messages --- firmware/Makefile | 1 - firmware/fsm.c | 3 ++- firmware/messages.c | 8 +++++--- firmware/protect.c | 14 +++++++++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index ccd2d9ccc5..600cfdfe4c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -45,4 +45,3 @@ CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' -CFLAGS += -DSCM_REVISION_LEN=20 diff --git a/firmware/fsm.c b/firmware/fsm.c index 834bdbb3a8..dc3ceeef3d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -111,7 +111,8 @@ void fsm_msgInitialize(Initialize *msg) resp->has_pin_protection = true; resp->pin_protection = storage.has_pin; resp->has_passphrase_protection = true; resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; #ifdef SCM_REVISION - resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, sizeof(resp->revision)); resp->revision.size = SCM_REVISION_LEN; + int len = sizeof(SCM_REVISION) - 1; + resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); if (storage.has_language) { diff --git a/firmware/messages.c b/firmware/messages.c index 403d1e8195..5618be39c5 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -290,6 +290,8 @@ void msg_read_common(char type, uint8_t *buf, int len) static uint32_t msg_pos = 0; static const pb_field_t *fields = 0; + if (len != 64) return; + if (read_state == READSTATE_IDLE) { if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard return; @@ -299,7 +301,7 @@ void msg_read_common(char type, uint8_t *buf, int len) fields = MessageFields(type, 'i', msg_id); if (!fields) { // unknown message - // fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); return; } if (msg_size > MSG_IN_SIZE) { // message is too big :( @@ -355,7 +357,7 @@ uint16_t msg_tiny_id = 0xFFFF; void msg_read_tiny(uint8_t *buf, int len) { - if (len < 9) return; + if (len != 64) return; if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { return; } @@ -402,7 +404,7 @@ void msg_read_tiny(uint8_t *buf, int len) msg_tiny_id = 0xFFFF; } } else { - // fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); msg_tiny_id = 0xFFFF; } } diff --git a/firmware/protect.c b/firmware/protect.c index 4c1596ee26..10976b5ee8 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -34,8 +34,11 @@ bool protectAbortedByInitialize = false; bool protectButton(ButtonRequestType type, bool confirm_only) { ButtonRequest resp; - bool result; + bool result = false; bool acked = false; +#if DEBUG_LINK + bool debug_decided = false; +#endif memset(&resp, 0, sizeof(ButtonRequest)); resp.has_code = true; @@ -46,7 +49,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) for (;;) { usbPoll(); - // wait for ButtonAck + // check for ButtonAck if (msg_tiny_id == MessageType_MessageType_ButtonAck) { msg_tiny_id = 0xFFFF; acked = true; @@ -66,6 +69,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) } } + // check for Cancel / Initialize if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { if (msg_tiny_id == MessageType_MessageType_Initialize) { protectAbortedByInitialize = true; @@ -75,12 +79,16 @@ bool protectButton(ButtonRequestType type, bool confirm_only) break; } - // check debug link #if DEBUG_LINK + // check DebugLink if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) { msg_tiny_id = 0xFFFF; DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny; result = dld->yes_no; + debug_decided = true; + } + + if (acked && debug_decided) { break; } From 8c4540ef915e465872dffb7f04dbfa03d926ea3f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 6 Jun 2014 03:01:11 +0200 Subject: [PATCH 0012/1154] use 1st, 2nd, 3rd, etc. for recovery (not 1., 2., 3., etc). --- firmware/recovery.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index 18b383edef..a34a3b7d6e 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -44,15 +44,23 @@ void next_word(void) { layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); } else { fake_word[0] = 0; - char descbuf[] = "__. word"; - char *desc = descbuf; + char desc[] = "##th word"; if (word_pos < 10) { - desc++; + desc[0] = ' '; } else { - descbuf[0] = '0' + word_pos / 10; + desc[0] = '0' + word_pos / 10; } - descbuf[1] = '0' + word_pos % 10; - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the", NULL, desc, NULL, "of your mnemonic", NULL); + desc[1] = '0' + word_pos % 10; + if (word_pos == 1 || word_pos == 21) { + desc[2] = 's'; desc[3] = 't'; + } else + if (word_pos == 2 || word_pos == 22) { + desc[2] = 'n'; desc[3] = 'd'; + } else + if (word_pos == 3 || word_pos == 23) { + desc[2] = 'r'; desc[3] = 'd'; + } + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); } WordRequest resp; memset(&resp, 0, sizeof(WordRequest)); From cf95f50997f5c24ce0abd422022b781016638777 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 6 Jun 2014 12:56:31 +0200 Subject: [PATCH 0013/1154] adjust protobuf --- firmware/protob/types.options | 8 +++----- firmware/protob/types.pb.h | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 477ebb3f66..747eb75a31 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -12,7 +12,7 @@ TxInputType.script_sig max_size:520 TxOutputType.address max_size:35 TxOutputType.address_n max_count:8 -TxOutputBinType.script_pubkey max_size:256 +TxOutputBinType.script_pubkey max_size:520 TransactionType.inputs max_count:1 TransactionType.bin_outputs max_count:1 @@ -23,7 +23,5 @@ TxRequestDetailsType.tx_hash max_size:32 TxRequestSerializedType.signature max_size:80 TxRequestSerializedType.serialized_tx max_size:1024 -MultisigRedeemScriptType.pubkeys max_count:5 -MultisigRedeemScriptType.pubkeys max_size:33 -MultisigRedeemScriptType.signatures max_count:4 -MultisigRedeemScriptType.signatures max_size:80 +MultisigRedeemScriptType.pubkeys max_count:5 max_size:65 +MultisigRedeemScriptType.signatures max_count:4 max_size:80 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index fb674eadff..2f3f016929 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -98,7 +98,7 @@ typedef struct _HDNodeType { typedef struct { size_t size; - uint8_t bytes[33]; + uint8_t bytes[65]; } MultisigRedeemScriptType_pubkeys_t; typedef struct { @@ -115,7 +115,7 @@ typedef struct _MultisigRedeemScriptType { typedef struct { size_t size; - uint8_t bytes[256]; + uint8_t bytes[520]; } TxOutputBinType_script_pubkey_t; typedef struct _TxOutputBinType { @@ -272,11 +272,11 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define CoinType_size 47 -#define MultisigRedeemScriptType_size 503 -#define TxInputType_size 1129 +#define MultisigRedeemScriptType_size 663 +#define TxInputType_size 1289 #define TxOutputType_size 102 -#define TxOutputBinType_size 270 -#define TransactionType_size 1533 +#define TxOutputBinType_size 534 +#define TransactionType_size 1957 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 1115 From 9d1cc7933db22ceb3ad311a018484e7d77598c8c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 6 Jun 2014 16:25:54 +0200 Subject: [PATCH 0014/1154] adjust reset_device loop to match recovery_device loop --- firmware/reset.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/firmware/reset.c b/firmware/reset.c index 4bc5ba0ad1..6070b76895 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -94,11 +94,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memset(int_entropy, 0, 32); awaiting_entropy = false; - int pass, idx, i = 0, j; + int pass, word_pos, i = 0, j; for (pass = 0; pass < 2; pass++) { i = 0; - for (idx = 0; idx < (int)strength/32*3; idx++) { + for (word_pos = 1; word_pos <= (int)strength/32*3; word_pos++) { // copy current_word j = 0; while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { @@ -106,25 +106,33 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) i++; j++; } current_word[j] = 0; if (storage.mnemonic[i] != 0) i++; - char descbuf[] = "__. word is:"; - char *desc = descbuf; - if (idx + 1 < 10) { - desc++; + char desc[] = "##th word"; + if (word_pos < 10) { + desc[0] = ' '; } else { - descbuf[0] = '0' + (idx + 1) / 10; + desc[0] = '0' + word_pos / 10; } - descbuf[1] = '0' + (idx + 1) % 10; - if (idx + 1 == (int)strength/32*3) { // last word + desc[1] = '0' + word_pos % 10; + if (word_pos == 1 || word_pos == 21) { + desc[2] = 's'; desc[3] = 't'; + } else + if (word_pos == 2 || word_pos == 22) { + desc[2] = 'n'; desc[3] = 'd'; + } else + if (word_pos == 3 || word_pos == 23) { + desc[2] = 'r'; desc[3] = 'd'; + } + if (word_pos == (int)strength/32*3) { // last word if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, desc, NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, desc, NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); } } else { if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, desc, NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, desc, NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { From 67ad0432091fef5282fee25a1145efa9c834edeb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 7 Jun 2014 14:21:59 +0200 Subject: [PATCH 0015/1154] adapt to new aes api --- firmware/Makefile | 9 +++++-- firmware/fsm.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ firmware/fsm.h | 1 + firmware/layout2.c | 20 +++++++++++++++ firmware/layout2.h | 1 + firmware/messages.c | 1 + firmware/storage.c | 15 +++++++----- trezor-crypto | 2 +- 8 files changed, 99 insertions(+), 9 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 600cfdfe4c..c9247b150d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -22,15 +22,19 @@ OBJS += debug.o OBJS += ../trezor-crypto/bignum.o OBJS += ../trezor-crypto/ecdsa.o OBJS += ../trezor-crypto/secp256k1.o -OBJS += ../trezor-crypto/sha2.o OBJS += ../trezor-crypto/hmac.o OBJS += ../trezor-crypto/bip32.o -OBJS += ../trezor-crypto/ripemd160.o OBJS += ../trezor-crypto/bip39.o OBJS += ../trezor-crypto/pbkdf2.o +OBJS += ../trezor-crypto/base58.o + +OBJS += ../trezor-crypto/ripemd160.o +OBJS += ../trezor-crypto/sha2.o + OBJS += ../trezor-crypto/aescrypt.o OBJS += ../trezor-crypto/aeskey.o OBJS += ../trezor-crypto/aestab.o +OBJS += ../trezor-crypto/aes_modes.o OBJS += protob/pb_decode.o OBJS += protob/pb_encode.o @@ -41,6 +45,7 @@ OBJS += protob/types.pb.o include ../Makefile.include # CFLAGS += -fstack-protector -fstack-protector-all +CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 diff --git a/firmware/fsm.c b/firmware/fsm.c index dc3ceeef3d..428db6225d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -38,6 +38,8 @@ #include "usb.h" #include "util.h" #include "signing.h" +#include "aes.h" +#include "hmac.h" // message methods @@ -360,6 +362,63 @@ void fsm_msgTxAck(TxAck *msg) } } +void fsm_msgCipherKeyValue(CipherKeyValue *msg) +{ + if (!msg->has_key) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); + return; + } + if (!msg->has_value) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No value provided"); + return; + } + if (msg->value.size % 16) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Value length must be a multiple of 16"); + return; + } + if (!protectPin(true)) { + layoutHome(); + return; + } + HDNode *node = fsm_getRootNode(); + if (!node) return; + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + + bool encrypt = msg->has_encrypt && msg->encrypt; + bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; + bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; + if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { + layoutCipherKeyValue(encrypt, msg->key); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "CipherKeyValue cancelled"); + layoutHome(); + return; + } + } + + uint8_t data[256 + 4]; + strlcpy((char *)data, msg->key, sizeof(data)); + strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); + strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); + + hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); + + RESP_INIT(Success); + if (encrypt) { + aes_encrypt_ctx ctx; + aes_encrypt_key256(data, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx); + } else { + aes_decrypt_ctx ctx; + aes_decrypt_key256(data, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx); + } + resp->has_payload = true; + resp->payload.size = msg->value.size; + msg_write(MessageType_MessageType_Success, resp); + layoutHome(); +} + void fsm_msgApplySettings(ApplySettings *msg) { if (msg->has_label && msg->has_language) { diff --git a/firmware/fsm.h b/firmware/fsm.h index 030d7afdce..59cb2a6b74 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -41,6 +41,7 @@ void fsm_msgSignTx(SignTx *msg); //void fsm_msgPinMatrixAck(PinMatrixAck *msg); void fsm_msgCancel(Cancel *msg); void fsm_msgTxAck(TxAck *msg); +void fsm_msgCipherKeyValue(CipherKeyValue *msg); void fsm_msgApplySettings(ApplySettings *msg); //void fsm_msgButtonAck(ButtonAck *msg); void fsm_msgGetAddress(GetAddress *msg); diff --git a/firmware/layout2.c b/firmware/layout2.c index e4813ed750..e090d51f2c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -231,3 +231,23 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len) ascii ? "Message contents:" : "Bin message contents:", str[0], str[1], str[2], str[3], NULL); } + +void layoutCipherKeyValue(bool encrypt, const char *key) +{ + int len = strlen(key); + char str[4][17]; + memset(str, 0, sizeof(str)); + strlcpy(str[0], (char *)key, 17); + if (len > 16) { + strlcpy(str[1], (char *)key + 16, 17); + } + if (len > 32) { + strlcpy(str[2], (char *)key + 32, 17); + } + if (len > 48) { + strlcpy(str[3], (char *)key + 48, 17); + } + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, + encrypt ? "Encrypt?" : "Decrypt?", + str[0], str[1], str[2], str[3], NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 290b97d481..ffa2f93f22 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -32,5 +32,6 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); +void layoutCipherKeyValue(bool encrypt, const char *key); #endif diff --git a/firmware/messages.c b/firmware/messages.c index 5618be39c5..4a0bb825eb 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -53,6 +53,7 @@ static const struct MessagesMap_t MessagesMap[] = { // {'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *))fsm_msgPinMatrixAck}, {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, + {'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *))fsm_msgCipherKeyValue}, {'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *))fsm_msgApplySettings}, // {'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *))fsm_msgButtonAck}, {'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *))fsm_msgGetAddress}, diff --git a/firmware/storage.c b/firmware/storage.c index 5a993f5aa9..0c99d3611a 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -26,7 +26,9 @@ #include "storage.pb.h" #include "trezor.h" +#include "sha2.h" #include "aes.h" +#include "pbkdf2.h" #include "bip32.h" #include "bip39.h" #include "util.h" @@ -217,12 +219,13 @@ bool storage_getRootNode(HDNode *node) hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode); if (storage.has_passphrase_protection && storage.passphrase_protection) { // decrypt hd node - aes_ctx ctx; - aes_enc_key((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), &ctx); - aes_enc_blk(sessionRootNode.chain_code, sessionRootNode.chain_code, &ctx); - aes_enc_blk(sessionRootNode.chain_code + 16, sessionRootNode.chain_code + 16, &ctx); - aes_enc_blk(sessionRootNode.private_key, sessionRootNode.private_key, &ctx); - aes_enc_blk(sessionRootNode.private_key + 16, sessionRootNode.private_key + 16, &ctx); + uint8_t secret[64]; + layoutProgressSwipe("Waking up", 0, 0); + pbkdf2((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (uint8_t *)"TREZORHD", 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); + aes_decrypt_ctx ctx; + aes_decrypt_key256(secret, &ctx); + aes_cbc_decrypt(sessionRootNode.chain_code, sessionRootNode.chain_code, 32, secret + 32, &ctx); + aes_cbc_decrypt(sessionRootNode.private_key, sessionRootNode.private_key, 32, secret + 32, &ctx); } memcpy(node, &sessionRootNode, sizeof(HDNode)); sessionRootNodeCached = true; diff --git a/trezor-crypto b/trezor-crypto index 44116b8a74..e588906f81 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 44116b8a7405299be5de8353e9e624538b4dac92 +Subproject commit e588906f811e826c596e631d4dd2500fc38fea60 From 272e10152ffc85c4f4114ed0762aeae45e97cd8e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 Jun 2014 20:42:48 +0200 Subject: [PATCH 0016/1154] bump to v 1.1.0 --- firmware/trezor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index c6ecbb1d38..23db6865dc 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,7 +21,7 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 0 +#define VERSION_MINOR 1 #define VERSION_PATCH 0 #define STR(X) #X From 441bb3b5134ab7f404d06b49390a3d5cacf091b7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 17 Jun 2014 16:03:07 +0200 Subject: [PATCH 0017/1154] implement ClearSession --- firmware/fsm.c | 7 +++++++ firmware/fsm.h | 1 + firmware/messages.c | 1 + firmware/protob/messages.pb.c | 19 ++++++++++++++++++- firmware/protob/messages.pb.h | 28 ++++++++++++++++++++++++++++ firmware/storage.c | 5 +++++ firmware/storage.h | 1 + trezor-common | 2 +- 8 files changed, 62 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 428db6225d..ddd975aa26 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -419,6 +419,13 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) layoutHome(); } +void fsm_msgClearSession(ClearSession *msg) +{ + (void)msg; + session_clear(); + fsm_sendSuccess("Session cleared"); +} + void fsm_msgApplySettings(ApplySettings *msg) { if (msg->has_label && msg->has_language) { diff --git a/firmware/fsm.h b/firmware/fsm.h index 59cb2a6b74..a5fcced525 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -42,6 +42,7 @@ void fsm_msgSignTx(SignTx *msg); void fsm_msgCancel(Cancel *msg); void fsm_msgTxAck(TxAck *msg); void fsm_msgCipherKeyValue(CipherKeyValue *msg); +void fsm_msgClearSession(ClearSession *msg); void fsm_msgApplySettings(ApplySettings *msg); //void fsm_msgButtonAck(ButtonAck *msg); void fsm_msgGetAddress(GetAddress *msg); diff --git a/firmware/messages.c b/firmware/messages.c index 4a0bb825eb..23041f996d 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -54,6 +54,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, {'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *))fsm_msgCipherKeyValue}, + {'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *))fsm_msgClearSession}, {'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *))fsm_msgApplySettings}, // {'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *))fsm_msgButtonAck}, {'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *))fsm_msgGetAddress}, diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 63d11333ef..02f7617ddf 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -37,6 +37,10 @@ const pb_field_t Features_fields[16] = { PB_LAST_FIELD }; +const pb_field_t ClearSession_fields[1] = { + PB_LAST_FIELD +}; + const pb_field_t ApplySettings_fields[3] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), @@ -205,6 +209,19 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; +const pb_field_t EncryptMessage_fields[4] = { + PB_FIELD2( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EncryptMessage, pubkey, pubkey, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EncryptMessage, message, pubkey, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptMessage_fields[3] = { + PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, DecryptMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, DecryptMessage, message, address_n, 0), + PB_LAST_FIELD +}; + const pb_field_t CipherKeyValue_fields[7] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), @@ -307,7 +324,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_DecryptMessage_CipherKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index b4b62261d5..d296af26c2 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -35,6 +35,7 @@ typedef enum _MessageType { MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, MessageType_MessageType_CipherKeyValue = 23, + MessageType_MessageType_ClearSession = 24, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, MessageType_MessageType_ButtonAck = 27, @@ -45,6 +46,8 @@ typedef enum _MessageType { MessageType_MessageType_SignMessage = 38, MessageType_MessageType_VerifyMessage = 39, MessageType_MessageType_MessageSignature = 40, + MessageType_MessageType_EncryptMessage = 48, + MessageType_MessageType_DecryptMessage = 49, MessageType_MessageType_PassphraseRequest = 41, MessageType_MessageType_PassphraseAck = 42, MessageType_MessageType_EstimateTxSize = 43, @@ -68,6 +71,10 @@ typedef struct _Cancel { uint8_t dummy_field; } Cancel; +typedef struct _ClearSession { + uint8_t dummy_field; +} ClearSession; + typedef struct _DebugLinkGetState { uint8_t dummy_field; } DebugLinkGetState; @@ -189,6 +196,18 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; +typedef struct _DecryptMessage { + pb_callback_t address_n; + pb_callback_t message; +} DecryptMessage; + +typedef struct _EncryptMessage { + pb_callback_t pubkey; + pb_callback_t message; + bool has_display_only; + bool display_only; +} EncryptMessage; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -500,6 +519,11 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkState_reset_entropy_tag 8 #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 +#define DecryptMessage_address_n_tag 1 +#define DecryptMessage_message_tag 2 +#define EncryptMessage_pubkey_tag 1 +#define EncryptMessage_message_tag 2 +#define EncryptMessage_display_only_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -581,6 +605,7 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; extern const pb_field_t Features_fields[16]; +extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[3]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; @@ -610,6 +635,8 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; +extern const pb_field_t EncryptMessage_fields[4]; +extern const pb_field_t DecryptMessage_fields[3]; extern const pb_field_t CipherKeyValue_fields[7]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; @@ -628,6 +655,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define Features_size (224 + 4*CoinType_size) +#define ClearSession_size 0 #define ApplySettings_size 54 #define ChangePin_size 2 #define Ping_size 265 diff --git a/firmware/storage.c b/firmware/storage.c index 0c99d3611a..4b1d1f499b 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -109,6 +109,11 @@ void storage_reset(void) // reset storage struct memset(&storage, 0, sizeof(storage)); storage.version = STORAGE_VERSION; + session_clear(); +} + +void session_clear(void) +{ sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); sessionPinCached = false; memset(&sessionPin, 0, sizeof(sessionPin)); diff --git a/firmware/storage.h b/firmware/storage.h index 0efe52f132..f68ab78fd8 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -29,6 +29,7 @@ void storage_init(void); void storage_reset_uuid(void); void storage_reset(void); void storage_commit(void); +void session_clear(void); void storage_loadDevice(LoadDevice *msg); diff --git a/trezor-common b/trezor-common index f264f01314..bf7b99fd28 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit f264f01314cefed2df4cfac84d7619d713fbc99a +Subproject commit bf7b99fd286ae6ff5ada0e1bc7e4d403f5a7dc8e From add928373f6289b55c9abb0a79dbe30bf1aff224 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Jun 2014 11:54:54 +0200 Subject: [PATCH 0018/1154] detect absolute path to Makefile.include automagically --- Makefile.include | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index ac43055be7..49c6000be9 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,3 +1,6 @@ +TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +TOOLCHAIN_DIR := $(TOP_DIR)/../libopencm3 + PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc LD = $(PREFIX)gcc @@ -5,8 +8,6 @@ OBJCOPY = $(PREFIX)objcopy OBJDUMP = $(PREFIX)objdump FLASH = st-flash OPENOCD = openocd -TOP_DIR = /home/stick/work/trezor/trezor-mcu -TOOLCHAIN_DIR = $(TOP_DIR)/../libopencm3 OPTFLAGS = -Os -g From ea42f6af4ee4dad04c82b7fdcb4bedf2e29bfa24 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jun 2014 00:12:31 +0200 Subject: [PATCH 0019/1154] adapt to new opencm3 include structure --- buttons.h | 2 +- firmware/storage.c | 2 +- memory.c | 2 +- oled.c | 4 ++-- rng.c | 2 ++ setup.c | 6 +++--- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/buttons.h b/buttons.h index 78a0fe24f5..58b7188019 100644 --- a/buttons.h +++ b/buttons.h @@ -20,7 +20,7 @@ #ifndef __BUTTONS_H__ #define __BUTTONS_H__ -#include +#include struct buttonState { volatile bool YesUp; diff --git a/firmware/storage.c b/firmware/storage.c index 4b1d1f499b..a3a00c847d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include "messages.pb.h" #include "storage.pb.h" diff --git a/memory.c b/memory.c index c82f9cf36b..5dcc8bd464 100644 --- a/memory.c +++ b/memory.c @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -#include +#include #include #include "memory.h" #include "sha2.h" diff --git a/oled.c b/oled.c index d207a1419e..a62b3c5190 100644 --- a/oled.c +++ b/oled.c @@ -17,8 +17,8 @@ * along with this library. If not, see . */ -#include -#include +#include +#include #include diff --git a/rng.c b/rng.c index 7bf275ac39..787739f4af 100644 --- a/rng.c +++ b/rng.c @@ -17,6 +17,8 @@ * along with this library. If not, see . */ +#include +#include #include #include "rng.h" diff --git a/setup.c b/setup.c index 310d86bf09..340bb20aa1 100644 --- a/setup.c +++ b/setup.c @@ -17,9 +17,9 @@ * along with this library. If not, see . */ -#include -#include -#include +#include +#include +#include #include void setup(void) From 23bae6ec9d7d7be680d8422385457aec462fe028 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jun 2014 00:31:40 +0200 Subject: [PATCH 0020/1154] add Dockerfile --- Dockerfile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..cd75d0f61d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# initialize from the image + +FROM ubuntu:14.04 + +# add and update package repositories + +RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update + +# install build tools and dependencies + +RUN apt-get install -y build-essential git gcc-arm-none-eabi python + +# clone the source code + +RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://github.com/trezor/trezor-mcu && cd trezor-mcu && git submodule update --init + +# build libopencm3 + +RUN cd libopencm3 && make + +# build the firmware + +RUN cd trezor-mcu && make && cd firmware && make From 92b6b8caf13fa0c8d9194210d759eb4bd695c495 Mon Sep 17 00:00:00 2001 From: slush0 Date: Thu, 19 Jun 2014 02:08:31 +0200 Subject: [PATCH 0021/1154] Tools for deterministic builds and firmware comparing --- docker-build.sh | 24 ++++++++++++++++++++++++ firmware-fingerprint.sh | 11 +++++++++++ 2 files changed, 35 insertions(+) create mode 100755 docker-build.sh create mode 100755 firmware-fingerprint.sh diff --git a/docker-build.sh b/docker-build.sh new file mode 100755 index 0000000000..4cb95deee7 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +dirname $0 + +# Build trezor firmware +docker build . | tee docker.log + +# Parse image name +IMAGE=`grep "Successfully built" docker.log | tail -n1 | cut -d' ' -f3` +echo "IMAGE NAME: $IMAGE" + +docker run -t $IMAGE true + +# Parse container name +CONTAINER=`docker ps -a | grep true | head -n1 | cut -d' ' -f1` +echo "CONTAINER NAME: $CONTAINER" + +docker cp $CONTAINER:/trezor-mcu/firmware/trezor.bin . + +echo "-------------------------" +echo "" +echo "SHA256 hash:" + +sha256sum trezor.bin diff --git a/firmware-fingerprint.sh b/firmware-fingerprint.sh new file mode 100755 index 0000000000..498ba9c9b3 --- /dev/null +++ b/firmware-fingerprint.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +MAGIC=`head -c +4 $1` + +if [ "x$MAGIC" != "xTRZR" ]; then + echo "Missing magic characters 'TRZR', invalid firmware" + exit 1 +fi + +echo "Firmware fingerprint:" +tail -c +257 $1 | sha256sum From e3d7687b7da6e5e79cc2796fb529a135bdd47178 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jun 2014 02:16:28 +0200 Subject: [PATCH 0022/1154] add CFLAGS optimizations --- Makefile.include | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.include b/Makefile.include index 49c6000be9..f51cfc231d 100644 --- a/Makefile.include +++ b/Makefile.include @@ -33,6 +33,8 @@ CFLAGS += $(OPTFLAGS) \ -fno-common \ -fno-exceptions \ -fvisibility=internal \ + -ffunction-sections \ + -fdata-sections \ -mcpu=cortex-m3 \ -mthumb \ -msoft-float \ From b6b49a20f5ea56a1ccd280a48a69c22d3ad3ced8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jun 2014 02:28:22 +0200 Subject: [PATCH 0023/1154] small changes to scripts for deterministic builds --- .gitignore | 4 ++-- Makefile.include | 5 +++-- docker-build.sh => firmware-docker-build.sh | 9 ++++----- firmware-fingerprint.sh | 1 + 4 files changed, 10 insertions(+), 9 deletions(-) rename docker-build.sh => firmware-docker-build.sh (62%) diff --git a/.gitignore b/.gitignore index 335be47ead..3c2f91f893 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ +*.o *.a *.d -*.o *.bin *.elf *.hex *.list *.srec -usb.pb* +*.log bootloader diff --git a/Makefile.include b/Makefile.include index f51cfc231d..9310d57be6 100644 --- a/Makefile.include +++ b/Makefile.include @@ -118,9 +118,10 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP clean: rm -f $(OBJS) rm -f *.a + rm -f *.bin rm -f *.d rm -f *.elf - rm -f *.bin rm -f *.hex - rm -f *.srec rm -f *.list + rm -r *.log + rm -f *.srec diff --git a/docker-build.sh b/firmware-docker-build.sh similarity index 62% rename from docker-build.sh rename to firmware-docker-build.sh index 4cb95deee7..ab44c9c524 100755 --- a/docker-build.sh +++ b/firmware-docker-build.sh @@ -3,10 +3,10 @@ dirname $0 # Build trezor firmware -docker build . | tee docker.log +docker build . | tee firmware-docker-build.log # Parse image name -IMAGE=`grep "Successfully built" docker.log | tail -n1 | cut -d' ' -f3` +IMAGE=`grep "Successfully built" firmware-docker-build.log | tail -n1 | cut -d' ' -f3` echo "IMAGE NAME: $IMAGE" docker run -t $IMAGE true @@ -17,8 +17,7 @@ echo "CONTAINER NAME: $CONTAINER" docker cp $CONTAINER:/trezor-mcu/firmware/trezor.bin . -echo "-------------------------" -echo "" -echo "SHA256 hash:" +echo "---------------------" +echo "Firmware fingerprint:" sha256sum trezor.bin diff --git a/firmware-fingerprint.sh b/firmware-fingerprint.sh index 498ba9c9b3..d235528f44 100755 --- a/firmware-fingerprint.sh +++ b/firmware-fingerprint.sh @@ -7,5 +7,6 @@ if [ "x$MAGIC" != "xTRZR" ]; then exit 1 fi +echo "---------------------" echo "Firmware fingerprint:" tail -c +257 $1 | sha256sum From c97b9348ff6317e7eb5aa61493c8e5146d0d5409 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jun 2014 19:01:41 +0200 Subject: [PATCH 0024/1154] add repo key to Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cd75d0f61d..fbebaff371 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM ubuntu:14.04 # add and update package repositories -RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update # install build tools and dependencies From a6105fbcb8ef09538214defceaaf96deb4501e36 Mon Sep 17 00:00:00 2001 From: slush0 Date: Fri, 20 Jun 2014 00:15:26 +0200 Subject: [PATCH 0025/1154] Howto for deterministic builds --- README | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README b/README index 98772f8ca7..5fae0e2119 100644 --- a/README +++ b/README @@ -1,3 +1,24 @@ -Embedded software for TREZOR +TREZOR firmware http://bitcointrezor.com/ + +How to build Trezor firmware? +============================= +1. Install Docker (docker.com) +2. git clone git@github.com:trezor/trezor-mcu.git +3. cd trezor-mcu +4. ./firmware-docker-build.sh + +This generates trezor.bin in current directory and prints sha256 fingerprint on last line of build log. + +How to get sha256 fingerprint of firmware signed and distributed by SatoshiLabs? +================================================================================ +1. Pick proper version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json +2. Download it: wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex +3. xxd -r -p trezor.signed.bin.hex trezor.signed.bin +4. ./firmware-fingerprint.sh trezor.signed.bin + +Step 4 should produce the same sha256 fingerprint like your local build. + +The reasoning behind "firmware-fingerprint.sh" is that signed firmware has special header holding signatures themselves, +which must be removed before calculating fingerprint. From e9fd756daad713525fa30bc3a08df4127548383f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 21 Jun 2014 00:31:44 +0200 Subject: [PATCH 0026/1154] better UI for layoutSignMessage, layoutVerifyMessage and layoutCipherKeyValue --- firmware/fsm.c | 2 ++ firmware/layout2.c | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ddd975aa26..35aa7b30ac 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -518,6 +518,7 @@ void fsm_msgSignMessage(SignMessage *msg) fsm_deriveKey(node, msg->address_n, msg->address_n_count); ecdsa_get_address(node->public_key, coin->address_type, resp->address); + layoutProgressSwipe("Signing", 0, 0); if (transactionMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->address, resp->signature.bytes)) { resp->has_address = true; resp->has_signature = true; @@ -532,6 +533,7 @@ void fsm_msgSignMessage(SignMessage *msg) void fsm_msgVerifyMessage(VerifyMessage *msg) { const char *address = msg->has_address ? msg->address : 0; + layoutProgressSwipe("Verifying", 0, 0); if (msg->signature.size == 65 && transactionMessageVerify(msg->message.bytes, msg->message.size, msg->signature.bytes, address)) { layoutVerifyMessage(msg->message.bytes, msg->message.size); protectButton(ButtonRequestType_ButtonRequest_Other, true); diff --git a/firmware/layout2.c b/firmware/layout2.c index e090d51f2c..f5b48215a9 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -185,9 +185,9 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) } } - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", ascii ? "Sign text message?" : "Sign binary message?", - str[0], str[1], str[2], str[3], NULL); + str[0], str[1], str[2], str[3], NULL, NULL); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) @@ -227,9 +227,9 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len) } } - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", NULL, - ascii ? "Message contents:" : "Bin message contents:", - str[0], str[1], str[2], str[3], NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", + ascii ? "Message contents" : "Binary message contents", + str[0], str[1], str[2], str[3], NULL, NULL); } void layoutCipherKeyValue(bool encrypt, const char *key) @@ -247,7 +247,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key) if (len > 48) { strlcpy(str[3], (char *)key + 48, 17); } - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", encrypt ? "Encrypt?" : "Decrypt?", - str[0], str[1], str[2], str[3], NULL); + str[0], str[1], str[2], str[3], NULL, NULL); } From 62ac6593f82475886e3d9f31b3c016c51718ffdb Mon Sep 17 00:00:00 2001 From: slush0 Date: Sun, 22 Jun 2014 19:29:16 +0200 Subject: [PATCH 0027/1154] Fixed docker build howto --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 5fae0e2119..10ae4f92c7 100644 --- a/README +++ b/README @@ -5,9 +5,9 @@ http://bitcointrezor.com/ How to build Trezor firmware? ============================= 1. Install Docker (docker.com) -2. git clone git@github.com:trezor/trezor-mcu.git +2. git clone https://github.com/trezor/trezor-mcu.git 3. cd trezor-mcu -4. ./firmware-docker-build.sh +4. sudo ./firmware-docker-build.sh (sudo may be needed on some distros because of Docker) This generates trezor.bin in current directory and prints sha256 fingerprint on last line of build log. From f59500510a2876dc74a7c9773998938fb98111a3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 23 Jun 2014 00:37:24 +0200 Subject: [PATCH 0028/1154] pin used revisions in Dockerfile --- Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index fbebaff371..c785e5acc4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,18 +6,24 @@ FROM ubuntu:14.04 RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update +# define used versions for pinning + +ENV GCC_ARM_VERSION 4-8-2014q2-0trusty9 +ENV LIBOPENCM3_GITREV c01f9ee323d06b5325d77cda593a46dfe76ba341 +ENV TREZOR_MCU_GITREV e9fd756daad713525fa30bc3a08df4127548383f + # install build tools and dependencies -RUN apt-get install -y build-essential git gcc-arm-none-eabi python +RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION python # clone the source code -RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://github.com/trezor/trezor-mcu && cd trezor-mcu && git submodule update --init +RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://github.com/trezor/trezor-mcu # build libopencm3 -RUN cd libopencm3 && make +RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make # build the firmware -RUN cd trezor-mcu && make && cd firmware && make +RUN cd trezor-mcu && git checkout $TREZOR_MCU_GITREV && git submodule update --init && make && cd firmware && make From 098ec05c5f5ff26d80bbc3284851c27a080b14cf Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Wed, 25 Jun 2014 14:25:30 +0200 Subject: [PATCH 0029/1154] Pin GPG key of ARM GCC repo by full fingerprint in Docker build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c785e5acc4..4e34632530 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ FROM ubuntu:14.04 # add and update package repositories -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update # define used versions for pinning From 849e758eb46ad521a076e6453d6b7ded92b69de4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 26 Jun 2014 00:26:19 +0200 Subject: [PATCH 0030/1154] double the delay before buttonupdate --- firmware/protect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protect.c b/firmware/protect.c index 10976b5ee8..3067678fc9 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -57,7 +57,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // button acked - check buttons if (acked) { - delay(50000); + delay(100000); buttonUpdate(); if (button.YesUp) { result = true; From 9ca3854146bbe2a78bc5f8160fa393ffe3148a5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Jul 2014 19:48:54 +0200 Subject: [PATCH 0031/1154] use estimate instead of real size of tx when calculating fee warning --- firmware/signing.c | 5 +++-- trezor-crypto | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 85ca2acb07..4c21cc4b3d 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -374,8 +374,9 @@ void signing_txack(TransactionType *tx) return; } uint64_t fee = to_spend - spending; - if (fee > (((uint64_t)tc.size + 999) / 1000) * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, ((uint64_t)tc.size + 999) / 1000); + uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); + if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee, tx_est_size); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); layoutHome(); diff --git a/trezor-crypto b/trezor-crypto index e588906f81..3308cc62a6 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit e588906f811e826c596e631d4dd2500fc38fea60 +Subproject commit 3308cc62a64bac76fb475363f9bce83cab1d8381 From 8ee9d50eb657cfa3ef1496547a9669b787cd60a5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Jul 2014 20:29:44 +0200 Subject: [PATCH 0032/1154] leave GPIO9 floating --- Makefile.include | 2 +- setup.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Makefile.include b/Makefile.include index 9310d57be6..bb8daba02b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -123,5 +123,5 @@ clean: rm -f *.elf rm -f *.hex rm -f *.list - rm -r *.log + rm -f *.log rm -f *.srec diff --git a/setup.c b/setup.c index 340bb20aa1..117a5b5cce 100644 --- a/setup.c +++ b/setup.c @@ -29,16 +29,18 @@ void setup(void) rcc_clock_setup_hse_3v3(&clock); // enable GPIO clock - A (oled), B(oled), C (buttons) - rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN | RCC_AHB1ENR_IOPBEN | RCC_AHB1ENR_IOPCEN); + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOC); // enable SPI clock - rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_SPI1EN); + rcc_periph_clock_enable(RCC_SPI1); // enable OTG FS clock - rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + rcc_periph_clock_enable(RCC_OTGFS); // enable RNG - rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_RNGEN); + rcc_periph_clock_enable(RCC_RNG); RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; // set GPIO for buttons @@ -61,6 +63,6 @@ void setup(void) spi_enable(SPI1); // enable OTG_FS - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); - gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); } From df524b9f35fd5cdba14eaa2bf2d948e3dc75254a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 1 Jul 2014 21:42:00 +0200 Subject: [PATCH 0033/1154] prepare 1.2.0 release --- Dockerfile | 6 +++--- firmware-fingerprint.sh | 5 +++++ firmware/protob/types.pb.h | 3 ++- firmware/trezor.h | 2 +- trezor-common | 2 +- trezor-crypto | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e34632530..38a4dd0160 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,9 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497E # define used versions for pinning -ENV GCC_ARM_VERSION 4-8-2014q2-0trusty9 -ENV LIBOPENCM3_GITREV c01f9ee323d06b5325d77cda593a46dfe76ba341 -ENV TREZOR_MCU_GITREV e9fd756daad713525fa30bc3a08df4127548383f +ENV GCC_ARM_VERSION 4-8-2014q2-0trusty10 +ENV LIBOPENCM3_GITREV f6b6d62ec5628ebb0602c466ee9fd7a6070ef1f0 +ENV TREZOR_MCU_GITREV v1.2.0 # install build tools and dependencies diff --git a/firmware-fingerprint.sh b/firmware-fingerprint.sh index d235528f44..0157467ccf 100755 --- a/firmware-fingerprint.sh +++ b/firmware-fingerprint.sh @@ -1,5 +1,10 @@ #!/bin/bash +if [ -z "$1" ]; then + echo "Please provide filename as argument" + exit 1 +fi + MAGIC=`head -c +4 $1` if [ "x$MAGIC" != "xTRZR" ]; then diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 2f3f016929..ac4756a446 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -49,7 +49,8 @@ typedef enum _ButtonRequestType { ButtonRequestType_ButtonRequest_ConfirmWord = 5, ButtonRequestType_ButtonRequest_WipeDevice = 6, ButtonRequestType_ButtonRequest_ProtectCall = 7, - ButtonRequestType_ButtonRequest_SignTx = 8 + ButtonRequestType_ButtonRequest_SignTx = 8, + ButtonRequestType_ButtonRequest_FirmwareCheck = 9 } ButtonRequestType; typedef enum _PinMatrixRequestType { diff --git a/firmware/trezor.h b/firmware/trezor.h index 23db6865dc..d4ad817a65 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,7 +21,7 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 1 +#define VERSION_MINOR 2 #define VERSION_PATCH 0 #define STR(X) #X diff --git a/trezor-common b/trezor-common index bf7b99fd28..fc98712da5 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit bf7b99fd286ae6ff5ada0e1bc7e4d403f5a7dc8e +Subproject commit fc98712da5c260f3828dab703880eb5e9da00580 diff --git a/trezor-crypto b/trezor-crypto index 3308cc62a6..3747ba4323 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 3308cc62a64bac76fb475363f9bce83cab1d8381 +Subproject commit 3747ba432336bf10191a63e84fbfead62e944ddb From 2707e8aff66be3ff78929cfe9528ada068f0bd10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 15:03:34 +0200 Subject: [PATCH 0034/1154] move APPVER guards from includes to app code --- demo/demo.c | 2 ++ firmware/trezor.c | 4 ++++ oled.h | 4 ---- setup.c | 6 ++++++ setup.h | 5 +---- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index 77dc3b5f1f..ff3b9b7f0a 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -241,8 +241,10 @@ void usbInit(void) int main(void) { +#ifndef APPVER setup(); oledInit(); +#endif usbInit(); passlen = strlen((char *)pass); diff --git a/firmware/trezor.c b/firmware/trezor.c index 9298285aed..969eb4ffe3 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -29,8 +29,12 @@ int main(void) { +#ifndef APPVER setup(); oledInit(); +#else + setupApp(); +#endif // __stack_chk_guard_setup(); #if DEBUG_LINK oledSetDebug(1); diff --git a/oled.h b/oled.h index f23728cfd6..0823b7a1a3 100644 --- a/oled.h +++ b/oled.h @@ -29,11 +29,7 @@ #define OLED_HEIGHT 64 #define OLED_BUFSIZE (OLED_WIDTH * OLED_HEIGHT / 8) -#ifdef APPVER -#define oledInit() do{}while(0) -#else void oledInit(void); -#endif void oledClear(void); void oledRefresh(void); diff --git a/setup.c b/setup.c index 117a5b5cce..cb6ad1bf03 100644 --- a/setup.c +++ b/setup.c @@ -66,3 +66,9 @@ void setup(void) gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); } + +void setupApp(void) +{ + // hotfix for old bootloader + gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); +} diff --git a/setup.h b/setup.h index a54c81b95d..ece89a52c4 100644 --- a/setup.h +++ b/setup.h @@ -20,10 +20,7 @@ #ifndef __SETUP_H__ #define __SETUP_H__ -#ifdef APPVER -#define setup() do{}while(0) -#else void setup(void); -#endif +void setupApp(void); #endif From 35d0aef0d478e672f735c9de016e4ac37cda9fc6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Jul 2014 16:59:37 +0200 Subject: [PATCH 0035/1154] simplify firmware-docker-build.sh --- firmware-docker-build.sh | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index ab44c9c524..3df89a88b3 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -2,20 +2,15 @@ dirname $0 -# Build trezor firmware -docker build . | tee firmware-docker-build.log +IMAGETAG=trezor-mcu-build +docker rmi $IMAGETAG || : +docker build -t $IMAGETAG . -# Parse image name -IMAGE=`grep "Successfully built" firmware-docker-build.log | tail -n1 | cut -d' ' -f3` -echo "IMAGE NAME: $IMAGE" +CONTAINERTAG=trezor-mcu-build +docker rm $CONTAINERTAG || : +docker run --name $CONTAINERTAG $IMAGETAG true -docker run -t $IMAGE true - -# Parse container name -CONTAINER=`docker ps -a | grep true | head -n1 | cut -d' ' -f1` -echo "CONTAINER NAME: $CONTAINER" - -docker cp $CONTAINER:/trezor-mcu/firmware/trezor.bin . +docker cp $CONTAINERTAG:/trezor-mcu/firmware/trezor.bin . echo "---------------------" echo "Firmware fingerprint:" From ea4d99cfee14d4c08431882c0d2b90f55aa3e7d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Jul 2014 18:11:44 +0200 Subject: [PATCH 0036/1154] change recovery logic --- firmware/recovery.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index a34a3b7d6e..1aa6d36e89 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -33,7 +33,7 @@ static bool enforce_wordlist; static char fake_word[12]; static uint32_t word_pos; static uint32_t word_index; -static char word_order[36]; +static char word_order[24]; static char words[24][12]; void next_word(void) { @@ -94,12 +94,12 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr for (i = 0; i < word_count; i++) { word_order[i] = i + 1; } - for (i = word_count; i < word_count + word_count / 2; i++) { + for (i = word_count; i < 24; i++) { word_order[i] = 0; } for (i = 0; i < 10000; i++) { - j = random32() % (word_count + word_count / 2); - k = random32() % (word_count + word_count / 2); + j = random32() % 24; + k = random32() % 24; t = word_order[j]; word_order[j] = word_order[k]; word_order[k] = t; @@ -145,7 +145,7 @@ void recovery_word(const char *word) strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); } - if (word_index + 1 == word_count + word_count / 2) { // last one + if (word_index + 1 == 24) { // last one uint32_t i; strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); for (i = 1; i < word_count; i++) { From cb39ab7b6d75513ce512b7d3b0715f7b5df20156 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 17 Jul 2014 16:41:34 +0200 Subject: [PATCH 0037/1154] new trezor-crypto, uint32_t -> size_t --- rng.c | 5 +++-- rng.h | 3 ++- trezor-crypto | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rng.c b/rng.c index 787739f4af..0f7437a741 100644 --- a/rng.c +++ b/rng.c @@ -35,9 +35,10 @@ uint32_t random32(void) return new; } -void random_buffer(uint8_t *buf, uint32_t len) +void random_buffer(uint8_t *buf, size_t len) { - uint32_t i, r = 0; + size_t i; + uint32_t r = 0; for (i = 0; i < len; i++) { if (i % 4 == 0) { r = random32(); diff --git a/rng.h b/rng.h index c8e02e3987..9fbe2bea29 100644 --- a/rng.h +++ b/rng.h @@ -21,8 +21,9 @@ #define __RNG_H__ #include +#include uint32_t random32(void); -void random_buffer(uint8_t *buf, uint32_t len); +void random_buffer(uint8_t *buf, size_t len); #endif diff --git a/trezor-crypto b/trezor-crypto index 3747ba4323..ffd2d69dd6 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 3747ba432336bf10191a63e84fbfead62e944ddb +Subproject commit ffd2d69dd658bad0e78cad853f8b81f2cd3e4b05 From a2eb43b05708a7cede7b67f1de14d094f50b0865 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 27 Jul 2014 16:20:35 +0200 Subject: [PATCH 0038/1154] fix message length in msg_read_tiny --- firmware/messages.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 23041f996d..4233ce8d4c 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -364,13 +364,13 @@ void msg_read_tiny(uint8_t *buf, int len) return; } uint16_t msg_id = (buf[3] << 8) + buf[4]; - uint32_t msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + uint32_t msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; if (msg_size > 64 || len - msg_size < 9) { return; } const pb_field_t *fields = 0; - pb_istream_t stream = pb_istream_from_buffer(buf + 9, len - 9); + pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); switch (msg_id) { case MessageType_MessageType_PinMatrixAck: From 524f2a957afb66e6a869384aceaca1cb7f9cba60 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 30 Jul 2014 20:34:28 +0200 Subject: [PATCH 0039/1154] enable stack protector --- Dockerfile | 9 +++------ Makefile.include | 1 + firmware/Makefile | 1 - firmware/ssp.c | 40 ---------------------------------------- firmware/ssp.h | 26 -------------------------- firmware/storage.c | 7 +++++-- firmware/transaction.c | 4 ++-- firmware/trezor.c | 13 +++++++++++-- firmware/trezor.h | 2 +- serialno.c | 18 ++++-------------- 10 files changed, 27 insertions(+), 94 deletions(-) delete mode 100644 firmware/ssp.c delete mode 100644 firmware/ssp.h diff --git a/Dockerfile b/Dockerfile index 38a4dd0160..81c4cf840d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,14 +6,9 @@ FROM ubuntu:14.04 RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update -# define used versions for pinning - -ENV GCC_ARM_VERSION 4-8-2014q2-0trusty10 -ENV LIBOPENCM3_GITREV f6b6d62ec5628ebb0602c466ee9fd7a6070ef1f0 -ENV TREZOR_MCU_GITREV v1.2.0 - # install build tools and dependencies +ENV GCC_ARM_VERSION 4-8-2014q2-0trusty10 RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION python # clone the source code @@ -22,8 +17,10 @@ RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://gith # build libopencm3 +ENV LIBOPENCM3_GITREV f6b6d62ec5628ebb0602c466ee9fd7a6070ef1f0 RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make # build the firmware +ENV TREZOR_MCU_GITREV v1.2.1 RUN cd trezor-mcu && git checkout $TREZOR_MCU_GITREV && git submodule update --init && make && cd firmware && make diff --git a/Makefile.include b/Makefile.include index bb8daba02b..59b8e7de52 100644 --- a/Makefile.include +++ b/Makefile.include @@ -35,6 +35,7 @@ CFLAGS += $(OPTFLAGS) \ -fvisibility=internal \ -ffunction-sections \ -fdata-sections \ + -fstack-protector-all \ -mcpu=cortex-m3 \ -mthumb \ -msoft-float \ diff --git a/firmware/Makefile b/firmware/Makefile index c9247b150d..f5f5d6b21c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -2,7 +2,6 @@ APPVER = 1.0.0 NAME = trezor -OBJS += ssp.o OBJS += usb.o OBJS += messages.o OBJS += storage.o diff --git a/firmware/ssp.c b/firmware/ssp.c deleted file mode 100644 index 089a77af11..0000000000 --- a/firmware/ssp.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the TREZOR project. - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "ssp.h" -#include "rng.h" -#include "layout.h" - -void *__stack_chk_guard = 0; - -void __stack_chk_guard_setup(void) -{ - unsigned char * p; - p = (unsigned char *) &__stack_chk_guard; - p[0] = 0; - p[1] = 0; - p[2] = '\n'; - p[3] = 0xFF; // random32() & 0xFF; -} - -void __attribute__((noreturn)) __stack_chk_fail(void) -{ - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever -} diff --git a/firmware/ssp.h b/firmware/ssp.h deleted file mode 100644 index c1cb260209..0000000000 --- a/firmware/ssp.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of the TREZOR project. - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#ifndef __SSP_H_ -#define __SSP_H_ - -void __stack_chk_guard_setup(void); -void __attribute__((noreturn)) __stack_chk_fail(void); - -#endif diff --git a/firmware/storage.c b/firmware/storage.c index a3a00c847d..ba6193531b 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -63,12 +63,15 @@ static char sessionPassphrase[51]; 0x0010 | ? | Storage structure */ -#define STORAGE_VERSION 1 +#define STORAGE_VERSION 2 void storage_from_flash(uint32_t version) { switch (version) { - case 1: + case 1: // copy + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + break; + case 2: // copy memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; } diff --git a/firmware/transaction.c b/firmware/transaction.c index c97b018ff6..8aa4776bdd 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -246,7 +246,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v bool tx_hash_input(TxStruct *t, TxInputType *input) { - uint8_t buf[512]; + uint8_t buf[1024]; uint32_t r = tx_serialize_input(t, input->prev_hash.bytes, input->prev_index, input->script_sig.bytes, input->script_sig.size, input->sequence, buf); if (!r) return false; sha256_Update(&(t->ctx), buf, r); @@ -255,7 +255,7 @@ bool tx_hash_input(TxStruct *t, TxInputType *input) bool tx_hash_output(TxStruct *t, TxOutputBinType *output) { - uint8_t buf[512]; + uint8_t buf[1024]; uint32_t r = tx_serialize_output(t, output->amount, output->script_pubkey.bytes, output->script_pubkey.size, buf); if (!r) return false; sha256_Update(&(t->ctx), buf, r); diff --git a/firmware/trezor.c b/firmware/trezor.c index 969eb4ffe3..bc9c1ba1b3 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -24,18 +24,27 @@ #include "usb.h" #include "setup.h" #include "storage.h" +#include "layout.h" #include "layout2.h" -#include "ssp.h" +#include "rng.h" + +uint32_t __stack_chk_guard; + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever +} int main(void) { + __stack_chk_guard = random32(); #ifndef APPVER setup(); oledInit(); #else setupApp(); #endif -// __stack_chk_guard_setup(); #if DEBUG_LINK oledSetDebug(1); storage_reset(); // wipe storage if debug link diff --git a/firmware/trezor.h b/firmware/trezor.h index d4ad817a65..001b7a4499 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/serialno.c b/serialno.c index 024d6ed49a..b8c6741634 100644 --- a/serialno.c +++ b/serialno.c @@ -20,27 +20,17 @@ #include #include +#include + #include "serialno.h" #include "util.h" #include "sha2.h" -#if defined(STM32F4) || defined(STM32F2) -#define UNIQUE_SERIAL_ADDR 0x1FFF7A10 -#elif defined(STM32F3) -#define UNIQUE_SERIAL_ADDR 0x1FFFF7AC -#elif defined(STM32L1) -#define UNIQUE_SERIAL_ADDR 0x1FF80050 -#else // STM32F1 -#define UNIQUE_SERIAL_ADDR 0x1FFFF7E8 -#endif - void fill_serialno_fixed(char *s) { uint8_t uuid[32]; - memcpy(uuid, (uint8_t *)UNIQUE_SERIAL_ADDR, 12); - memcpy(uuid + 12, (uint8_t *)UNIQUE_SERIAL_ADDR, 12); - memcpy(uuid + 24, (uint8_t *)UNIQUE_SERIAL_ADDR, 8); - sha256_Raw(uuid, 32, uuid); + desig_get_unique_id((uint32_t *)uuid); + sha256_Raw(uuid, 12, uuid); sha256_Raw(uuid, 32, uuid); data2hex(uuid, 12, s); } From e5bdf1943a271be084a84bb4dcffae02b7f4ecf7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 7 Aug 2014 20:56:56 +0200 Subject: [PATCH 0040/1154] align encryption of hdnode with mnemonic logic --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index ba6193531b..a2e95f83d5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -225,7 +225,7 @@ bool storage_getRootNode(HDNode *node) return false; } hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode); - if (storage.has_passphrase_protection && storage.passphrase_protection) { + if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) { // decrypt hd node uint8_t secret[64]; layoutProgressSwipe("Waking up", 0, 0); From 63c6d046d10ed9700426d882336f8c3fccd59b72 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 7 Aug 2014 21:53:55 +0200 Subject: [PATCH 0041/1154] add PublicKey.xpub field --- firmware/fsm.c | 3 ++- firmware/protob/messages.options | 2 ++ firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 7 +++++-- trezor-common | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 35aa7b30ac..383a2f5128 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -273,7 +273,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); - + resp->has_xpub = true; + hdnode_serialize_public(node, resp->xpub); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 6e2ffaf64c..c0c2c634c4 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -26,6 +26,8 @@ Entropy.entropy max_size:1024 GetPublicKey.address_n max_count:8 +PublicKey.xpub max_size:113 + GetAddress.address_n max_count:8 GetAddress.coin_name max_size:17 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 02f7617ddf..6c0097fd08 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -120,8 +120,9 @@ const pb_field_t GetPublicKey_fields[2] = { PB_LAST_FIELD }; -const pb_field_t PublicKey_fields[2] = { +const pb_field_t PublicKey_fields[3] = { PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index d296af26c2..234ea073b5 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -364,6 +364,8 @@ typedef struct _Ping { typedef struct _PublicKey { HDNodeType node; + bool has_xpub; + char xpub[113]; } PublicKey; typedef struct _RecoveryDevice { @@ -568,6 +570,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Ping_pin_protection_tag 3 #define Ping_passphrase_protection_tag 4 #define PublicKey_node_tag 1 +#define PublicKey_xpub_tag 2 #define RecoveryDevice_word_count_tag 1 #define RecoveryDevice_passphrase_protection_tag 2 #define RecoveryDevice_pin_protection_tag 3 @@ -621,7 +624,7 @@ extern const pb_field_t PassphraseAck_fields[2]; extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[2]; -extern const pb_field_t PublicKey_fields[2]; +extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[3]; extern const pb_field_t Address_fields[2]; extern const pb_field_t WipeDevice_fields[1]; @@ -671,7 +674,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define GetEntropy_size 6 #define Entropy_size 1027 #define GetPublicKey_size 48 -#define PublicKey_size (6 + HDNodeType_size) +#define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size 67 #define Address_size 37 #define WipeDevice_size 0 diff --git a/trezor-common b/trezor-common index fc98712da5..ce8e99465e 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit fc98712da5c260f3828dab703880eb5e9da00580 +Subproject commit ce8e99465ea1fbcbdc5e7b477cfdab73244a444d From e5d55967a0308dba7efd6ff5b83ac11db0351ba2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 8 Aug 2014 19:09:54 +0200 Subject: [PATCH 0042/1154] implement GetAddress.show_display --- .gitmodules | 3 ++ Makefile.include | 1 + firmware/Makefile | 4 ++- firmware/fsm.c | 9 ++++++ firmware/layout2.c | 53 +++++++++++++++++++++++++++++++++++ firmware/layout2.h | 1 + firmware/protob/messages.pb.c | 3 +- firmware/protob/messages.pb.h | 7 +++-- firmware/protob/types.pb.h | 3 +- trezor-common | 2 +- trezor-qrenc | 1 + 11 files changed, 81 insertions(+), 6 deletions(-) create mode 160000 trezor-qrenc diff --git a/.gitmodules b/.gitmodules index e029233140..97aef8fa1c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "trezor-common"] path = trezor-common url = https://github.com/trezor/trezor-common.git +[submodule "trezor-qrenc"] + path = trezor-qrenc + url = https://github.com/trezor/trezor-qrenc.git diff --git a/Makefile.include b/Makefile.include index 59b8e7de52..965c5388be 100644 --- a/Makefile.include +++ b/Makefile.include @@ -44,6 +44,7 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)/gen \ -I$(TOP_DIR)/trezor-crypto \ + -I$(TOP_DIR)/trezor-qrenc ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) diff --git a/firmware/Makefile b/firmware/Makefile index f5f5d6b21c..eff59afc2e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -35,6 +35,8 @@ OBJS += ../trezor-crypto/aeskey.o OBJS += ../trezor-crypto/aestab.o OBJS += ../trezor-crypto/aes_modes.o +OBJS += ../trezor-qrenc/qr_encode.o + OBJS += protob/pb_decode.o OBJS += protob/pb_encode.o OBJS += protob/messages.pb.o @@ -43,9 +45,9 @@ OBJS += protob/types.pb.o include ../Makefile.include -# CFLAGS += -fstack-protector -fstack-protector-all CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 +CFLAGS += -DQR_MAX_VERSION=0 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' diff --git a/firmware/fsm.c b/firmware/fsm.c index 383a2f5128..8c1ecb6705 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -478,6 +478,15 @@ void fsm_msgGetAddress(GetAddress *msg) ecdsa_get_address(node->public_key, coin->address_type, resp->address); + if (msg->has_show_display && msg->show_display) { + layoutAddress(resp->address); + if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + layoutHome(); + return; + } + } + msg_write(MessageType_MessageType_Address, resp); layoutHome(); } diff --git a/firmware/layout2.c b/firmware/layout2.c index f5b48215a9..1e2ad5bb36 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -26,6 +26,7 @@ #include "bitmaps.h" #include "string.h" #include "util.h" +#include "qr_encode.h" void *layoutLast = layoutHome; @@ -251,3 +252,55 @@ void layoutCipherKeyValue(bool encrypt, const char *key) encrypt ? "Encrypt?" : "Decrypt?", str[0], str[1], str[2], str[3], NULL, NULL); } + +void layoutAddress(const char *address) +{ + oledSwipeLeft(); + layoutLast = layoutAddress; + + static unsigned char bitdata[QR_MAX_BITDATA]; + int a, i, j; + int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata); + + if (side > 0 && side <= 29) { + oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); + for (i = 0; i < side; i++) { + for (j = 0; j< side; j++) { + a = i * side + j; + if (bitdata[a / 8] & (1 << (7 - a % 8))) { + oledClearPixel(2 + i * 2, 2 + j * 2); + oledClearPixel(3 + i * 2, 2 + j * 2); + oledClearPixel(2 + i * 2, 3 + j * 2); + oledClearPixel(3 + i * 2, 3 + j * 2); + } + } + } + } + + int len = strlen(address); + char str[4][10]; + memset(str, 0, sizeof(str)); + + strlcpy(str[0], (char *)address, 10); + if (len > 9) { + strlcpy(str[1], (char *)address + 9, 10); + } + if (len > 18) { + strlcpy(str[2], (char *)address + 18, 10); + } + if (len > 27) { + strlcpy(str[3], (char *)address + 27, 10); + } + + oledDrawString(68, 0 * 9, str[0]); + oledDrawString(68, 1 * 9, str[1]); + oledDrawString(68, 2 * 9, str[2]); + oledDrawString(68, 3 * 9, str[3]); + + static const char *btnYes = "Continue"; + oledDrawString(OLED_WIDTH - fontCharWidth('}') - 1, OLED_HEIGHT - 8, "}"); + oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + + oledRefresh(); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index ffa2f93f22..9a836d3b7e 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -33,5 +33,6 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); +void layoutAddress(const char *address); #endif diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 6c0097fd08..629844fa54 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -126,9 +126,10 @@ const pb_field_t PublicKey_fields[3] = { PB_LAST_FIELD }; -const pb_field_t GetAddress_fields[3] = { +const pb_field_t GetAddress_fields[4] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 234ea073b5..3937da58d6 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -298,6 +298,8 @@ typedef struct _GetAddress { uint32_t address_n[8]; bool has_coin_name; char coin_name[17]; + bool has_show_display; + bool show_display; } GetAddress; typedef struct _GetEntropy { @@ -551,6 +553,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define FirmwareUpload_payload_tag 1 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 +#define GetAddress_show_display_tag 3 #define GetEntropy_size_tag 1 #define GetPublicKey_address_n_tag 1 #define LoadDevice_mnemonic_tag 1 @@ -625,7 +628,7 @@ extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[2]; extern const pb_field_t PublicKey_fields[3]; -extern const pb_field_t GetAddress_fields[3]; +extern const pb_field_t GetAddress_fields[4]; extern const pb_field_t Address_fields[2]; extern const pb_field_t WipeDevice_fields[1]; extern const pb_field_t LoadDevice_fields[8]; @@ -675,7 +678,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define Entropy_size 1027 #define GetPublicKey_size 48 #define PublicKey_size (121 + HDNodeType_size) -#define GetAddress_size 67 +#define GetAddress_size 69 #define Address_size 37 #define WipeDevice_size 0 #define LoadDevice_size (320 + HDNodeType_size) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index ac4756a446..8f532605cd 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -50,7 +50,8 @@ typedef enum _ButtonRequestType { ButtonRequestType_ButtonRequest_WipeDevice = 6, ButtonRequestType_ButtonRequest_ProtectCall = 7, ButtonRequestType_ButtonRequest_SignTx = 8, - ButtonRequestType_ButtonRequest_FirmwareCheck = 9 + ButtonRequestType_ButtonRequest_FirmwareCheck = 9, + ButtonRequestType_ButtonRequest_Address = 10 } ButtonRequestType; typedef enum _PinMatrixRequestType { diff --git a/trezor-common b/trezor-common index ce8e99465e..5bbe684c10 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit ce8e99465ea1fbcbdc5e7b477cfdab73244a444d +Subproject commit 5bbe684c1068bd9cb6d24b12da5e216feb74351d diff --git a/trezor-qrenc b/trezor-qrenc new file mode 160000 index 0000000000..dfcfd702be --- /dev/null +++ b/trezor-qrenc @@ -0,0 +1 @@ +Subproject commit dfcfd702be6d0c1bc3f035001fba20f5336f308b From ba63157a776d3d2884f19540ad2a0f672f908885 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Aug 2014 00:49:17 +0200 Subject: [PATCH 0043/1154] check coin->address_type while building output --- firmware/transaction.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/transaction.c b/firmware/transaction.c index 8aa4776bdd..69acabd732 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -106,6 +106,9 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (!ecdsa_address_decode(in->address, decoded)) { return 0; } + if (decoded[0] != coin->address_type) { + return 0; + } memcpy(out->script_pubkey.bytes + 3, decoded + 1, 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG @@ -120,6 +123,9 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (!ecdsa_address_decode(in->address, decoded)) { return 0; } + if (decoded[0] != 0x05) { // 0x05 is P2SH + return 0; + } memcpy(out->script_pubkey.bytes + 2, decoded + 1, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; From 5765fccc0d0c9e17c71c82f61bb25bcaa9fb96cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Aug 2014 10:46:12 +0200 Subject: [PATCH 0044/1154] update README --- README | 24 ------------------------ README.rst | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 24 deletions(-) delete mode 100644 README create mode 100644 README.rst diff --git a/README b/README deleted file mode 100644 index 10ae4f92c7..0000000000 --- a/README +++ /dev/null @@ -1,24 +0,0 @@ -TREZOR firmware - -http://bitcointrezor.com/ - -How to build Trezor firmware? -============================= -1. Install Docker (docker.com) -2. git clone https://github.com/trezor/trezor-mcu.git -3. cd trezor-mcu -4. sudo ./firmware-docker-build.sh (sudo may be needed on some distros because of Docker) - -This generates trezor.bin in current directory and prints sha256 fingerprint on last line of build log. - -How to get sha256 fingerprint of firmware signed and distributed by SatoshiLabs? -================================================================================ -1. Pick proper version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json -2. Download it: wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex -3. xxd -r -p trezor.signed.bin.hex trezor.signed.bin -4. ./firmware-fingerprint.sh trezor.signed.bin - -Step 4 should produce the same sha256 fingerprint like your local build. - -The reasoning behind "firmware-fingerprint.sh" is that signed firmware has special header holding signatures themselves, -which must be removed before calculating fingerprint. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000000..c12aa8303e --- /dev/null +++ b/README.rst @@ -0,0 +1,26 @@ +TREZOR Firmware +=============== + +http://bitcointrezor.com/ + +How to build Trezor firmware? +----------------------------- + +1. Install Docker (from docker.com or from your distribution repositories) +2. ``git clone https://github.com/trezor/trezor-mcu.git`` +3. ``cd trezor-mcu`` +4. ``./firmware-docker-build.sh`` + +This creates trezor.bin in current directory and prints its fingerprint at the last line of the build log. + +How to get fingerprint of firmware signed and distributed by SatoshiLabs? +------------------------------------------------------------------------- + +1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json +2. Download it: ``wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex`` +3. ``xxd -r -p trezor.signed.bin.hex trezor.signed.bin`` +4. ``./firmware-fingerprint.sh trezor.signed.bin`` + +Step 4 should produce the same sha256 fingerprint like your local build. + +The reasoning for ``firmware-fingerprint.sh`` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. From 8f1c40a933be08b487b57312330d1257d21717eb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 22 Oct 2014 19:53:25 +0200 Subject: [PATCH 0045/1154] start implementing EncryptMessage/DecryptMessage --- firmware/fsm.c | 55 ++++++++++++++++++++++++++++++++ firmware/fsm.h | 2 ++ firmware/messages.c | 2 ++ firmware/protob/messages.options | 7 ++++ firmware/protob/messages.pb.c | 11 ++++--- firmware/protob/messages.pb.h | 34 +++++++++++++++++--- trezor-common | 2 +- trezor-crypto | 2 +- trezor-qrenc | 2 +- 9 files changed, 104 insertions(+), 13 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 8c1ecb6705..b91f9faf7d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -554,6 +554,61 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) layoutHome(); } +void fsm_msgEncryptMessage(EncryptMessage *msg) +{ + if (!msg->has_pubkey) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); + return; + } + if (!msg->has_message) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); + return; + } + curve_point pubkey; + if ((msg->pubkey.size != 33 && msg->pubkey.size != 65) || ecdsa_read_pubkey(msg->pubkey.bytes, &pubkey) == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); + return; + } + + if (msg->address_n_count) { + if (!protectPin(true)) { + layoutHome(); + return; + } + HDNode *node = fsm_getRootNode(); + if (!node) return; + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + } + + // TODO + + layoutHome(); +} + +void fsm_msgDecryptMessage(DecryptMessage *msg) +{ + if (!msg->has_message) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); + return; + } + if (msg->message.size % 16) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Message length must be a multiple of 16"); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + HDNode *node = fsm_getRootNode(); + if (!node) return; + fsm_deriveKey(node, msg->address_n, msg->address_n_count); + + // TODO + + layoutHome(); +} + void fsm_msgEstimateTxSize(EstimateTxSize *msg) { RESP_INIT(TxSize); diff --git a/firmware/fsm.h b/firmware/fsm.h index a5fcced525..6b7bde8e39 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -49,6 +49,8 @@ void fsm_msgGetAddress(GetAddress *msg); void fsm_msgEntropyAck(EntropyAck *msg); void fsm_msgSignMessage(SignMessage *msg); void fsm_msgVerifyMessage(VerifyMessage *msg); +void fsm_msgEncryptMessage(EncryptMessage *msg); +void fsm_msgDecryptMessage(DecryptMessage *msg); //void fsm_msgPassphraseAck(PassphraseAck *msg); void fsm_msgEstimateTxSize(EstimateTxSize *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); diff --git a/firmware/messages.c b/firmware/messages.c index 4233ce8d4c..63b40080e9 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -61,6 +61,8 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *))fsm_msgEntropyAck}, {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, + {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, + {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, // {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck}, {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c0c2c634c4..3ead3da1c9 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -59,6 +59,13 @@ VerifyMessage.message max_size:256 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 +EncryptMessage.pubkey max_size:65 +EncryptMessage.message max_size:1024 +EncryptMessage.address_n max_count:8 + +DecryptMessage.address_n max_count:8 +DecryptMessage.message max_size:1024 + CipherKeyValue.address_n max_count:8 CipherKeyValue.key max_size:256 CipherKeyValue.value max_size:1024 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 629844fa54..5a1965a045 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -211,16 +211,17 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; -const pb_field_t EncryptMessage_fields[4] = { - PB_FIELD2( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EncryptMessage, pubkey, pubkey, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EncryptMessage, message, pubkey, 0), +const pb_field_t EncryptMessage_fields[5] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), + PB_FIELD2( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), PB_LAST_FIELD }; const pb_field_t DecryptMessage_fields[3] = { - PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, DecryptMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, DecryptMessage, message, address_n, 0), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, address_n, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 3937da58d6..2849fffe9b 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -196,16 +196,37 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DecryptMessage_message_t; + typedef struct _DecryptMessage { - pb_callback_t address_n; - pb_callback_t message; + size_t address_n_count; + uint32_t address_n[8]; + bool has_message; + DecryptMessage_message_t message; } DecryptMessage; +typedef struct { + size_t size; + uint8_t bytes[65]; +} EncryptMessage_pubkey_t; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EncryptMessage_message_t; + typedef struct _EncryptMessage { - pb_callback_t pubkey; - pb_callback_t message; + bool has_pubkey; + EncryptMessage_pubkey_t pubkey; + bool has_message; + EncryptMessage_message_t message; bool has_display_only; bool display_only; + size_t address_n_count; + uint32_t address_n[8]; } EncryptMessage; typedef struct { @@ -528,6 +549,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define EncryptMessage_pubkey_tag 1 #define EncryptMessage_message_tag 2 #define EncryptMessage_display_only_tag 3 +#define EncryptMessage_address_n_tag 4 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -641,7 +663,7 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; -extern const pb_field_t EncryptMessage_fields[4]; +extern const pb_field_t EncryptMessage_fields[5]; extern const pb_field_t DecryptMessage_fields[3]; extern const pb_field_t CipherKeyValue_fields[7]; extern const pb_field_t EstimateTxSize_fields[4]; @@ -691,6 +713,8 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 326 #define VerifyMessage_size 363 #define MessageSignature_size 104 +#define EncryptMessage_size 1144 +#define DecryptMessage_size 1075 #define CipherKeyValue_size 1340 #define EstimateTxSize_size 31 #define TxSize_size 6 diff --git a/trezor-common b/trezor-common index 5bbe684c10..e2dab40398 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 5bbe684c1068bd9cb6d24b12da5e216feb74351d +Subproject commit e2dab40398da63becf0e815c9fece141d2043d2e diff --git a/trezor-crypto b/trezor-crypto index ffd2d69dd6..ad8e618ed2 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit ffd2d69dd658bad0e78cad853f8b81f2cd3e4b05 +Subproject commit ad8e618ed28f4dca108461a9afdbbaadeb26746c diff --git a/trezor-qrenc b/trezor-qrenc index dfcfd702be..f12996741c 160000 --- a/trezor-qrenc +++ b/trezor-qrenc @@ -1 +1 @@ -Subproject commit dfcfd702be6d0c1bc3f035001fba20f5336f308b +Subproject commit f12996741ca0a73b09e324306c7e79755a84202c From 938e8a596607a4795512089b7e059ace32d5528a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 23 Oct 2014 18:09:41 +0200 Subject: [PATCH 0046/1154] bootloader source code --- .gitignore | 1 - bootloader/.gitignore | 9 + bootloader/Makefile | 23 ++ bootloader/bootloader.c | 132 ++++++++ bootloader/bootloader.h | 36 +++ bootloader/combine/prepare.py | 10 + bootloader/combine/write.sh | 2 + bootloader/firmware_align.py | 11 + bootloader/firmware_sign.py | 189 +++++++++++ bootloader/firmware_sign_split.py | 31 ++ bootloader/signatures.c | 66 ++++ bootloader/signatures.h | 25 ++ bootloader/usb.c | 518 ++++++++++++++++++++++++++++++ bootloader/usb.h | 26 ++ 14 files changed, 1078 insertions(+), 1 deletion(-) create mode 100644 bootloader/.gitignore create mode 100644 bootloader/Makefile create mode 100644 bootloader/bootloader.c create mode 100644 bootloader/bootloader.h create mode 100755 bootloader/combine/prepare.py create mode 100755 bootloader/combine/write.sh create mode 100755 bootloader/firmware_align.py create mode 100755 bootloader/firmware_sign.py create mode 100755 bootloader/firmware_sign_split.py create mode 100644 bootloader/signatures.c create mode 100644 bootloader/signatures.h create mode 100644 bootloader/usb.c create mode 100644 bootloader/usb.h diff --git a/.gitignore b/.gitignore index 3c2f91f893..e0baf9ab7d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ *.list *.srec *.log -bootloader diff --git a/bootloader/.gitignore b/bootloader/.gitignore new file mode 100644 index 0000000000..e0baf9ab7d --- /dev/null +++ b/bootloader/.gitignore @@ -0,0 +1,9 @@ +*.o +*.a +*.d +*.bin +*.elf +*.hex +*.list +*.srec +*.log diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000000..fd8703d390 --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,23 @@ +NAME = bootloader + +MCU_DIR=$(subst /bootloader,,$(PWD)) + +OBJS += bootloader.o +OBJS += signatures.o +OBJS += usb.o + +OBJS += $(MCU_DIR)/trezor-crypto/bignum.small.o +OBJS += $(MCU_DIR)/trezor-crypto/ecdsa.small.o +OBJS += $(MCU_DIR)/trezor-crypto/hmac.o +OBJS += $(MCU_DIR)/trezor-crypto/ripemd160.o +OBJS += $(MCU_DIR)/trezor-crypto/secp256k1.small.o +OBJS += $(MCU_DIR)/trezor-crypto/sha2.o + +CFLAGS += -DUSE_PRECOMPUTED_IV=0 +CFLAGS += -DUSE_PRECOMPUTED_CP=0 +CFLAGS += -DUSE_PUBKEY_VALIDATE=0 + +include $(MCU_DIR)/Makefile.include + +align: + ./firmware_align.py $(NAME).bin diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c new file mode 100644 index 0000000000..57bf5f9746 --- /dev/null +++ b/bootloader/bootloader.c @@ -0,0 +1,132 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include +#include +#include + +#include "bootloader.h" +#include "buttons.h" +#include "setup.h" +#include "usb.h" +#include "oled.h" +#include "util.h" +#include "signatures.h" +#include "layout.h" +#include "serialno.h" + +#ifdef APPVER +#error Bootloader cannot be used in app mode +#endif + +void show_unofficial_warning(void) +{ + layoutDialog(DIALOG_ICON_WARNING, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); + + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + + if (button.YesUp) { + return; // yes button was pressed -> return + } + + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + system_halt(); +} + +void load_app(void) +{ + // jump to app + SCB_VTOR = FLASH_APP_START; // & 0xFFFF; + asm volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); + (*(void (**)())(FLASH_APP_START + 4))(); +} + +void bootloader_loop(void) +{ + static char serial[25]; + + fill_serialno_fixed(serial); + + oledDrawBitmap(0, 0, &bmp_logo64); + oledDrawString(52, 0, "TREZOR"); + + oledDrawString(52, 20, "Serial No."); + oledDrawString(52, 40, serial + 12); // second part of serial + serial[12] = 0; + oledDrawString(52, 30, serial); // first part of serial + + oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "BLv" VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); + + oledRefresh(); + + usbInit(); + usbLoop(); +} + +void check_firmware_sanity(void) +{ + int broken = 0; + if (memcmp((void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match + broken++; + } + if (*((uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB + broken++; + } + if (*((uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size + broken++; + } + if (broken) { + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + system_halt(); + } +} + +int main(void) +{ + setup(); + memory_protect(); + oledInit(); + + // at least one button is unpressed + uint16_t state = gpio_port_read(BTN_PORT); + if ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO) { + + check_firmware_sanity(); + + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64_empty); + oledRefresh(); + + if (!signatures_ok()) { + show_unofficial_warning(); + } + + load_app(); + + } + + bootloader_loop(); + + return 0; +} diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h new file mode 100644 index 0000000000..3546d150d0 --- /dev/null +++ b/bootloader/bootloader.h @@ -0,0 +1,36 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __BOOTLOADER_H__ +#define __BOOTLOADER_H__ + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 2 +#define VERSION_PATCH 5 + +#define STR(X) #X +#define VERSTR(X) STR(X) + +#define VERSION_MAJOR_CHAR "\x01" +#define VERSION_MINOR_CHAR "\x02" +#define VERSION_PATCH_CHAR "\x05" + +#include "memory.h" + +#endif diff --git a/bootloader/combine/prepare.py b/bootloader/combine/prepare.py new file mode 100755 index 0000000000..491c3000f5 --- /dev/null +++ b/bootloader/combine/prepare.py @@ -0,0 +1,10 @@ +#!/usr/bin/python +bl = open('bl.bin').read() +fw = open('fw.bin').read() +combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:] + +open('combined.bin', 'w').write(combined) + +print 'bootloader : %d bytes' % len(bl) +print 'firmware : %d bytes' % len(fw) +print 'combined : %d bytes' % len(combined) diff --git a/bootloader/combine/write.sh b/bootloader/combine/write.sh new file mode 100755 index 0000000000..6854ee6008 --- /dev/null +++ b/bootloader/combine/write.sh @@ -0,0 +1,2 @@ +#!/bin/bash +st-flash write combined.bin 0x8000000 diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py new file mode 100755 index 0000000000..6a2788c9dd --- /dev/null +++ b/bootloader/firmware_align.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +import sys +import os + +fn = sys.argv[1] +fs = os.stat(fn).st_size +if fs > 32768: + raise Exception('bootloader has to be smaller than 32768 bytes') +with open(fn, 'ab') as f: + f.write(os.urandom(32768 - fs)) + f.close() diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py new file mode 100755 index 0000000000..152f92ed57 --- /dev/null +++ b/bootloader/firmware_sign.py @@ -0,0 +1,189 @@ +#!/usr/bin/python +import argparse +import hashlib +import struct +import binascii +import ecdsa + +SLOTS = 3 + +pubkeys = { + 1: '04d571b7f148c5e4232c3814f777d8faeaf1a84216c78d569b71041ffc768a5b2d810fc3bb134dd026b57e65005275aedef43e155f48fc11a32ec790a93312bd58', + 2: '0463279c0c0866e50c05c799d32bd6bab0188b6de06536d1109d2ed9ce76cb335c490e55aee10cc901215132e853097d5432eda06b792073bd7740c94ce4516cb1', + 3: '0443aedbb6f7e71c563f8ed2ef64ec9981482519e7ef4f4aa98b27854e8c49126d4956d300ab45fdc34cd26bc8710de0a31dbdf6de7435fd0b492be70ac75fde58', + 4: '04877c39fd7c62237e038235e9c075dab261630f78eeb8edb92487159fffedfdf6046c6f8b881fa407c4a4ce6c28de0b19c1f4e29f1fcbc5a58ffd1432a3e0938a', + 5: '047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45', +} + +INDEXES_START = len('TRZR') + struct.calcsize(' SLOTS: + raise Exception("Invalid slot") + + if is_pem: + print "Paste ECDSA private key in PEM format and press Enter:" + print "(blank private key removes the signature on given index)" + pem_key = '' + while True: + key = raw_input() + pem_key += key + "\n" + if key == '': + break + if pem_key.strip() == '': + # Blank key,let's remove existing signature from slot + return modify(data, slot, 0, '\x00' * 64) + key = ecdsa.SigningKey.from_pem(pem_key) + else: + print "Paste SECEXP (in hex) and press Enter:" + print "(blank private key removes the signature on given index)" + secexp = raw_input() + if secexp.strip() == '': + # Blank key,let's remove existing signature from slot + return modify(data, slot, 0, '\x00' * 64) + key = ecdsa.SigningKey.from_secret_exponent(secexp = int(secexp, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256) + + to_sign = prepare(data)[256:] # without meta + + # Locate proper index of current signing key + pubkey = '04' + binascii.hexlify(key.get_verifying_key().to_string()) + index = None + for i, pk in pubkeys.iteritems(): + if pk == pubkey: + index = i + break + + if index == None: + raise Exception("Unable to find private key index. Unknown private key?") + + signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256) + + return modify(data, slot, index, signature) + +def main(args): + if args.generate: + key = ecdsa.SigningKey.generate( + curve=ecdsa.curves.SECP256k1, + hashfunc=hashlib.sha256) + + print "PRIVATE KEY (SECEXP):" + print binascii.hexlify(key.to_string()) + print + + print "PRIVATE KEY (PEM):" + print key.to_pem() + + print "PUBLIC KEY:" + print '04' + binascii.hexlify(key.get_verifying_key().to_string()) + return + + if not args.path: + raise Exception("-f/--file is required") + + data = open(args.path, 'rb').read() + assert len(data) % 4 == 0 + + if data[:4] != 'TRZR': + print "Metadata has been added..." + data = prepare(data) + + if data[:4] != 'TRZR': + raise Exception("Firmware header expected") + + print "Firmware size %d bytes" % len(data) + + check_signatures(data) + + if args.sign: + data = sign(data, args.pem) + check_signatures(data) + + fp = open(args.path, 'w') + fp.write(data) + fp.close() + +if __name__ == '__main__': + args = parse_args() + main(args) diff --git a/bootloader/firmware_sign_split.py b/bootloader/firmware_sign_split.py new file mode 100755 index 0000000000..3d72b968ba --- /dev/null +++ b/bootloader/firmware_sign_split.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import hashlib +import os +import subprocess +import ecdsa +from binascii import hexlify, unhexlify + +print 'master secret:', +h = raw_input() +if h: + h = unhexlify(h) +else: + h = hashlib.sha256(os.urandom(1024)).digest() + +print +print 'master secret:', hexlify(h) +print + +for i in range(1, 6): + se = hashlib.sha256(h + chr(i)).hexdigest() + print 'seckey', i, ':', se + sk = ecdsa.SigningKey.from_secret_exponent(secexp = int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256) + print 'pubkey', i, ':', '04' + hexlify(sk.get_verifying_key().to_string()) + print sk.to_pem() + +p = subprocess.Popen('ssss-split -t 3 -n 5 -x'.split(' '), stdin = subprocess.PIPE) +p.communicate(input = hexlify(h) + '\n') + +# to recover use: +# $ ssss-combine -t 3 -x diff --git a/bootloader/signatures.c b/bootloader/signatures.c new file mode 100644 index 0000000000..db9601b22f --- /dev/null +++ b/bootloader/signatures.c @@ -0,0 +1,66 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "signatures.h" +#include "ecdsa.h" +#include "bootloader.h" + +#define PUBKEYS 5 + +static const uint8_t *pubkey[PUBKEYS] = { + (uint8_t *)"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58", + (uint8_t *)"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1", + (uint8_t *)"\x04\x43\xae\xdb\xb6\xf7\xe7\x1c\x56\x3f\x8e\xd2\xef\x64\xec\x99\x81\x48\x25\x19\xe7\xef\x4f\x4a\xa9\x8b\x27\x85\x4e\x8c\x49\x12\x6d\x49\x56\xd3\x00\xab\x45\xfd\xc3\x4c\xd2\x6b\xc8\x71\x0d\xe0\xa3\x1d\xbd\xf6\xde\x74\x35\xfd\x0b\x49\x2b\xe7\x0a\xc7\x5f\xde\x58", + (uint8_t *)"\x04\x87\x7c\x39\xfd\x7c\x62\x23\x7e\x03\x82\x35\xe9\xc0\x75\xda\xb2\x61\x63\x0f\x78\xee\xb8\xed\xb9\x24\x87\x15\x9f\xff\xed\xfd\xf6\x04\x6c\x6f\x8b\x88\x1f\xa4\x07\xc4\xa4\xce\x6c\x28\xde\x0b\x19\xc1\xf4\xe2\x9f\x1f\xcb\xc5\xa5\x8f\xfd\x14\x32\xa3\xe0\x93\x8a", + (uint8_t *)"\x04\x73\x84\xc5\x1a\xe8\x1a\xdd\x0a\x52\x3a\xdb\xb1\x86\xc9\x1b\x90\x6f\xfb\x64\xc2\xc7\x65\x80\x2b\xf2\x6d\xbd\x13\xbd\xf1\x2c\x31\x9e\x80\xc2\x21\x3a\x13\x6c\x8e\xe0\x3d\x78\x74\xfd\x22\xb7\x0d\x68\xe7\xde\xe4\x69\xde\xcf\xbb\xb5\x10\xee\x9a\x46\x0c\xda\x45", +}; + +#define SIGNATURES 3 + +int signatures_ok(void) +{ + uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); + uint8_t sigindex1, sigindex2, sigindex3; + + sigindex1 = *((uint8_t *)FLASH_META_SIGINDEX1); + sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2); + sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3); + + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return 0; // invalid index + if (sigindex2 < 1 || sigindex2 > PUBKEYS) return 0; // invalid index + if (sigindex3 < 1 || sigindex3 > PUBKEYS) return 0; // invalid index + + if (sigindex1 == sigindex2) return 0; // duplicate use + if (sigindex1 == sigindex3) return 0; // duplicate use + if (sigindex2 == sigindex3) return 0; // duplicate use + + if (ecdsa_verify(pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + return 0; + } + if (ecdsa_verify(pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + return 0; + } + if (ecdsa_verify(pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture + return 0; + } + + return 1; +} diff --git a/bootloader/signatures.h b/bootloader/signatures.h new file mode 100644 index 0000000000..e081be3520 --- /dev/null +++ b/bootloader/signatures.h @@ -0,0 +1,25 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SIGNATURES_H__ +#define __SIGNATURES_H__ + +int signatures_ok(void); + +#endif diff --git a/bootloader/usb.c b/bootloader/usb.c new file mode 100644 index 0000000000..1e36c95228 --- /dev/null +++ b/bootloader/usb.c @@ -0,0 +1,518 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + +#include + +#include "buttons.h" +#include "bootloader.h" +#include "oled.h" +#include "rng.h" +#include "usb.h" +#include "serialno.h" +#include "layout.h" +#include "util.h" +#include "signatures.h" +#include "sha2.h" + +static const struct usb_device_descriptor dev_descr = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x534c, + .idProduct = 0x0001, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* got via usbhid-dump from CP2110 */ +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, + 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, + 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, + 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, + 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, + 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, + 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, + 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, + 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, + 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, + 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, + 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, + 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, + 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, + 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, + 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, + 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, + 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, + 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, + 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, + 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, + 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, + 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, + 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, +}; + +static const struct { + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) hid_function = { + .hid_descriptor = { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + } +}; + +static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor hid_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = hid_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SatoshiLabs", + "TREZOR", + "", // empty serial +}; + +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + void (**complete)(usbd_device *, struct usb_setup_data *)) +{ + (void)complete; + (void)dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) return 0; + + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + + return 1; +} + +enum { + STATE_READY, + STATE_OPEN, + STATE_FLASHSTART, + STATE_FLASHING, + STATE_CHECK, + STATE_END, +}; + +static uint32_t flash_pos = 0, flash_len = 0; +static char flash_state = STATE_READY; +static uint8_t flash_anim = 0; +static uint16_t msg_id = 0xFFFF; +static uint32_t msg_size = 0; + +static uint8_t meta_backup[FLASH_META_LEN]; + +static void send_msg_success(usbd_device *dev) +{ + // send response: Success message (id 2), payload len 0 + while ( usbd_ep_write_packet(dev, 0x81, + "?##" // header + "\x00\x02" // msg_id + "\x00\x00\x00\x00" // payload_len + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} +} + +static void send_msg_failure(usbd_device *dev) +{ + // send response: Failure message (id 3), payload len 2 + // code = 99 (Failure_FirmwareError) + while ( usbd_ep_write_packet(dev, 0x81, + "?##" // header + "\x00\x03" // msg_id + "\x00\x00\x00\x02" // payload_len + "\x08\x63" // data + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} +} + +static void send_msg_features(usbd_device *dev) +{ + // send response: Features message (id 17), payload len 27 + // vendor = "bitcointrezor.com" + // major_version = VERSION_MAJOR + // minor_version = VERSION_MINOR + // patch_version = VERSION_PATCH + // bootloader_mode = True + while ( usbd_ep_write_packet(dev, 0x81, + "?##" // header + "\x00\x11" // msg_id + "\x00\x00\x00\x1b" // payload_len + "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} +} + +static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) +{ + // send response: ButtonRequest message (id 26), payload len 2 + // code = ButtonRequest_FirmwareCheck (9) + while ( usbd_ep_write_packet(dev, 0x81, + "?##" // header + "\x00\x1a" // msg_id + "\x00\x00\x00\x02" // payload_len + "\x08\x09" // data + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} +} + +static void hid_rx_callback(usbd_device *dev, uint8_t ep) +{ + (void)ep; + static uint8_t buf[64] __attribute__((aligned(4))); + uint8_t *p; + static uint8_t towrite[4] __attribute__((aligned(4))); + static int wi; + int i; + uint32_t *w; + static SHA256_CTX ctx; + + if ( usbd_ep_read_packet(dev, 0x02, buf, 64) != 64) return; + + if (flash_state == STATE_END) { + return; + } + + if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) { + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard + return; + } + // struct.unpack(">HL") => msg, size + msg_id = (buf[3] << 8) + buf[4]; + msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + } + + if (flash_state == STATE_READY || flash_state == STATE_OPEN) { + if (msg_id == 0x0000) { // Initialize message (id 0) + send_msg_features(dev); + flash_state = STATE_OPEN; + return; + } + if (msg_id == 0x0001) { // Ping message (id 1) + send_msg_success(dev); + return; + } + } + + if (flash_state == STATE_OPEN) { + if (msg_id == 0x0006) { // FirmwareErase message (id 6) + layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + if (button.YesUp) { + layoutProgress("INSTALLING ... Please wait", 0, 0); + // backup metadata + memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); + flash_unlock(); + // erase metadata area + for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // erase code area + for (i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_lock(); + send_msg_success(dev); + flash_state = STATE_FLASHSTART; + return; + } + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); + return; + } + return; + } + + if (flash_state == STATE_FLASHSTART) { + if (msg_id == 0x0007) { // FirmwareUpload message (id 7) + if (buf[9] != 0x0a) { // invalid contents + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + return; + } + // read payload length + p = buf + 10; + flash_len = readprotobufint(&p); + if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL); + return; + } + sha256_Init(&ctx); + flash_state = STATE_FLASHING; + flash_pos = 0; + wi = 0; + flash_unlock(); + while (p < buf + 64) { + towrite[wi] = *p; + wi++; + if (wi == 4) { + w = (uint32_t *)towrite; + flash_program_word(FLASH_META_START + flash_pos, *w); + flash_pos += 4; + wi = 0; + } + p++; + } + flash_lock(); + return; + } + return; + } + + if (flash_state == STATE_FLASHING) { + if (buf[0] != '?') { // invalid contents + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + return; + } + p = buf + 1; + layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len, flash_anim / 8); + flash_anim++; + flash_unlock(); + while (p < buf + 64 && flash_pos < flash_len) { + towrite[wi] = *p; + wi++; + if (wi == 4) { + w = (uint32_t *)towrite; + if (flash_pos < FLASH_META_DESC_LEN) { + flash_program_word(FLASH_META_START + flash_pos, *w); // the first 256 bytes of firmware is metadata descriptor + } else { + flash_program_word(FLASH_APP_START + (flash_pos - FLASH_META_DESC_LEN), *w); // the rest is code + sha256_Update(&ctx, towrite, 4); + } + flash_pos += 4; + wi = 0; + } + p++; + } + flash_lock(); + // flashing done + if (flash_pos == flash_len) { + flash_state = STATE_CHECK; + send_msg_buttonrequest_firmwarecheck(dev); + } + return; + } + + if (flash_state == STATE_CHECK) { + if (msg_id != 0x001B) { // ButtonAck message (id 27) + return; + } + char digest[64]; + sha256_End(&ctx, digest); + char str[4][17]; + strlcpy(str[0], digest, 17); + strlcpy(str[1], digest + 16, 17); + strlcpy(str[2], digest + 32, 17); + strlcpy(str[3], digest + 48, 17); + layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); + + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + + bool hash_check_ok = button.YesUp; + + layoutProgress("INSTALLING ... Please wait", 1000, 0); + uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); + // check if to restore old storage area but only if signatures are ok + if ((flags & 0x01) && signatures_ok()) { + // copy new stuff + memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); + // replace "TRZR" in header with 0000 when hash not confirmed + if (!hash_check_ok) { + meta_backup[0] = 0; + meta_backup[1] = 0; + meta_backup[2] = 0; + meta_backup[3] = 0; + } + flash_unlock(); + // erase storage + for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // copy it back + for (i = 0; i < FLASH_META_LEN / 4; i++) { + w = (uint32_t *)(meta_backup + i * 4); + flash_program_word(FLASH_META_START + i * 4, *w); + } + flash_lock(); + } else { + // replace "TRZR" in header with 0000 when hash not confirmed + if (!hash_check_ok) { + // no need to erase, because we are just erasing bits + flash_unlock(); + flash_program_word(FLASH_META_START, 0x00000000); + flash_lock(); + } + } + flash_state = STATE_END; + if (hash_check_ok) { + layoutDialog(DIALOG_ICON_OK, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); + send_msg_success(dev); + } else { + layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); + send_msg_failure(dev); + } + return; + } + +} + +static void hid_set_config(usbd_device *dev, uint16_t wValue) +{ + (void)wValue; + + usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + + usbd_register_control_callback( + dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + hid_control_request + ); +} + +static usbd_device *usbd_dev; +static uint8_t usbd_control_buffer[128]; + +void usbInit(void) +{ + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); +} + +void usbLoop(void) +{ + for (;;) { + usbd_poll(usbd_dev); + } +} diff --git a/bootloader/usb.h b/bootloader/usb.h new file mode 100644 index 0000000000..e054a488b5 --- /dev/null +++ b/bootloader/usb.h @@ -0,0 +1,26 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __USB_H__ +#define __USB_H__ + +void usbInit(void); +void usbLoop(void); + +#endif From 8b70713e2b42b719df93a8470b63f9f74621e8d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Oct 2014 00:51:28 +0100 Subject: [PATCH 0047/1154] update protobuf --- firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 4 +++- firmware/protob/messages.pb.h | 8 ++++++-- trezor-common | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 3ead3da1c9..2342ca2b8e 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -62,6 +62,7 @@ MessageSignature.signature max_size:65 EncryptMessage.pubkey max_size:65 EncryptMessage.message max_size:1024 EncryptMessage.address_n max_count:8 +EncryptMessage.coin_name max_size:17 DecryptMessage.address_n max_count:8 DecryptMessage.message max_size:1024 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 5a1965a045..1b51ed7241 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -9,6 +9,7 @@ const uint32_t ResetDevice_strength_default = 128u; const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; +const char EncryptMessage_coin_name_default[17] = "Bitcoin"; const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; const char SimpleSignTx_coin_name_default[17] = "Bitcoin"; @@ -211,11 +212,12 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; -const pb_field_t EncryptMessage_fields[5] = { +const pb_field_t EncryptMessage_fields[6] = { PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), PB_FIELD2( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 2849fffe9b..ac41e98498 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -227,6 +227,8 @@ typedef struct _EncryptMessage { bool display_only; size_t address_n_count; uint32_t address_n[8]; + bool has_coin_name; + char coin_name[17]; } EncryptMessage; typedef struct { @@ -513,6 +515,7 @@ extern const uint32_t ResetDevice_strength_default; extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; extern const char SignMessage_coin_name_default[17]; +extern const char EncryptMessage_coin_name_default[17]; extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const char SimpleSignTx_coin_name_default[17]; @@ -550,6 +553,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define EncryptMessage_message_tag 2 #define EncryptMessage_display_only_tag 3 #define EncryptMessage_address_n_tag 4 +#define EncryptMessage_coin_name_tag 5 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -663,7 +667,7 @@ extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; -extern const pb_field_t EncryptMessage_fields[5]; +extern const pb_field_t EncryptMessage_fields[6]; extern const pb_field_t DecryptMessage_fields[3]; extern const pb_field_t CipherKeyValue_fields[7]; extern const pb_field_t EstimateTxSize_fields[4]; @@ -713,7 +717,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 326 #define VerifyMessage_size 363 #define MessageSignature_size 104 -#define EncryptMessage_size 1144 +#define EncryptMessage_size 1163 #define DecryptMessage_size 1075 #define CipherKeyValue_size 1340 #define EstimateTxSize_size 31 diff --git a/trezor-common b/trezor-common index e2dab40398..71a02eb83d 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit e2dab40398da63becf0e815c9fece141d2043d2e +Subproject commit 71a02eb83dfa4a5f0543743bc8fcfbd74fc0b7d0 From c051dfde9d7c96532a7fe75174e0c076e7c0ce4c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Oct 2014 01:38:40 +0100 Subject: [PATCH 0048/1154] update trezor-crypto --- demo/demo.c | 2 +- firmware/storage.c | 2 +- trezor-crypto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index ff3b9b7f0a..0682e7ca7b 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -265,7 +265,7 @@ int main(void) switch (state) { case 1: layoutProgress("WORKING", frame % 41 * 25, frame % 4); - pbkdf2(pass, passlen, salt, saltlen, 100, seed, 64, NULL); + pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64, NULL); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); break; } diff --git a/firmware/storage.c b/firmware/storage.c index a2e95f83d5..7524741214 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -229,7 +229,7 @@ bool storage_getRootNode(HDNode *node) // decrypt hd node uint8_t secret[64]; layoutProgressSwipe("Waking up", 0, 0); - pbkdf2((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (uint8_t *)"TREZORHD", 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); + pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (uint8_t *)"TREZORHD", 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); aes_cbc_decrypt(sessionRootNode.chain_code, sessionRootNode.chain_code, 32, secret + 32, &ctx); diff --git a/trezor-crypto b/trezor-crypto index ad8e618ed2..f6560c7d13 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit ad8e618ed28f4dca108461a9afdbbaadeb26746c +Subproject commit f6560c7d1303a50d215cffab87acc7fc8c8964a4 From 58ecfdcab0a2653be32a9d9895d815380ce4f84f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Oct 2014 17:57:33 +0100 Subject: [PATCH 0049/1154] use stack protector in bootloader --- bootloader/bootloader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 57bf5f9746..065b83a097 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -32,6 +32,7 @@ #include "signatures.h" #include "layout.h" #include "serialno.h" +#include "rng.h" #ifdef APPVER #error Bootloader cannot be used in app mode @@ -102,8 +103,17 @@ void check_firmware_sanity(void) } } +uint32_t __stack_chk_guard; + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever +} + int main(void) { + __stack_chk_guard = random32(); setup(); memory_protect(); oledInit(); From 960c665aac474aa972857892e91390aec76a5686 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Nov 2014 19:17:14 +0100 Subject: [PATCH 0050/1154] update protobuf, require address for verifymsg --- firmware/Makefile | 1 + firmware/protob/messages.options | 18 +- firmware/protob/messages.pb.c | 257 +++++++++++++------------ firmware/protob/messages.pb.h | 291 +++++++++++++++++++--------- firmware/protob/pb.h | 101 +++++----- firmware/protob/pb_common.c | 90 +++++++++ firmware/protob/pb_common.h | 42 +++++ firmware/protob/pb_decode.c | 315 +++++++++++++++---------------- firmware/protob/pb_decode.h | 6 +- firmware/protob/pb_encode.c | 55 +++--- firmware/protob/pb_encode.h | 6 +- firmware/protob/storage.pb.c | 28 +-- firmware/protob/storage.pb.h | 14 +- firmware/protob/types.pb.c | 90 ++++----- firmware/protob/types.pb.h | 99 +++++----- firmware/transaction.c | 18 +- trezor-common | 2 +- 17 files changed, 849 insertions(+), 584 deletions(-) create mode 100644 firmware/protob/pb_common.c create mode 100644 firmware/protob/pb_common.h diff --git a/firmware/Makefile b/firmware/Makefile index eff59afc2e..710c36f4dc 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -37,6 +37,7 @@ OBJS += ../trezor-crypto/aes_modes.o OBJS += ../trezor-qrenc/qr_encode.o +OBJS += protob/pb_common.o OBJS += protob/pb_decode.o OBJS += protob/pb_encode.o OBJS += protob/messages.pb.o diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 2342ca2b8e..cd887bb650 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -12,7 +12,6 @@ ApplySettings.label max_size:33 Ping.message max_size:256 Success.message max_size:256 -Success.payload max_size:1024 Failure.message max_size:256 @@ -49,12 +48,12 @@ RecoveryDevice.label max_size:33 WordAck.word max_size:12 SignMessage.address_n max_count:8 -SignMessage.message max_size:256 +SignMessage.message max_size:1024 SignMessage.coin_name max_size:17 VerifyMessage.address max_size:35 VerifyMessage.signature max_size:65 -VerifyMessage.message max_size:256 +VerifyMessage.message max_size:1024 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 @@ -64,13 +63,24 @@ EncryptMessage.message max_size:1024 EncryptMessage.address_n max_count:8 EncryptMessage.coin_name max_size:17 +EncryptedMessage.nonce max_size:33 +EncryptedMessage.message max_size:1120 +EncryptedMessage.hmac max_size:8 + DecryptMessage.address_n max_count:8 -DecryptMessage.message max_size:1024 +DecryptMessage.nonce max_size:33 +DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 +DecryptMessage.hmac max_size:8 + +DecryptedMessage.address max_size:35 +DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 CipherKeyValue.key max_size:256 CipherKeyValue.value max_size:1024 +CipheredKeyValue.value max_size:1024 + EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 1b51ed7241..72b7d04385 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -1,8 +1,12 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ #include "messages.pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + const char GetAddress_coin_name_default[17] = "Bitcoin"; const char LoadDevice_language_default[17] = "english"; const uint32_t ResetDevice_strength_default = 128u; @@ -20,21 +24,21 @@ const pb_field_t Initialize_fields[1] = { }; const pb_field_t Features_fields[16] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), - PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), - PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), - PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), - PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), - PB_FIELD2( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), - PB_FIELD2( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), - PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), - PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), - PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), - PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), + PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), + PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), + PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), + PB_FIELD( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), + PB_FIELD( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), + PB_FIELD( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), + PB_FIELD( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), + PB_FIELD( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), + PB_FIELD( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), + PB_FIELD( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), + PB_FIELD( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), PB_LAST_FIELD }; @@ -43,39 +47,38 @@ const pb_field_t ClearSession_fields[1] = { }; const pb_field_t ApplySettings_fields[3] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), PB_LAST_FIELD }; const pb_field_t ChangePin_fields[2] = { - PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), + PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), PB_LAST_FIELD }; const pb_field_t Ping_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), - PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), PB_LAST_FIELD }; -const pb_field_t Success_fields[3] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, Success, payload, message, 0), +const pb_field_t Success_fields[2] = { + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), PB_LAST_FIELD }; const pb_field_t Failure_fields[3] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), PB_LAST_FIELD }; const pb_field_t ButtonRequest_fields[3] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), PB_LAST_FIELD }; @@ -84,12 +87,12 @@ const pb_field_t ButtonAck_fields[1] = { }; const pb_field_t PinMatrixRequest_fields[2] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), PB_LAST_FIELD }; const pb_field_t PinMatrixAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), + PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), PB_LAST_FIELD }; @@ -102,40 +105,40 @@ const pb_field_t PassphraseRequest_fields[1] = { }; const pb_field_t PassphraseAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), + PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), PB_LAST_FIELD }; const pb_field_t GetEntropy_fields[2] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), PB_LAST_FIELD }; const pb_field_t Entropy_fields[2] = { - PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), + PB_FIELD( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), PB_LAST_FIELD }; const pb_field_t GetPublicKey_fields[2] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), PB_LAST_FIELD }; const pb_field_t PublicKey_fields[3] = { - PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), + PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), PB_LAST_FIELD }; const pb_field_t GetAddress_fields[4] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), PB_LAST_FIELD }; const pb_field_t Address_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), + PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), PB_LAST_FIELD }; @@ -144,23 +147,23 @@ const pb_field_t WipeDevice_fields[1] = { }; const pb_field_t LoadDevice_fields[8] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), - PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), + PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), + PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), + PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), PB_LAST_FIELD }; const pb_field_t ResetDevice_fields[7] = { - PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), + PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), + PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), + PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), PB_LAST_FIELD }; @@ -169,17 +172,17 @@ const pb_field_t EntropyRequest_fields[1] = { }; const pb_field_t EntropyAck_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), PB_LAST_FIELD }; const pb_field_t RecoveryDevice_fields[7] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), - PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), + PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), + PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), PB_LAST_FIELD }; @@ -188,91 +191,111 @@ const pb_field_t WordRequest_fields[1] = { }; const pb_field_t WordAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), + PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), PB_LAST_FIELD }; const pb_field_t SignMessage_fields[4] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), + PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), PB_LAST_FIELD }; const pb_field_t VerifyMessage_fields[4] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), PB_LAST_FIELD }; const pb_field_t MessageSignature_fields[3] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), PB_LAST_FIELD }; const pb_field_t EncryptMessage_fields[6] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), - PB_FIELD2( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), + PB_FIELD( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), + PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), PB_LAST_FIELD }; -const pb_field_t DecryptMessage_fields[3] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, address_n, 0), +const pb_field_t EncryptedMessage_fields[4] = { + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptedMessage, nonce, nonce, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, message, nonce, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, hmac, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptMessage_fields[5] = { + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, nonce, address_n, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, nonce, 0), + PB_FIELD( 4, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, hmac, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t DecryptedMessage_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, DecryptedMessage, message, message, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptedMessage, address, message, 0), PB_LAST_FIELD }; const pb_field_t CipherKeyValue_fields[7] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), - PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), + PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), + PB_LAST_FIELD +}; + +const pb_field_t CipheredKeyValue_fields[2] = { + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, CipheredKeyValue, value, value, 0), PB_LAST_FIELD }; const pb_field_t EstimateTxSize_fields[4] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), PB_LAST_FIELD }; const pb_field_t TxSize_fields[2] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), PB_LAST_FIELD }; const pb_field_t SignTx_fields[4] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), PB_LAST_FIELD }; const pb_field_t SimpleSignTx_fields[5] = { - PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), - PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), - PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), + PB_FIELD( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), + PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), + PB_FIELD( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), + PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), PB_LAST_FIELD }; const pb_field_t TxRequest_fields[4] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), - PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), PB_LAST_FIELD }; const pb_field_t TxAck_fields[2] = { - PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), PB_LAST_FIELD }; @@ -281,12 +304,12 @@ const pb_field_t FirmwareErase_fields[1] = { }; const pb_field_t FirmwareUpload_fields[2] = { - PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), + PB_FIELD( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), PB_LAST_FIELD }; const pb_field_t DebugLinkDecision_fields[2] = { - PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), + PB_FIELD( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), PB_LAST_FIELD }; @@ -295,16 +318,16 @@ const pb_field_t DebugLinkGetState_fields[1] = { }; const pb_field_t DebugLinkState_fields[11] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), - PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), - PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), - PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), - PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), - PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), + PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), + PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), + PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), + PB_FIELD( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), + PB_FIELD( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), + PB_FIELD( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), + PB_FIELD( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), PB_LAST_FIELD }; @@ -313,9 +336,9 @@ const pb_field_t DebugLinkStop_fields[1] = { }; const pb_field_t DebugLinkLog_fields[4] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), PB_LAST_FIELD }; @@ -329,11 +352,11 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_DecryptMessage_CipherKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +PB_STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for Success.payload is too large. Define PB_FIELD_16BIT to fix this. +#error Field descriptor for EncryptedMessage.message is too large. Define PB_FIELD_16BIT to fix this. #endif diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index ac41e98498..41f70a2f51 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -1,11 +1,15 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ -#ifndef _PB_MESSAGES_PB_H_ -#define _PB_MESSAGES_PB_H_ +#ifndef PB_MESSAGES_PB_H_INCLUDED +#define PB_MESSAGES_PB_H_INCLUDED #include "pb.h" #include "types.pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + #ifdef __cplusplus extern "C" { #endif @@ -35,6 +39,7 @@ typedef enum _MessageType { MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, MessageType_MessageType_CipherKeyValue = 23, + MessageType_MessageType_CipheredKeyValue = 48, MessageType_MessageType_ClearSession = 24, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, @@ -46,8 +51,10 @@ typedef enum _MessageType { MessageType_MessageType_SignMessage = 38, MessageType_MessageType_VerifyMessage = 39, MessageType_MessageType_MessageSignature = 40, - MessageType_MessageType_EncryptMessage = 48, - MessageType_MessageType_DecryptMessage = 49, + MessageType_MessageType_EncryptMessage = 49, + MessageType_MessageType_EncryptedMessage = 50, + MessageType_MessageType_DecryptMessage = 51, + MessageType_MessageType_DecryptedMessage = 52, MessageType_MessageType_PassphraseRequest = 41, MessageType_MessageType_PassphraseAck = 42, MessageType_MessageType_EstimateTxSize = 43, @@ -130,13 +137,10 @@ typedef struct _ChangePin { bool remove; } ChangePin; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} CipherKeyValue_value_t; +typedef PB_BYTES_ARRAY_T(1024) CipherKeyValue_value_t; typedef struct _CipherKeyValue { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; bool has_key; char key[256]; @@ -150,6 +154,13 @@ typedef struct _CipherKeyValue { bool ask_on_decrypt; } CipherKeyValue; +typedef PB_BYTES_ARRAY_T(1024) CipheredKeyValue_value_t; + +typedef struct _CipheredKeyValue { + bool has_value; + CipheredKeyValue_value_t value; +} CipheredKeyValue; + typedef struct _DebugLinkDecision { bool yes_no; } DebugLinkDecision; @@ -163,15 +174,9 @@ typedef struct _DebugLinkLog { char text[256]; } DebugLinkLog; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DebugLinkState_layout_t; +typedef PB_BYTES_ARRAY_T(1024) DebugLinkState_layout_t; -typedef struct { - size_t size; - uint8_t bytes[128]; -} DebugLinkState_reset_entropy_t; +typedef PB_BYTES_ARRAY_T(128) DebugLinkState_reset_entropy_t; typedef struct _DebugLinkState { bool has_layout; @@ -196,27 +201,35 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DecryptMessage_message_t; +typedef PB_BYTES_ARRAY_T(33) DecryptMessage_nonce_t; + +typedef PB_BYTES_ARRAY_T(1120) DecryptMessage_message_t; + +typedef PB_BYTES_ARRAY_T(8) DecryptMessage_hmac_t; typedef struct _DecryptMessage { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; + bool has_nonce; + DecryptMessage_nonce_t nonce; bool has_message; DecryptMessage_message_t message; + bool has_hmac; + DecryptMessage_hmac_t hmac; } DecryptMessage; -typedef struct { - size_t size; - uint8_t bytes[65]; -} EncryptMessage_pubkey_t; +typedef PB_BYTES_ARRAY_T(1024) DecryptedMessage_message_t; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EncryptMessage_message_t; +typedef struct _DecryptedMessage { + bool has_message; + DecryptedMessage_message_t message; + bool has_address; + char address[35]; +} DecryptedMessage; + +typedef PB_BYTES_ARRAY_T(65) EncryptMessage_pubkey_t; + +typedef PB_BYTES_ARRAY_T(1024) EncryptMessage_message_t; typedef struct _EncryptMessage { bool has_pubkey; @@ -225,25 +238,34 @@ typedef struct _EncryptMessage { EncryptMessage_message_t message; bool has_display_only; bool display_only; - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; bool has_coin_name; char coin_name[17]; } EncryptMessage; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} Entropy_entropy_t; +typedef PB_BYTES_ARRAY_T(33) EncryptedMessage_nonce_t; + +typedef PB_BYTES_ARRAY_T(1120) EncryptedMessage_message_t; + +typedef PB_BYTES_ARRAY_T(8) EncryptedMessage_hmac_t; + +typedef struct _EncryptedMessage { + bool has_nonce; + EncryptedMessage_nonce_t nonce; + bool has_message; + EncryptedMessage_message_t message; + bool has_hmac; + EncryptedMessage_hmac_t hmac; +} EncryptedMessage; + +typedef PB_BYTES_ARRAY_T(1024) Entropy_entropy_t; typedef struct _Entropy { Entropy_entropy_t entropy; } Entropy; -typedef struct { - size_t size; - uint8_t bytes[128]; -} EntropyAck_entropy_t; +typedef PB_BYTES_ARRAY_T(128) EntropyAck_entropy_t; typedef struct _EntropyAck { bool has_entropy; @@ -264,15 +286,9 @@ typedef struct _Failure { char message[256]; } Failure; -typedef struct { - size_t size; - uint8_t bytes[20]; -} Features_revision_t; +typedef PB_BYTES_ARRAY_T(20) Features_revision_t; -typedef struct { - size_t size; - uint8_t bytes[32]; -} Features_bootloader_hash_t; +typedef PB_BYTES_ARRAY_T(32) Features_bootloader_hash_t; typedef struct _Features { bool has_vendor; @@ -295,7 +311,7 @@ typedef struct _Features { char language[17]; bool has_label; char label[33]; - size_t coins_count; + pb_size_t coins_count; CoinType coins[4]; bool has_initialized; bool initialized; @@ -307,17 +323,14 @@ typedef struct _Features { bool imported; } Features; -typedef struct { - size_t size; - uint8_t bytes[0]; -} FirmwareUpload_payload_t; +typedef PB_BYTES_ARRAY_T(0) FirmwareUpload_payload_t; typedef struct _FirmwareUpload { FirmwareUpload_payload_t payload; } FirmwareUpload; typedef struct _GetAddress { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; bool has_coin_name; char coin_name[17]; @@ -330,7 +343,7 @@ typedef struct _GetEntropy { } GetEntropy; typedef struct _GetPublicKey { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; } GetPublicKey; @@ -351,10 +364,7 @@ typedef struct _LoadDevice { bool skip_checksum; } LoadDevice; -typedef struct { - size_t size; - uint8_t bytes[65]; -} MessageSignature_signature_t; +typedef PB_BYTES_ARRAY_T(65) MessageSignature_signature_t; typedef struct _MessageSignature { bool has_address; @@ -423,13 +433,10 @@ typedef struct _ResetDevice { char label[33]; } ResetDevice; -typedef struct { - size_t size; - uint8_t bytes[256]; -} SignMessage_message_t; +typedef PB_BYTES_ARRAY_T(1024) SignMessage_message_t; typedef struct _SignMessage { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; SignMessage_message_t message; bool has_coin_name; @@ -444,26 +451,19 @@ typedef struct _SignTx { } SignTx; typedef struct _SimpleSignTx { - size_t inputs_count; + pb_size_t inputs_count; TxInputType inputs[0]; - size_t outputs_count; + pb_size_t outputs_count; TxOutputType outputs[0]; - size_t transactions_count; + pb_size_t transactions_count; TransactionType transactions[0]; bool has_coin_name; char coin_name[17]; } SimpleSignTx; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} Success_payload_t; - typedef struct _Success { bool has_message; char message[256]; - bool has_payload; - Success_payload_t payload; } Success; typedef struct _TxAck { @@ -485,15 +485,9 @@ typedef struct _TxSize { uint32_t tx_size; } TxSize; -typedef struct { - size_t size; - uint8_t bytes[65]; -} VerifyMessage_signature_t; +typedef PB_BYTES_ARRAY_T(65) VerifyMessage_signature_t; -typedef struct { - size_t size; - uint8_t bytes[256]; -} VerifyMessage_message_t; +typedef PB_BYTES_ARRAY_T(1024) VerifyMessage_message_t; typedef struct _VerifyMessage { bool has_address; @@ -520,6 +514,110 @@ extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const char SimpleSignTx_coin_name_default[17]; +/* Initializer values for message structs */ +#define Initialize_init_default {0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define ClearSession_init_default {0} +#define ApplySettings_init_default {false, "", false, ""} +#define ChangePin_init_default {false, 0} +#define Ping_init_default {false, "", false, 0, false, 0, false, 0} +#define Success_init_default {false, ""} +#define Failure_init_default {false, (FailureType)0, false, ""} +#define ButtonRequest_init_default {false, (ButtonRequestType)0, false, ""} +#define ButtonAck_init_default {0} +#define PinMatrixRequest_init_default {false, (PinMatrixRequestType)0} +#define PinMatrixAck_init_default {""} +#define Cancel_init_default {0} +#define PassphraseRequest_init_default {0} +#define PassphraseAck_init_default {""} +#define GetEntropy_init_default {0} +#define Entropy_init_default {{0, {0}}} +#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define PublicKey_init_default {HDNodeType_init_default, false, ""} +#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0} +#define Address_init_default {""} +#define WipeDevice_init_default {0} +#define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} +#define ResetDevice_init_default {false, 0, false, 128u, false, 0, false, 0, false, "english", false, ""} +#define EntropyRequest_init_default {0} +#define EntropyAck_init_default {false, {0, {0}}} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0} +#define WordRequest_init_default {0} +#define WordAck_init_default {""} +#define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} +#define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}} +#define MessageSignature_init_default {false, "", false, {0, {0}}} +#define EncryptMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin"} +#define EncryptedMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define DecryptMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define DecryptedMessage_init_default {false, {0, {0}}, false, ""} +#define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0} +#define CipheredKeyValue_init_default {false, {0, {0}}} +#define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} +#define TxSize_init_default {false, 0} +#define SignTx_init_default {0, 0, false, "Bitcoin"} +#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin"} +#define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} +#define TxAck_init_default {false, TransactionType_init_default} +#define FirmwareErase_init_default {0} +#define FirmwareUpload_init_default {{0, {0}}} +#define DebugLinkDecision_init_default {0} +#define DebugLinkGetState_init_default {0} +#define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0} +#define DebugLinkStop_init_default {0} +#define DebugLinkLog_init_default {false, 0, false, "", false, ""} +#define Initialize_init_zero {0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define ClearSession_init_zero {0} +#define ApplySettings_init_zero {false, "", false, ""} +#define ChangePin_init_zero {false, 0} +#define Ping_init_zero {false, "", false, 0, false, 0, false, 0} +#define Success_init_zero {false, ""} +#define Failure_init_zero {false, (FailureType)0, false, ""} +#define ButtonRequest_init_zero {false, (ButtonRequestType)0, false, ""} +#define ButtonAck_init_zero {0} +#define PinMatrixRequest_init_zero {false, (PinMatrixRequestType)0} +#define PinMatrixAck_init_zero {""} +#define Cancel_init_zero {0} +#define PassphraseRequest_init_zero {0} +#define PassphraseAck_init_zero {""} +#define GetEntropy_init_zero {0} +#define Entropy_init_zero {{0, {0}}} +#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define PublicKey_init_zero {HDNodeType_init_zero, false, ""} +#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} +#define Address_init_zero {""} +#define WipeDevice_init_zero {0} +#define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0} +#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, ""} +#define EntropyRequest_init_zero {0} +#define EntropyAck_init_zero {false, {0, {0}}} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0} +#define WordRequest_init_zero {0} +#define WordAck_init_zero {""} +#define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} +#define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} +#define MessageSignature_init_zero {false, "", false, {0, {0}}} +#define EncryptMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} +#define EncryptedMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define DecryptMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define DecryptedMessage_init_zero {false, {0, {0}}, false, ""} +#define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0} +#define CipheredKeyValue_init_zero {false, {0, {0}}} +#define EstimateTxSize_init_zero {0, 0, false, ""} +#define TxSize_init_zero {false, 0} +#define SignTx_init_zero {0, 0, false, ""} +#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""} +#define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} +#define TxAck_init_zero {false, TransactionType_init_zero} +#define FirmwareErase_init_zero {0} +#define FirmwareUpload_init_zero {{0, {0}}} +#define DebugLinkDecision_init_zero {0} +#define DebugLinkGetState_init_zero {0} +#define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0} +#define DebugLinkStop_init_zero {0} +#define DebugLinkLog_init_zero {false, 0, false, "", false, ""} + /* Field tags (for use in manual encoding/decoding) */ #define Address_address_tag 1 #define ApplySettings_language_tag 1 @@ -533,6 +631,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define CipherKeyValue_encrypt_tag 4 #define CipherKeyValue_ask_on_encrypt_tag 5 #define CipherKeyValue_ask_on_decrypt_tag 6 +#define CipheredKeyValue_value_tag 1 #define DebugLinkDecision_yes_no_tag 1 #define DebugLinkLog_level_tag 1 #define DebugLinkLog_bucket_tag 2 @@ -548,12 +647,19 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 #define DecryptMessage_address_n_tag 1 -#define DecryptMessage_message_tag 2 +#define DecryptMessage_nonce_tag 2 +#define DecryptMessage_message_tag 3 +#define DecryptMessage_hmac_tag 4 +#define DecryptedMessage_message_tag 1 +#define DecryptedMessage_address_tag 2 #define EncryptMessage_pubkey_tag 1 #define EncryptMessage_message_tag 2 #define EncryptMessage_display_only_tag 3 #define EncryptMessage_address_n_tag 4 #define EncryptMessage_coin_name_tag 5 +#define EncryptedMessage_nonce_tag 1 +#define EncryptedMessage_message_tag 2 +#define EncryptedMessage_hmac_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -623,7 +729,6 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_transactions_tag 3 #define SimpleSignTx_coin_name_tag 4 #define Success_message_tag 1 -#define Success_payload_tag 2 #define TxAck_tx_tag 1 #define TxRequest_request_type_tag 1 #define TxRequest_details_tag 2 @@ -641,7 +746,7 @@ extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[3]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; -extern const pb_field_t Success_fields[3]; +extern const pb_field_t Success_fields[2]; extern const pb_field_t Failure_fields[3]; extern const pb_field_t ButtonRequest_fields[3]; extern const pb_field_t ButtonAck_fields[1]; @@ -668,8 +773,11 @@ extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[4]; extern const pb_field_t MessageSignature_fields[3]; extern const pb_field_t EncryptMessage_fields[6]; -extern const pb_field_t DecryptMessage_fields[3]; +extern const pb_field_t EncryptedMessage_fields[4]; +extern const pb_field_t DecryptMessage_fields[5]; +extern const pb_field_t DecryptedMessage_fields[3]; extern const pb_field_t CipherKeyValue_fields[7]; +extern const pb_field_t CipheredKeyValue_fields[2]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[4]; @@ -691,7 +799,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define ApplySettings_size 54 #define ChangePin_size 2 #define Ping_size 265 -#define Success_size 1286 +#define Success_size 259 #define Failure_size 265 #define ButtonRequest_size 265 #define ButtonAck_size 0 @@ -714,12 +822,15 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define RecoveryDevice_size 66 #define WordRequest_size 0 #define WordAck_size 14 -#define SignMessage_size 326 -#define VerifyMessage_size 363 +#define SignMessage_size 1094 +#define VerifyMessage_size 1131 #define MessageSignature_size 104 #define EncryptMessage_size 1163 -#define DecryptMessage_size 1075 +#define EncryptedMessage_size 1168 +#define DecryptMessage_size 1216 +#define DecryptedMessage_size 1064 #define CipherKeyValue_size 1340 +#define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 #define TxSize_size 6 #define SignTx_size 31 diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h index b5cb3ea4b9..34d14b0405 100644 --- a/firmware/protob/pb.h +++ b/firmware/protob/pb.h @@ -2,8 +2,8 @@ * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. */ -#ifndef _PB_H_ -#define _PB_H_ +#ifndef PB_H_INCLUDED +#define PB_H_INCLUDED /***************************************************************** * Nanopb compilation time options. You can change these here by * @@ -46,7 +46,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.2.7 +#define NANOPB_VERSION nanopb-0.3.1 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -80,8 +80,8 @@ # define PB_PACKED_STRUCT_START # define PB_PACKED_STRUCT_END # define pb_packed __attribute__((packed)) -#elif defined(__ICCARM__) - /* For IAR ARM compiler */ +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ # define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") # define PB_PACKED_STRUCT_END _Pragma("pack(pop)") # define pb_packed @@ -98,23 +98,27 @@ #endif /* Handly macro for suppressing unreferenced-parameter compiler warnings. */ -#ifndef UNUSED -#define UNUSED(x) (void)(x) +#ifndef PB_UNUSED +#define PB_UNUSED(x) (void)(x) #endif /* Compile-time assertion, used for checking compatible compilation options. - * If this does not work properly on your compiler, use #define STATIC_ASSERT - * to disable it. + * If this does not work properly on your compiler, use + * #define PB_NO_STATIC_ASSERT to disable it. * * But before doing that, check carefully the error message / place where it * comes from to see if the error has a real cause. Unfortunately the error * message is not always very clear to read, but you can see the reason better - * in the place where the STATIC_ASSERT macro was called. + * in the place where the PB_STATIC_ASSERT macro was called. */ -#ifndef STATIC_ASSERT -#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; -#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) -#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER +#ifndef PB_NO_STATIC_ASSERT +#ifndef PB_STATIC_ASSERT +#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#endif +#else +#define PB_STATIC_ASSERT(COND,MSG) #endif /* Number of required fields to keep track of. */ @@ -187,12 +191,15 @@ typedef uint8_t pb_type_t; * and array counts. */ #if defined(PB_FIELD_32BIT) +#define PB_SIZE_MAX ((uint32_t)-1) typedef uint32_t pb_size_t; typedef int32_t pb_ssize_t; #elif defined(PB_FIELD_16BIT) +#define PB_SIZE_MAX ((uint16_t)-1) typedef uint16_t pb_size_t; typedef int16_t pb_ssize_t; #else +#define PB_SIZE_MAX ((uint8_t)-1) typedef uint8_t pb_size_t; typedef int8_t pb_ssize_t; #endif @@ -206,8 +213,8 @@ typedef uint8_t pb_type_t; * PB_FIELD_32BIT. */ PB_PACKED_STRUCT_START -typedef struct _pb_field_t pb_field_t; -struct _pb_field_t { +typedef struct pb_field_s pb_field_t; +struct pb_field_s { pb_size_t tag; pb_type_t type; pb_size_t data_offset; /* Offset of field data, relative to previous field. */ @@ -228,27 +235,27 @@ PB_PACKED_STRUCT_END * If you get errors here, it probably means that your stdint.h is not * correct for your platform. */ -STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) /* This structure is used for 'bytes' arrays. * It has the number of bytes in the beginning, and after that an array. * Note that actual structs used will have a different length of bytes array. */ -#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; } +#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; } #define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) -struct _pb_bytes_array_t { - size_t size; +struct pb_bytes_array_s { + pb_size_t size; uint8_t bytes[1]; }; -typedef struct _pb_bytes_array_t pb_bytes_array_t; +typedef struct pb_bytes_array_s pb_bytes_array_t; /* This structure is used for giving the callback function. * It is stored in the message structure and filled in by the method that @@ -268,10 +275,10 @@ typedef struct _pb_bytes_array_t pb_bytes_array_t; * * The callback can be null if you want to skip a field. */ -typedef struct _pb_istream_t pb_istream_t; -typedef struct _pb_ostream_t pb_ostream_t; -typedef struct _pb_callback_t pb_callback_t; -struct _pb_callback_t { +typedef struct pb_istream_s pb_istream_t; +typedef struct pb_ostream_s pb_ostream_t; +typedef struct pb_callback_s pb_callback_t; +struct pb_callback_s { #ifdef PB_OLD_CALLBACK_STYLE /* Deprecated since nanopb-0.2.1 */ union { @@ -304,9 +311,9 @@ typedef enum { * if you want to catch all unknown fields, you can also create a custom * pb_extension_type_t with your own callback. */ -typedef struct _pb_extension_type_t pb_extension_type_t; -typedef struct _pb_extension_t pb_extension_t; -struct _pb_extension_type_t { +typedef struct pb_extension_type_s pb_extension_type_t; +typedef struct pb_extension_s pb_extension_t; +struct pb_extension_type_s { /* Called for each unknown field in the message. * If you handle the field, read off all of its data and return true. * If you do not handle the field, do not read anything and return true. @@ -328,7 +335,7 @@ struct _pb_extension_type_t { const void *arg; }; -struct _pb_extension_t { +struct pb_extension_s { /* Type describing the extension field. Usually you'll initialize * this to a pointer to the automatically generated structure. */ const pb_extension_type_t *type; @@ -358,6 +365,9 @@ struct _pb_extension_t { # endif #endif +/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ +#define PB_PROTO_HEADER_VERSION 30 + /* These macros are used to declare pb_field_t's in the constant array. */ /* Size of a structure member, in bytes. */ #define pb_membersize(st, m) (sizeof ((st*)0)->m) @@ -469,26 +479,15 @@ struct _pb_extension_t { * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION * - Field rules: REQUIRED, OPTIONAL or REPEATED * - Allocation: STATIC or CALLBACK + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. * - Message name * - Field name * - Previous field name (or field name again for first field) * - Pointer to default value or submsg fields. */ -#define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ - PB_DATAOFFSET_CHOOSE(message, field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) - -/* This is a new version of the macro used by nanopb generator from - * version 0.2.3 onwards. It avoids the use of a ternary expression in - * the initialization, which confused some compilers. - * - * - Placement: FIRST or OTHER, depending on if this is the first field in structure. - * - */ -#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ PB_DATAOFFSET_ ## placement(message, field, prevfield), \ PB_LTYPE_MAP_ ## type, ptr) @@ -502,7 +501,7 @@ struct _pb_extension_t { #ifdef PB_NO_ERRMSG #define PB_RETURN_ERROR(stream,msg) \ do {\ - UNUSED(stream); \ + PB_UNUSED(stream); \ return false; \ } while(0) #define PB_GET_ERROR(stream) "(errmsg disabled)" diff --git a/firmware/protob/pb_common.c b/firmware/protob/pb_common.c new file mode 100644 index 0000000000..a9cade6391 --- /dev/null +++ b/firmware/protob/pb_common.c @@ -0,0 +1,90 @@ +/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. + * + * 2014 Petteri Aimonen + */ + +#include "pb_common.h" + +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + + return (iter->pos->tag != 0); +} + +bool pb_field_iter_next(pb_field_iter_t *iter) +{ + const pb_field_t *prev_field = iter->pos; + + if (prev_field->tag == 0) + { + /* Handle empty message types, where the first field is already the terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) + { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } + else + { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) + { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) + { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void*); + } + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) + { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return true; + } +} + +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) +{ + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} + + diff --git a/firmware/protob/pb_common.h b/firmware/protob/pb_common.h new file mode 100644 index 0000000000..60b3d37491 --- /dev/null +++ b/firmware/protob/pb_common.h @@ -0,0 +1,42 @@ +/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. + * These functions are rarely needed by applications directly. + */ + +#ifndef PB_COMMON_H_INCLUDED +#define PB_COMMON_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Iterator for pb_field_t list */ +struct pb_field_iter_s { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ +}; +typedef struct pb_field_iter_s pb_field_iter_t; + +/* Initialize the field iterator structure to beginning. + * Returns false if the message type is empty. */ +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); + +/* Advance the iterator to the next field. + * Returns false when the iterator wraps back to the first field. */ +bool pb_field_iter_next(pb_field_iter_t *iter); + +/* Advance the iterator until it points at a field with the given tag. + * Returns false if no such field exists. */ +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c index 9a48c60fcd..d1efd1b516 100644 --- a/firmware/protob/pb_decode.c +++ b/firmware/protob/pb_decode.c @@ -15,36 +15,23 @@ #include "pb.h" #include "pb_decode.h" +#include "pb_common.h" /************************************** * Declarations internal to this file * **************************************/ -/* Iterator for pb_field_t list */ -typedef struct { - const pb_field_t *start; /* Start of the pb_field_t array */ - const pb_field_t *pos; /* Current position of the iterator */ - unsigned field_index; /* Zero-based index of the field. */ - unsigned required_field_index; /* Zero-based index that counts only the required fields */ - void *dest_struct; /* Pointer to the destination structure to decode to */ - void *pData; /* Pointer where to store current field value */ - void *pSize; /* Pointer where to store the size of current array field */ -} pb_field_iterator_t; - typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); -static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); -static bool pb_field_next(pb_field_iterator_t *iter); -static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn find_extension_field(pb_field_iterator_t *iter); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn find_extension_field(pb_field_iter_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); @@ -57,6 +44,11 @@ static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t static bool checkreturn pb_skip_varint(pb_istream_t *stream); static bool checkreturn pb_skip_string(pb_istream_t *stream); +#ifdef PB_ENABLE_MALLOC +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static void pb_release_single_field(const pb_field_iter_t *iter); +#endif + /* --- Function pointers to field decoders --- * Order in the array must match pb_action_t LTYPE numbering. */ @@ -338,75 +330,11 @@ void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) #endif } -static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) -{ - iter->start = iter->pos = fields; - iter->field_index = 0; - iter->required_field_index = 0; - iter->pData = (char*)dest_struct + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - iter->dest_struct = dest_struct; -} - -static bool pb_field_next(pb_field_iterator_t *iter) -{ - bool notwrapped = true; - size_t prev_size = iter->pos->data_size; - - if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && - PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) - { - prev_size *= iter->pos->array_size; - } - else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) - { - prev_size = sizeof(void*); - } - - if (iter->pos->tag == 0) - return false; /* Only happens with empty message types */ - - if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) - iter->required_field_index++; - - iter->pos++; - iter->field_index++; - if (iter->pos->tag == 0) - { - iter->pos = iter->start; - iter->field_index = 0; - iter->required_field_index = 0; - iter->pData = iter->dest_struct; - prev_size = 0; - notwrapped = false; - } - - iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - return notwrapped; -} - -static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) -{ - unsigned start = iter->field_index; - - do { - if (iter->pos->tag == tag && - PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) - { - return true; - } - (void)pb_field_next(iter); - } while (iter->field_index != start); - - return false; -} - /************************* * Decode a single field * *************************/ -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { pb_type_t type; pb_decoder_t func; @@ -429,7 +357,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t { /* Packed array */ bool status = true; - size_t *size = (size_t*)iter->pSize; + pb_size_t *size = (pb_size_t*)iter->pSize; pb_istream_t substream; if (!pb_make_string_substream(stream, &substream)) return false; @@ -454,7 +382,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t else { /* Repeated field */ - size_t *size = (size_t*)iter->pSize; + pb_size_t *size = (pb_size_t*)iter->pSize; void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); if (*size >= iter->pos->array_size) PB_RETURN_ERROR(stream, "array overflow"); @@ -470,16 +398,37 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t #ifdef PB_ENABLE_MALLOC /* Allocate storage for the field and store the pointer at iter->pData. - * array_size is the number of entries to reserve in an array. */ + * array_size is the number of entries to reserve in an array. + * Zero size is not allowed, use pb_free() for releasing. + */ static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) { void *ptr = *(void**)pData; - size_t size = array_size * data_size; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) + { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) + { + PB_RETURN_ERROR(stream, "size too large"); + } + } + } /* Allocate new or expand previous allocation */ /* Note: on failure the old pointer will remain in the structure, * the message must be freed by caller also on error return. */ - ptr = pb_realloc(ptr, size); + ptr = pb_realloc(ptr, array_size * data_size); if (ptr == NULL) PB_RETURN_ERROR(stream, "realloc failed"); @@ -488,7 +437,7 @@ static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t } /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ -static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) @@ -502,11 +451,11 @@ static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) } #endif -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { #ifndef PB_ENABLE_MALLOC - UNUSED(wire_type); - UNUSED(iter); + PB_UNUSED(wire_type); + PB_UNUSED(iter); PB_RETURN_ERROR(stream, "no malloc support"); #else pb_type_t type; @@ -519,6 +468,13 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { case PB_HTYPE_REQUIRED: case PB_HTYPE_OPTIONAL: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void**)iter->pData != NULL) + { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + if (PB_LTYPE(type) == PB_LTYPE_STRING || PB_LTYPE(type) == PB_LTYPE_BYTES) { @@ -539,7 +495,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { /* Packed array, multiple items come in at once. */ bool status = true; - size_t *size = (size_t*)iter->pSize; + pb_size_t *size = (pb_size_t*)iter->pSize; size_t allocated_size = *size; void *pItem; pb_istream_t substream; @@ -549,7 +505,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ while (substream.bytes_left) { - if (*size + 1 > allocated_size) + if ((size_t)*size + 1 > allocated_size) { /* Allocate more storage. This tries to guess the * number of remaining entries. Round the division @@ -571,6 +527,16 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ status = false; break; } + + if (*size == PB_SIZE_MAX) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = "too many array entries"; +#endif + status = false; + break; + } + (*size)++; } pb_close_string_substream(stream, &substream); @@ -580,9 +546,12 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ else { /* Normal repeated field, i.e. only one item at a time. */ - size_t *size = (size_t*)iter->pSize; + pb_size_t *size = (pb_size_t*)iter->pSize; void *pItem; + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + (*size)++; if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) return false; @@ -598,7 +567,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ #endif } -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { pb_callback_t *pCallback = (pb_callback_t*)iter->pData; @@ -645,7 +614,7 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type } } -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) { switch (PB_ATYPE(iter->pos->type)) { @@ -669,16 +638,15 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) { const pb_field_t *field = (const pb_field_t*)extension->type->arg; - pb_field_iterator_t iter; + pb_field_iter_t iter; if (field->tag != tag) return true; - iter.start = field; - iter.pos = field; - iter.field_index = 0; - iter.required_field_index = 0; - iter.dest_struct = extension->dest; + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + (void)pb_field_iter_begin(&iter, field, extension->dest); iter.pData = extension->dest; iter.pSize = &extension->found; @@ -688,7 +656,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, /* Try to decode an unknown field as an extension field. Tries each extension * decoder in turn, until one of them handles the field or loop ends. */ static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) + uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) { pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; @@ -713,15 +681,15 @@ static bool checkreturn decode_extension(pb_istream_t *stream, /* Step through the iterator until an extension field is found or until all * entries have been checked. There can be only one extension field per * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iterator_t *iter) +static bool checkreturn find_extension_field(pb_field_iter_t *iter) { - unsigned start = iter->field_index; + const pb_field_t *start = iter->pos; do { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) return true; - (void)pb_field_next(iter); - } while (iter->field_index != start); + (void)pb_field_iter_next(iter); + } while (iter->pos != start); return false; } @@ -729,17 +697,15 @@ static bool checkreturn find_extension_field(pb_field_iterator_t *iter) /* Initialize message fields to default values, recursively */ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) { - pb_field_iterator_t iter; - pb_field_init(&iter, fields, dest_struct); + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ do { pb_type_t type; type = iter.pos->type; - - /* Avoid crash on empty message types (zero fields) */ - if (iter.pos->tag == 0) - continue; if (PB_ATYPE(type) == PB_ATYPE_STATIC) { @@ -752,7 +718,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { /* Set array count to 0, no need to initialize contents. */ - *(size_t*)iter.pSize = 0; + *(pb_size_t*)iter.pSize = 0; continue; } @@ -780,14 +746,14 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str /* Initialize array count to 0. */ if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { - *(size_t*)iter.pSize = 0; + *(pb_size_t*)iter.pSize = 0; } } else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) { /* Don't overwrite callback */ } - } while (pb_field_next(&iter)); + } while (pb_field_iter_next(&iter)); } /********************* @@ -798,9 +764,11 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ { uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint32_t extension_range_start = 0; - pb_field_iterator_t iter; + pb_field_iter_t iter; - pb_field_init(&iter, fields, dest_struct); + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); while (stream->bytes_left) { @@ -816,7 +784,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ return false; } - if (!pb_field_find(&iter, tag)) + if (!pb_field_iter_find(&iter, tag)) { /* No match found, check if it matches an extension. */ if (tag >= extension_range_start) @@ -869,7 +837,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ do { req_field_count = iter.required_field_index; last_type = iter.pos->type; - } while (pb_field_next(&iter)); + } while (pb_field_iter_next(&iter)); /* Fixup if last field was also required. */ if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) @@ -918,58 +886,66 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * } #ifdef PB_ENABLE_MALLOC -void pb_release(const pb_field_t fields[], void *dest_struct) +static void pb_release_single_field(const pb_field_iter_t *iter) { - pb_field_iterator_t iter; - pb_field_init(&iter, fields, dest_struct); - - do + pb_type_t type; + type = iter->pos->type; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) { - pb_type_t type; - type = iter.pos->type; - - /* Avoid crash on empty message types (zero fields) */ - if (iter.pos->tag == 0) - continue; - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) { - if (PB_HTYPE(type) == PB_HTYPE_REPEATED && - (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES)) + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter->pData; + pb_size_t count = *(pb_size_t*)iter->pSize; + while (count--) { - /* Release entries in repeated string or bytes array */ - void **pItem = *(void***)iter.pData; - size_t count = *(size_t*)iter.pSize; - while (count--) - { - pb_free(*pItem); - *pItem++ = NULL; - } + pb_free(*pItem); + *pItem++ = NULL; } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + *(pb_size_t*)iter->pSize = 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessages */ + void *pItem = *(void**)iter->pData; + if (pItem) { - /* Release fields in submessages */ - void *pItem = *(void**)iter.pData; - size_t count = (pItem ? 1 : 0); + pb_size_t count = 1; if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { - count = *(size_t*)iter.pSize; + count = *(pb_size_t*)iter->pSize; + *(pb_size_t*)iter->pSize = 0; } while (count--) { - pb_release((const pb_field_t*)iter.pos->ptr, pItem); - pItem = (uint8_t*)pItem + iter.pos->data_size; + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter->pos->data_size; } } - - /* Release main item */ - pb_free(*(void**)iter.pData); - *(void**)iter.pData = NULL; } - } while (pb_field_next(&iter)); + + /* Release main item */ + pb_free(*(void**)iter->pData); + *(void**)iter->pData = NULL; + } +} + +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); } #endif @@ -1083,42 +1059,50 @@ static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *f static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) { - UNUSED(field); + PB_UNUSED(field); return pb_decode_fixed32(stream, dest); } static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) { - UNUSED(field); + PB_UNUSED(field); return pb_decode_fixed64(stream, dest); } static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) { uint32_t size; + size_t alloc_size; pb_bytes_array_t *bdest; if (!pb_decode_varint32(stream, &size)) return false; + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) + PB_RETURN_ERROR(stream, "size too large"); + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { #ifndef PB_ENABLE_MALLOC PB_RETURN_ERROR(stream, "no malloc support"); #else - if (!allocate_field(stream, dest, PB_BYTES_ARRAY_T_ALLOCSIZE(size), 1)) + if (!allocate_field(stream, dest, alloc_size, 1)) return false; bdest = *(pb_bytes_array_t**)dest; #endif } else { - if (PB_BYTES_ARRAY_T_ALLOCSIZE(size) > field->data_size) + if (alloc_size > field->data_size) PB_RETURN_ERROR(stream, "bytes overflow"); bdest = (pb_bytes_array_t*)dest; } - - bdest->size = size; + + bdest->size = (pb_size_t)size; return pb_read(stream, bdest->bytes, size); } @@ -1133,6 +1117,9 @@ static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *fi /* Space for null terminator */ alloc_size = size + 1; + if (alloc_size < size) + PB_RETURN_ERROR(stream, "size too large"); + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) { #ifndef PB_ENABLE_MALLOC diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h index 8dc67408a8..3d433155b8 100644 --- a/firmware/protob/pb_decode.h +++ b/firmware/protob/pb_decode.h @@ -3,8 +3,8 @@ * field descriptions created by nanopb_generator.py. */ -#ifndef _PB_DECODE_H_ -#define _PB_DECODE_H_ +#ifndef PB_DECODE_H_INCLUDED +#define PB_DECODE_H_INCLUDED #include "pb.h" @@ -25,7 +25,7 @@ extern "C" { * is different than from the main stream. Don't use bytes_left to compute * any pointers. */ -struct _pb_istream_t +struct pb_istream_s { #ifdef PB_BUFFER_ONLY /* Callback pointer is not used in buffer-only configuration. diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c index dc5a273493..cdd789555a 100644 --- a/firmware/protob/pb_encode.c +++ b/firmware/protob/pb_encode.c @@ -5,6 +5,7 @@ #include "pb.h" #include "pb_encode.h" +#include "pb_common.h" /* Use the GCC warn_unused_result attribute to check that all return values * are propagated correctly. On other compilers and gcc before 3.4.0 just @@ -245,7 +246,7 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream, break; case PB_HTYPE_REPEATED: - if (!encode_array(stream, field, pData, *(const size_t*)pSize, func)) + if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func)) return false; break; @@ -310,7 +311,7 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData) { const pb_extension_t *extension = *(const pb_extension_t* const *)pData; - UNUSED(field); + PB_UNUSED(field); while (extension) { @@ -333,42 +334,38 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream, * Encode all fields * *********************/ +static void *remove_const(const void *p) +{ + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) { - const pb_field_t *field = fields; - const void *pData = src_struct; - size_t prev_size = 0; + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct))) + return true; /* Empty message type */ - while (field->tag != 0) - { - pData = (const char*)pData + prev_size + field->data_offset; - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - prev_size = sizeof(const void*); - else - prev_size = field->data_size; - - /* Special case for static arrays */ - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_HTYPE(field->type) == PB_HTYPE_REPEATED) - { - prev_size *= field->array_size; - } - - if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION) + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) { /* Special case for the extension field placeholder */ - if (!encode_extension_field(stream, field, pData)) + if (!encode_extension_field(stream, iter.pos, iter.pData)) return false; } else { /* Regular field */ - if (!encode_field(stream, field, pData)) + if (!encode_field(stream, iter.pos, iter.pData)) return false; } - - field++; - } + } while (pb_field_iter_next(&iter)); return true; } @@ -602,13 +599,13 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - UNUSED(field); + PB_UNUSED(field); return pb_encode_fixed64(stream, src); } static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - UNUSED(field); + PB_UNUSED(field); return pb_encode_fixed32(stream, src); } @@ -633,7 +630,6 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - /* strnlen() is not always available, so just use a loop */ size_t size = 0; size_t max_size = field->data_size; const char *p = (const char*)src; @@ -647,6 +643,7 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi } else { + /* strnlen() is not always available, so just use a loop */ while (size < max_size && *p != '\0') { size++; diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h index f82bac8f86..e992c8dca1 100644 --- a/firmware/protob/pb_encode.h +++ b/firmware/protob/pb_encode.h @@ -3,8 +3,8 @@ * field descriptions created by nanopb_generator.py. */ -#ifndef _PB_ENCODE_H_ -#define _PB_ENCODE_H_ +#ifndef PB_ENCODE_H_INCLUDED +#define PB_ENCODE_H_INCLUDED #include "pb.h" @@ -24,7 +24,7 @@ extern "C" { * 4) Substreams will modify max_size and bytes_written. Don't use them * to calculate any pointers. */ -struct _pb_ostream_t +struct pb_ostream_s { #ifdef PB_BUFFER_ONLY /* Callback pointer is not used in buffer-only configuration. diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 7625797cf2..bd177d78e1 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -1,20 +1,24 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ #include "storage.pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + const pb_field_t Storage_fields[10] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), - PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), - PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), - PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), + PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), + PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), + PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), + PB_FIELD( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), + PB_FIELD( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), + PB_FIELD( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_LAST_FIELD }; @@ -28,7 +32,7 @@ const pb_field_t Storage_fields[10] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) +PB_STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -39,7 +43,7 @@ STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_3 * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) +PB_STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) #endif diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 1814c27c47..82d1ba0cf3 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -1,11 +1,15 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ -#ifndef _PB_STORAGE_PB_H_ -#define _PB_STORAGE_PB_H_ +#ifndef PB_STORAGE_PB_H_INCLUDED +#define PB_STORAGE_PB_H_INCLUDED #include "pb.h" #include "types.pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +38,10 @@ typedef struct _Storage { /* Default values for struct fields */ +/* Initializer values for message structs */ +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0} + /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 #define Storage_node_tag 2 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 1d9e61f172..66c417590d 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -1,82 +1,86 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ #include "types.pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + const uint32_t TxInputType_sequence_default = 4294967295u; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const pb_field_t HDNodeType_fields[7] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), - PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), - PB_FIELD2( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), - PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), - PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), + PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), + PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), + PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), + PB_FIELD( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), + PB_FIELD( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), + PB_FIELD( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), PB_LAST_FIELD }; const pb_field_t CoinType_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, 0), - PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), + PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, 0), + PB_FIELD( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), PB_LAST_FIELD }; const pb_field_t MultisigRedeemScriptType_fields[3] = { - PB_FIELD2( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), - PB_FIELD2( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_FIELD( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), + PB_FIELD( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), PB_LAST_FIELD }; const pb_field_t TxInputType_fields[8] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), - PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), - PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), - PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), + PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), + PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), + PB_FIELD( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_FIELD( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), + PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; const pb_field_t TxOutputType_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), - PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), - PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), - PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), + PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), + PB_FIELD( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), + PB_FIELD( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), + PB_FIELD( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), PB_LAST_FIELD }; const pb_field_t TxOutputBinType_fields[3] = { - PB_FIELD2( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), + PB_FIELD( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), + PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), PB_LAST_FIELD }; const pb_field_t TransactionType_fields[8] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), - PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), - PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), - PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), - PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), + PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), + PB_FIELD( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), + PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), + PB_FIELD( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), + PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), PB_LAST_FIELD }; const pb_field_t TxRequestDetailsType_fields[3] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), PB_LAST_FIELD }; const pb_field_t TxRequestSerializedType_fields[4] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), + PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), + PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), PB_LAST_FIELD }; @@ -85,7 +89,7 @@ typedef struct { } wire_in_struct; static const pb_field_t wire_in_field = - PB_FIELD2(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); + PB_FIELD(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); const pb_extension_type_t wire_in = { NULL, @@ -98,7 +102,7 @@ typedef struct { } wire_out_struct; static const pb_field_t wire_out_field = - PB_FIELD2(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); + PB_FIELD(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); const pb_extension_type_t wire_out = { NULL, @@ -111,7 +115,7 @@ typedef struct { } wire_debug_in_struct; static const pb_field_t wire_debug_in_field = - PB_FIELD2(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); + PB_FIELD(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); const pb_extension_type_t wire_debug_in = { NULL, @@ -124,7 +128,7 @@ typedef struct { } wire_debug_out_struct; static const pb_field_t wire_debug_out_field = - PB_FIELD2(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); + PB_FIELD(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); const pb_extension_type_t wire_debug_out = { NULL, @@ -142,7 +146,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +PB_STATIC_ASSERT((pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 8f532605cd..3b91af9293 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -1,9 +1,13 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.8 */ +/* Generated by nanopb-0.3.1 */ -#ifndef _PB_TYPES_PB_H_ -#define _PB_TYPES_PB_H_ +#ifndef PB_TYPES_PB_H_INCLUDED +#define PB_TYPES_PB_H_INCLUDED #include "pb.h" +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + #ifdef __cplusplus extern "C" { #endif @@ -72,20 +76,11 @@ typedef struct _CoinType { uint64_t maxfee_kb; } CoinType; -typedef struct { - size_t size; - uint8_t bytes[32]; -} HDNodeType_chain_code_t; +typedef PB_BYTES_ARRAY_T(32) HDNodeType_chain_code_t; -typedef struct { - size_t size; - uint8_t bytes[32]; -} HDNodeType_private_key_t; +typedef PB_BYTES_ARRAY_T(32) HDNodeType_private_key_t; -typedef struct { - size_t size; - uint8_t bytes[33]; -} HDNodeType_public_key_t; +typedef PB_BYTES_ARRAY_T(33) HDNodeType_public_key_t; typedef struct _HDNodeType { uint32_t depth; @@ -98,27 +93,18 @@ typedef struct _HDNodeType { HDNodeType_public_key_t public_key; } HDNodeType; -typedef struct { - size_t size; - uint8_t bytes[65]; -} MultisigRedeemScriptType_pubkeys_t; +typedef PB_BYTES_ARRAY_T(65) MultisigRedeemScriptType_pubkeys_t; -typedef struct { - size_t size; - uint8_t bytes[80]; -} MultisigRedeemScriptType_signatures_t; +typedef PB_BYTES_ARRAY_T(80) MultisigRedeemScriptType_signatures_t; typedef struct _MultisigRedeemScriptType { - size_t pubkeys_count; + pb_size_t pubkeys_count; MultisigRedeemScriptType_pubkeys_t pubkeys[5]; - size_t signatures_count; + pb_size_t signatures_count; MultisigRedeemScriptType_signatures_t signatures[4]; } MultisigRedeemScriptType; -typedef struct { - size_t size; - uint8_t bytes[520]; -} TxOutputBinType_script_pubkey_t; +typedef PB_BYTES_ARRAY_T(520) TxOutputBinType_script_pubkey_t; typedef struct _TxOutputBinType { uint64_t amount; @@ -128,16 +114,13 @@ typedef struct _TxOutputBinType { typedef struct _TxOutputType { bool has_address; char address[35]; - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; uint64_t amount; OutputScriptType script_type; } TxOutputType; -typedef struct { - size_t size; - uint8_t bytes[32]; -} TxRequestDetailsType_tx_hash_t; +typedef PB_BYTES_ARRAY_T(32) TxRequestDetailsType_tx_hash_t; typedef struct _TxRequestDetailsType { bool has_request_index; @@ -146,15 +129,9 @@ typedef struct _TxRequestDetailsType { TxRequestDetailsType_tx_hash_t tx_hash; } TxRequestDetailsType; -typedef struct { - size_t size; - uint8_t bytes[80]; -} TxRequestSerializedType_signature_t; +typedef PB_BYTES_ARRAY_T(80) TxRequestSerializedType_signature_t; -typedef struct { - size_t size; - uint8_t bytes[1024]; -} TxRequestSerializedType_serialized_tx_t; +typedef PB_BYTES_ARRAY_T(1024) TxRequestSerializedType_serialized_tx_t; typedef struct _TxRequestSerializedType { bool has_signature_index; @@ -165,18 +142,12 @@ typedef struct _TxRequestSerializedType { TxRequestSerializedType_serialized_tx_t serialized_tx; } TxRequestSerializedType; -typedef struct { - size_t size; - uint8_t bytes[32]; -} TxInputType_prev_hash_t; +typedef PB_BYTES_ARRAY_T(32) TxInputType_prev_hash_t; -typedef struct { - size_t size; - uint8_t bytes[520]; -} TxInputType_script_sig_t; +typedef PB_BYTES_ARRAY_T(520) TxInputType_script_sig_t; typedef struct _TxInputType { - size_t address_n_count; + pb_size_t address_n_count; uint32_t address_n[8]; TxInputType_prev_hash_t prev_hash; uint32_t prev_index; @@ -193,13 +164,13 @@ typedef struct _TxInputType { typedef struct _TransactionType { bool has_version; uint32_t version; - size_t inputs_count; + pb_size_t inputs_count; TxInputType inputs[1]; - size_t bin_outputs_count; + pb_size_t bin_outputs_count; TxOutputBinType bin_outputs[1]; bool has_lock_time; uint32_t lock_time; - size_t outputs_count; + pb_size_t outputs_count; TxOutputType outputs[1]; bool has_inputs_cnt; uint32_t inputs_cnt; @@ -217,6 +188,26 @@ extern const pb_extension_type_t wire_debug_out; extern const uint32_t TxInputType_sequence_default; extern const InputScriptType TxInputType_script_type_default; +/* Initializer values for message structs */ +#define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define CoinType_init_default {false, "", false, "", false, 0, false, 0} +#define MultisigRedeemScriptType_init_default {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}} +#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} +#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} +#define TxOutputBinType_init_default {0, {0, {0}}} +#define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} +#define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} +#define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} +#define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0} +#define MultisigRedeemScriptType_init_zero {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}} +#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} +#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} +#define TxOutputBinType_init_zero {0, {0, {0}}} +#define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} +#define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} +#define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}} + /* Field tags (for use in manual encoding/decoding) */ #define CoinType_coin_name_tag 1 #define CoinType_coin_shortcut_tag 2 diff --git a/firmware/transaction.c b/firmware/transaction.c index 69acabd732..bd02bb1cc2 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -372,16 +372,14 @@ bool transactionMessageVerify(uint8_t *message, uint32_t message_len, uint8_t *s pubkey[0] = 0x04; bn_write_be(&cp.x, pubkey + 1); bn_write_be(&cp.y, pubkey + 33); - // check if the address is correct when provided - if (address) { - ecdsa_address_decode(address, decoded); - if (compressed) { - pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); - } - ecdsa_get_address(pubkey, decoded[0], addr); - if (strcmp(addr, address) != 0) { - return false; - } + // check if the address is correct + ecdsa_address_decode(address, decoded); + if (compressed) { + pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); + } + ecdsa_get_address(pubkey, decoded[0], addr); + if (strcmp(addr, address) != 0) { + return false; } // check if signature verifies the digest if (ecdsa_verify_digest(pubkey, signature + 1, hash) != 0) { diff --git a/trezor-common b/trezor-common index 71a02eb83d..e675d5fd76 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 71a02eb83dfa4a5f0543743bc8fcfbd74fc0b7d0 +Subproject commit e675d5fd7684e437bb35fb24330234d43ee2e4db From f75515544fedd3138a66187772937ab6773346b7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Nov 2014 02:01:21 +0100 Subject: [PATCH 0051/1154] move Sign/Verify to crypto.c/h, implement Encrypt/Decrypt --- firmware/Makefile | 1 + firmware/crypto.c | 263 +++++++++++++++++++++++++++++++++++++++++ firmware/crypto.h | 41 +++++++ firmware/fsm.c | 112 ++++++++++++++---- firmware/layout2.c | 20 ++++ firmware/layout2.h | 2 + firmware/messages.c | 3 + firmware/transaction.c | 119 +------------------ firmware/transaction.h | 4 - trezor-crypto | 2 +- 10 files changed, 422 insertions(+), 145 deletions(-) create mode 100644 firmware/crypto.c create mode 100644 firmware/crypto.h diff --git a/firmware/Makefile b/firmware/Makefile index 710c36f4dc..5f97591157 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -15,6 +15,7 @@ OBJS += layout2.o OBJS += recovery.o OBJS += reset.o OBJS += signing.o +OBJS += crypto.o OBJS += debug.o diff --git a/firmware/crypto.c b/firmware/crypto.c new file mode 100644 index 0000000000..8aea82658e --- /dev/null +++ b/firmware/crypto.c @@ -0,0 +1,263 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include "crypto.h" +#include "sha2.h" +#include "ecdsa.h" +#include "pbkdf2.h" +#include "aes.h" +#include "hmac.h" + +uint32_t ser_length(uint32_t len, uint8_t *out) +{ + if (len < 253) { + out[0] = len & 0xFF; + return 1; + } + if (len < 0x10000) { + out[0] = 253; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + return 3; + } + out[0] = 254; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + out[3] = (len >> 16) & 0xFF; + out[4] = (len >> 24) & 0xFF; + return 5; +} + +uint32_t deser_length(const uint8_t *in, uint32_t *out) +{ + if (in[0] < 253) { + *out = in[0]; + return 1; + } + if (in[0] == 253) { + *out = in[1] + (in[2] << 8); + return 1 + 2; + } + if (in[0] == 254) { + *out = in[1] + (in[2] << 8) + (in[3] << 16) + (in[4] << 24); + return 1 + 4; + } + *out = 0; // ignore 64 bit + return 1 + 8; +} + +int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, const uint8_t *address_raw, uint8_t *signature) +{ + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + sha256_Update(&ctx, varint, l); + sha256_Update(&ctx, message, message_len); + uint8_t hash[32]; + sha256_Final(hash, &ctx); + sha256_Raw(hash, 32, hash); + ecdsa_sign_digest(privkey, hash, signature + 1); + uint8_t i; + for (i = 27 + 4; i < 27 + 4 + 4; i++) { + signature[0] = i; + if (cryptoMessageVerify(message, message_len, address_raw, signature) == 0) { + return 0; + } + } + return 1; +} + +int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature) +{ + bignum256 r, s, e; + curve_point cp, cp2; + SHA256_CTX ctx; + uint8_t pubkey[65], addr_raw[21], hash[32]; + + uint8_t nV = signature[0]; + if (nV < 27 || nV >= 35) { + return 1; + } + bool compressed; + compressed = (nV >= 31); + if (compressed) { + nV -= 4; + } + uint8_t recid = nV - 27; + // read r and s + bn_read_be(signature + 1, &r); + bn_read_be(signature + 33, &s); + // x = r + (recid / 2) * order + bn_zero(&cp.x); + uint8_t i; + for (i = 0; i < recid / 2; i++) { + bn_addmod(&cp.x, &order256k1, &prime256k1); + } + bn_addmod(&cp.x, &r, &prime256k1); + // compute y from x + uncompress_coords(recid % 2, &cp.x, &cp.y); + // calculate hash + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + sha256_Update(&ctx, varint, l); + sha256_Update(&ctx, message, message_len); + sha256_Final(hash, &ctx); + sha256_Raw(hash, 32, hash); + // e = -hash + bn_read_be(hash, &e); + bn_substract_noprime(&order256k1, &e, &e); + // r = r^-1 + bn_inverse(&r, &order256k1); + point_multiply(&s, &cp, &cp); + scalar_multiply(&e, &cp2); + point_add(&cp2, &cp); + point_multiply(&r, &cp, &cp); + pubkey[0] = 0x04; + bn_write_be(&cp.x, pubkey + 1); + bn_write_be(&cp.y, pubkey + 33); + // check if the address is correct + if (compressed) { + pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); + } + ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw); + if (memcmp(addr_raw, address_raw, 21) != 0) { + return 2; + } + // check if signature verifies the digest + if (ecdsa_verify_digest(pubkey, signature + 1, hash) != 0) { + return 3; + } + return 0; +} + +// internal from ecdsa.c +int generate_k_random(bignum256 *k); + +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_size, bool display_only, uint8_t *nonce, pb_size_t *nonce_len, uint8_t *payload, pb_size_t *payload_len, uint8_t *hmac, pb_size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) +{ + if (privkey && address_raw) { // signing == true + payload[0] = display_only ? 0x81 : 0x01; + uint32_t l = ser_length(msg_size, payload + 1); + memcpy(payload + 1 + l, msg, msg_size); + memcpy(payload + 1 + l + msg_size, address_raw, 21); + if (cryptoMessageSign(msg, msg_size, privkey, address_raw, payload + 1 + l + msg_size + 21) != 0) { + return 1; + } + *payload_len = 1 + l + msg_size + 21 + 65; + } else { + payload[0] = display_only ? 0x80 : 0x00; + uint32_t l = ser_length(msg_size, payload + 1); + memcpy(payload + 1 + l, msg, msg_size); + *payload_len = 1 + l + msg_size; + } + // generate random nonce + curve_point R; + bignum256 k; + if (generate_k_random(&k) != 0) { + return 2; + } + // compute k*G + scalar_multiply(&k, &R); + nonce[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, nonce + 1); + *nonce_len = 33; + // compute shared secret + point_multiply(&k, pubkey, &R); + uint8_t shared_secret[33]; + shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, shared_secret + 1); + // generate keying bytes + uint8_t keying_bytes[80]; + uint8_t salt[22 + 33 + 4]; + memcpy(salt, "Bitcoin Secure Message", 22); + memcpy(salt + 22, nonce, 33); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); + // encrypt payload + aes_encrypt_ctx ctx; + aes_encrypt_key256(keying_bytes, &ctx); + aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64, &ctx); + // compute hmac + uint8_t out[32]; + hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out); + memcpy(hmac, out, 8); + *hmac_len = 8; + + return 0; +} + +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) +{ + if (hmac_len != 8) { + return 1; + } + // compute shared secret + curve_point R; + bignum256 k; + bn_read_be(privkey, &k); + point_multiply(&k, nonce, &R); + uint8_t shared_secret[33]; + shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, shared_secret + 1); + // generate keying bytes + uint8_t keying_bytes[80]; + uint8_t salt[22 + 33 + 4]; + memcpy(salt, "Bitcoin Secure Message", 22); + salt[22] = 0x02 | (nonce->y.val[0] & 0x01); + bn_write_be(&(nonce->x), salt + 23); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); + // compute hmac + uint8_t out[32]; + hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); + if (memcmp(hmac, out, 8) != 0) { + return 2; + } + // decrypt payload + aes_encrypt_ctx ctx; + aes_encrypt_key256(keying_bytes, &ctx); + aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx); + // check first byte + if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && payload[0] != 0x81) { + return 3; + } + *signing = payload[0] & 0x01; + *display_only = payload[0] & 0x80; + uint32_t l, o; + l = deser_length(payload + 1, &o); + if (*signing) { + if (1 + l + o + 21 + 65 != payload_len) { + return 4; + } + if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) { + return 5; + } + memcpy(address_raw, payload + 1 + l + o, 21); + } else { + if (1 + l + o != payload_len) { + return 4; + } + } + memcpy(msg, payload + 1 + l, o); + *msg_len = o; + return 0; +} diff --git a/firmware/crypto.h b/firmware/crypto.h new file mode 100644 index 0000000000..603c52edc9 --- /dev/null +++ b/firmware/crypto.h @@ -0,0 +1,41 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __CRYPTO_H__ +#define __CRYPTO_H__ + +#include +#include +#include +#include +#include + +uint32_t ser_length(uint32_t len, uint8_t *out); + +int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, const uint8_t *address_raw, uint8_t *signature); + +int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature); + +// ECIES: http://memwallet.info/btcmssgs.html + +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_size, bool display_only, uint8_t *nonce, pb_size_t *nonce_len, uint8_t *payload, pb_size_t *payload_len, uint8_t *hmac, pb_size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); + +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); + +#endif diff --git a/firmware/fsm.c b/firmware/fsm.c index b91f9faf7d..d1f886fd1e 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -40,6 +40,8 @@ #include "signing.h" #include "aes.h" #include "hmac.h" +#include "crypto.h" +#include "base58.h" // message methods @@ -404,19 +406,19 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); - RESP_INIT(Success); + RESP_INIT(CipheredKeyValue); if (encrypt) { aes_encrypt_ctx ctx; aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); } else { aes_decrypt_ctx ctx; aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); } - resp->has_payload = true; - resp->payload.size = msg->value.size; - msg_write(MessageType_MessageType_Success, resp); + resp->has_value = true; + resp->value.size = msg->value.size; + msg_write(MessageType_MessageType_CipheredKeyValue, resp); layoutHome(); } @@ -526,10 +528,11 @@ void fsm_msgSignMessage(SignMessage *msg) } fsm_deriveKey(node, msg->address_n, msg->address_n_count); - - ecdsa_get_address(node->public_key, coin->address_type, resp->address); + uint8_t addr_raw[21]; + ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); + base58_encode_check(addr_raw, 21, resp->address); layoutProgressSwipe("Signing", 0, 0); - if (transactionMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->address, resp->signature.bytes)) { + if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, addr_raw, resp->signature.bytes) == 0) { resp->has_address = true; resp->has_signature = true; resp->signature.size = 65; @@ -542,9 +545,20 @@ void fsm_msgSignMessage(SignMessage *msg) void fsm_msgVerifyMessage(VerifyMessage *msg) { - const char *address = msg->has_address ? msg->address : 0; + if (!msg->has_address) { + fsm_sendFailure(FailureType_Failure_Other, "No address provided"); + return; + } + if (!msg->has_message) { + fsm_sendFailure(FailureType_Failure_Other, "No message provided"); + return; + } layoutProgressSwipe("Verifying", 0, 0); - if (msg->signature.size == 65 && transactionMessageVerify(msg->message.bytes, msg->message.size, msg->signature.bytes, address)) { + uint8_t addr_raw[21]; + if (!ecdsa_address_decode(msg->address, addr_raw)) { + fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); + } + if (msg->signature.size == 65 && cryptoMessageVerify(msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { layoutVerifyMessage(msg->message.bytes, msg->message.size); protectButton(ButtonRequestType_ButtonRequest_Other, true); fsm_sendSuccess("Message verified"); @@ -569,33 +583,65 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); return; } - - if (msg->address_n_count) { + bool display_only = msg->has_display_only && msg->display_only; + bool signing = msg->address_n_count > 0; + RESP_INIT(EncryptedMessage); + const CoinType *coin = 0; + HDNode *node = 0; + uint8_t address_raw[21]; + if (signing) { + coin = coinByName(msg->coin_name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + return; + } if (!protectPin(true)) { layoutHome(); return; } - HDNode *node = fsm_getRootNode(); + node = fsm_getRootNode(); if (!node) return; fsm_deriveKey(node, msg->address_n, msg->address_n_count); + hdnode_fill_public_key(node); + ecdsa_get_address_raw(node->public_key, coin->address_type, address_raw); } - - // TODO - + layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Encrypt message cancelled"); + layoutHome(); + return; + } + if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error encrypting message"); + layoutHome(); + return; + } + resp->has_nonce = true; + resp->has_message = true; + resp->has_hmac = true; + msg_write(MessageType_MessageType_EncryptedMessage, resp); layoutHome(); } void fsm_msgDecryptMessage(DecryptMessage *msg) { + if (!msg->has_nonce) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); + return; + } if (!msg->has_message) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); return; } - if (msg->message.size % 16) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Message length must be a multiple of 16"); + if (!msg->has_hmac) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided"); + return; + } + curve_point nonce_pubkey; + if (msg->nonce.size != 33 || ecdsa_read_pubkey(msg->nonce.bytes, &nonce_pubkey) == 0) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); return; } - if (!protectPin(true)) { layoutHome(); return; @@ -604,8 +650,30 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) if (!node) return; fsm_deriveKey(node, msg->address_n, msg->address_n_count); - // TODO - + RESP_INIT(DecryptedMessage); + bool display_only = false; + bool signing = false; + uint8_t address_raw[21]; + if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message"); + layoutHome(); + return; + } + if (signing) { + base58_encode_check(address_raw, 21, resp->address); + } + layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + if (display_only) { + resp->has_address = false; + resp->has_message = false; + memset(resp->address, sizeof(resp->address), 0); + memset(&(resp->message), sizeof(resp->message), 0); + } else { + resp->has_address = signing; + resp->has_message = true; + } + msg_write(MessageType_MessageType_DecryptedMessage, resp); layoutHome(); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 1e2ad5bb36..8b582d188d 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -304,3 +304,23 @@ void layoutAddress(const char *address) oledRefresh(); } + +void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) +{ + // TODO: finish + (void)msg; + (void)len; + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + signing ? "Encrypt message?" : "Encrypt+sign message?", + NULL, NULL, NULL, NULL, NULL, NULL); +} + +void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) +{ + // TODO: finish + (void)msg; + (void)len; + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", + address ? "Signed message contents" : "Message contents", + NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 9a836d3b7e..5fadb68e6a 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -34,5 +34,7 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutAddress(const char *address); +void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); +void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); #endif diff --git a/firmware/messages.c b/firmware/messages.c index 63b40080e9..0692ff5c07 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -75,10 +75,13 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'o', MessageType_MessageType_Features, Features_fields, 0}, {'n', 'o', MessageType_MessageType_PinMatrixRequest, PinMatrixRequest_fields, 0}, {'n', 'o', MessageType_MessageType_TxRequest, TxRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0}, {'n', 'o', MessageType_MessageType_ButtonRequest, ButtonRequest_fields, 0}, {'n', 'o', MessageType_MessageType_Address, Address_fields, 0}, {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, + {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, + {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, diff --git a/firmware/transaction.c b/firmware/transaction.c index bd02bb1cc2..fc3d6e1447 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -25,29 +25,9 @@ #include "debug.h" #include "protect.h" #include "layout2.h" +#include "crypto.h" #include "messages.pb.h" -// aux methods - -uint32_t ser_length(uint32_t len, uint8_t *out) { - if (len < 253) { - out[0] = len & 0xFF; - return 1; - } - if (len < 0x10000) { - out[0] = 253; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - return 3; - } - out[0] = 254; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - out[3] = (len >> 16) & 0xFF; - out[4] = (len >> 24) & 0xFF; - return 5; -} - uint32_t op_push(uint32_t i, uint8_t *out) { if (i < 0x4C) { out[0] = i & 0xFF; @@ -290,100 +270,3 @@ uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs) { return (transactionEstimateSize(inputs, outputs) + 999) / 1000; } - -bool transactionMessageSign(uint8_t *message, uint32_t message_len, uint8_t *privkey, const char *address, uint8_t *signature) -{ - if (message_len >= 256) { - return false; - } - - SHA256_CTX ctx; - uint8_t i, hash[32]; - - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); - i = message_len; - sha256_Update(&ctx, &i, 1); - sha256_Update(&ctx, message, message_len); - sha256_Final(hash, &ctx); - sha256_Raw(hash, 32, hash); - - ecdsa_sign_digest(privkey, hash, signature + 1); - for (i = 27 + 4; i < 27 + 4 + 4; i++) { - signature[0] = i; - if (transactionMessageVerify(message, message_len, signature, address)) { - return true; - } - } - - return false; -} - -bool transactionMessageVerify(uint8_t *message, uint32_t message_len, uint8_t *signature, const char *address) -{ - if (message_len >= 256) { - return false; - } - - bool compressed; - uint8_t nV = signature[0]; - bignum256 r, s, e; - curve_point cp, cp2; - SHA256_CTX ctx; - uint8_t i, pubkey[65], decoded[21], hash[32]; - char addr[35]; - - if (nV < 27 || nV >= 35) { - return false; - } - compressed = (nV >= 31); - if (compressed) { - nV -= 4; - } - uint8_t recid = nV - 27; - // read r and s - bn_read_be(signature + 1, &r); - bn_read_be(signature + 33, &s); - // x = r + (recid / 2) * order - bn_zero(&cp.x); - for (i = 0; i < recid / 2; i++) { - bn_addmod(&cp.x, &order256k1, &prime256k1); - } - bn_addmod(&cp.x, &r, &prime256k1); - // compute y from x - uncompress_coords(recid % 2, &cp.x, &cp.y); - // calculate hash - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); - i = message_len; - sha256_Update(&ctx, &i, 1); - sha256_Update(&ctx, message, message_len); - sha256_Final(hash, &ctx); - sha256_Raw(hash, 32, hash); - // e = -hash - bn_read_be(hash, &e); - bn_substract_noprime(&order256k1, &e, &e); - // r = r^-1 - bn_inverse(&r, &order256k1); - point_multiply(&s, &cp, &cp); - scalar_multiply(&e, &cp2); - point_add(&cp2, &cp); - point_multiply(&r, &cp, &cp); - pubkey[0] = 0x04; - bn_write_be(&cp.x, pubkey + 1); - bn_write_be(&cp.y, pubkey + 33); - // check if the address is correct - ecdsa_address_decode(address, decoded); - if (compressed) { - pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); - } - ecdsa_get_address(pubkey, decoded[0], addr); - if (strcmp(addr, address) != 0) { - return false; - } - // check if signature verifies the digest - if (ecdsa_verify_digest(pubkey, signature + 1, hash) != 0) { - return false; - } - return true; -} diff --git a/firmware/transaction.h b/firmware/transaction.h index 0939ea3637..2a2e098492 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -56,8 +56,4 @@ uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs); -bool transactionMessageSign(uint8_t *message, uint32_t message_len, uint8_t *privkey, const char *address, uint8_t *signature); - -bool transactionMessageVerify(uint8_t *message, uint32_t message_len, uint8_t *signature, const char *address); - #endif diff --git a/trezor-crypto b/trezor-crypto index f6560c7d13..9469a64a0a 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit f6560c7d1303a50d215cffab87acc7fc8c8964a4 +Subproject commit 9469a64a0a1ec032b829e7a1465d0e4b2996cd61 From 0c050e7fca31e71c28463d61e129a3477c27a118 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 26 Nov 2014 18:52:30 +0100 Subject: [PATCH 0052/1154] update layouts for message operations --- firmware/layout2.c | 110 ++++++++++++++------------------------------- firmware/layout2.h | 2 +- 2 files changed, 34 insertions(+), 78 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 8b582d188d..fb2c833f9a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -149,20 +149,20 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) ); } -void layoutSignMessage(const uint8_t *msg, uint32_t len) +// split longer message into 4 rows, 16 chars each +const char **prepare_message(const uint8_t *msg, uint32_t len) { - bool ascii = true; + bool binary = false; uint32_t i; for (i = 0; i < len; i++) { - if (msg[i] < 0x20 || msg[i] >= 0x80) { - ascii = false; + if (msg[i] < 0x20) { + binary = true; break; } } - - char str[4][17]; + static char str[4][17]; memset(str, 0, sizeof(str)); - if (ascii) { + if (!binary) { strlcpy(str[0], (char *)msg, 17); if (len > 16) { strlcpy(str[1], (char *)msg + 16, 17); @@ -185,74 +185,50 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) data2hex(msg + 24, len > 32 ? 8 : len - 24, str[3]); } } + static const char *ret[4] = { str[0], str[1], str[2], str[3] }; + return ret; +} +void layoutSignMessage(const uint8_t *msg, uint32_t len) +{ + const char **str = prepare_message(msg, len); layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - ascii ? "Sign text message?" : "Sign binary message?", + "Sign message?", str[0], str[1], str[2], str[3], NULL, NULL); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { - bool ascii = true; - uint32_t i; - for (i = 0; i < len; i++) { - if (msg[i] < 0x20 || msg[i] >= 0x80) { - ascii = false; - break; - } - } - - char str[4][17]; - memset(str, 0, sizeof(str)); - if (ascii) { - strlcpy(str[0], (char *)msg, 17); - if (len > 16) { - strlcpy(str[1], (char *)msg + 16, 17); - } - if (len > 32) { - strlcpy(str[2], (char *)msg + 32, 17); - } - if (len > 48) { - strlcpy(str[3], (char *)msg + 48, 17); - } - } else { - data2hex(msg, len > 8 ? 8 : len, str[0]); - if (len > 8) { - data2hex(msg + 8, len > 16 ? 8 : len - 8, str[1]); - } - if (len > 16) { - data2hex(msg + 16, len > 24 ? 8 : len - 16, str[2]); - } - if (len > 24) { - data2hex(msg + 24, len > 32 ? 8 : len - 24, str[3]); - } - } - + const char **str = prepare_message(msg, len); layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", - ascii ? "Message contents" : "Binary message contents", + "Verified message", str[0], str[1], str[2], str[3], NULL, NULL); } void layoutCipherKeyValue(bool encrypt, const char *key) { - int len = strlen(key); - char str[4][17]; - memset(str, 0, sizeof(str)); - strlcpy(str[0], (char *)key, 17); - if (len > 16) { - strlcpy(str[1], (char *)key + 16, 17); - } - if (len > 32) { - strlcpy(str[2], (char *)key + 32, 17); - } - if (len > 48) { - strlcpy(str[3], (char *)key + 48, 17); - } + const char **str = prepare_message((const uint8_t *)key, strlen(key)); layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", encrypt ? "Encrypt?" : "Decrypt?", str[0], str[1], str[2], str[3], NULL, NULL); } +void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) +{ + const char **str = prepare_message(msg, len); + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + signing ? "Encrypt+Sign message?" : "Encrypt message?", + str[0], str[1], str[2], str[3], NULL, NULL); +} + +void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) +{ + const char **str = prepare_message(msg, len); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", + address ? "Decrypted signed message" : "Decrypted message", + str[0], str[1], str[2], str[3], NULL, NULL); +} + void layoutAddress(const char *address) { oledSwipeLeft(); @@ -304,23 +280,3 @@ void layoutAddress(const char *address) oledRefresh(); } - -void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) -{ - // TODO: finish - (void)msg; - (void)len; - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - signing ? "Encrypt message?" : "Encrypt+sign message?", - NULL, NULL, NULL, NULL, NULL, NULL); -} - -void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) -{ - // TODO: finish - (void)msg; - (void)len; - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", - address ? "Signed message contents" : "Message contents", - NULL, NULL, NULL, NULL, NULL, NULL); -} diff --git a/firmware/layout2.h b/firmware/layout2.h index 5fadb68e6a..df4c0d2ff3 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -33,8 +33,8 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); -void layoutAddress(const char *address); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); +void layoutAddress(const char *address); #endif From a16e8c0e04cbe2e2e6dd85cbb1fa89d4d56413d5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 27 Nov 2014 17:23:04 +0100 Subject: [PATCH 0053/1154] more layout fixes --- firmware/fsm.c | 3 +- firmware/layout2.c | 73 +++++++++++++--------------------------------- 2 files changed, 23 insertions(+), 53 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index d1f886fd1e..bdd0232b2d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -611,6 +611,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) layoutHome(); return; } + layoutProgressSwipe("Encrypting", 0, 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error encrypting message"); layoutHome(); @@ -649,7 +650,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) HDNode *node = fsm_getRootNode(); if (!node) return; fsm_deriveKey(node, msg->address_n, msg->address_n_count); - + layoutProgressSwipe("Decrypting", 0, 0); RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; diff --git a/firmware/layout2.c b/firmware/layout2.c index fb2c833f9a..454fdfdc21 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -149,41 +149,23 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) ); } -// split longer message into 4 rows, 16 chars each -const char **prepare_message(const uint8_t *msg, uint32_t len) +// split longer string into 4 rows, rowlen chars each +const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) { - bool binary = false; - uint32_t i; - for (i = 0; i < len; i++) { - if (msg[i] < 0x20) { - binary = true; - break; - } + static char str[4][32 + 1]; + if (rowlen > 32) { + rowlen = 32; } - static char str[4][17]; memset(str, 0, sizeof(str)); - if (!binary) { - strlcpy(str[0], (char *)msg, 17); - if (len > 16) { - strlcpy(str[1], (char *)msg + 16, 17); - } - if (len > 32) { - strlcpy(str[2], (char *)msg + 32, 17); - } - if (len > 48) { - strlcpy(str[3], (char *)msg + 48, 17); - } - } else { - data2hex(msg, len > 8 ? 8 : len, str[0]); - if (len > 8) { - data2hex(msg + 8, len > 16 ? 8 : len - 8, str[1]); - } - if (len > 16) { - data2hex(msg + 16, len > 24 ? 8 : len - 16, str[2]); - } - if (len > 24) { - data2hex(msg + 24, len > 32 ? 8 : len - 24, str[3]); - } + strlcpy(str[0], (char *)msg, rowlen + 1); + if (len > rowlen) { + strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); + } + if (len > rowlen * 2) { + strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); + } + if (len > rowlen * 3) { + strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); } static const char *ret[4] = { str[0], str[1], str[2], str[3] }; return ret; @@ -191,7 +173,7 @@ const char **prepare_message(const uint8_t *msg, uint32_t len) void layoutSignMessage(const uint8_t *msg, uint32_t len) { - const char **str = prepare_message(msg, len); + const char **str = split_message(msg, len, 16); layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", "Sign message?", str[0], str[1], str[2], str[3], NULL, NULL); @@ -199,7 +181,7 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { - const char **str = prepare_message(msg, len); + const char **str = split_message(msg, len, 16); layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", "Verified message", str[0], str[1], str[2], str[3], NULL, NULL); @@ -207,15 +189,15 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len) void layoutCipherKeyValue(bool encrypt, const char *key) { - const char **str = prepare_message((const uint8_t *)key, strlen(key)); + const char **str = split_message((const uint8_t *)key, strlen(key), 16); layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - encrypt ? "Encrypt?" : "Decrypt?", + encrypt ? "Encode value of this key?" : "Decode value of this key?", str[0], str[1], str[2], str[3], NULL, NULL); } void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) { - const char **str = prepare_message(msg, len); + const char **str = split_message(msg, len, 16); layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", signing ? "Encrypt+Sign message?" : "Encrypt message?", str[0], str[1], str[2], str[3], NULL, NULL); @@ -223,7 +205,7 @@ void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) { - const char **str = prepare_message(msg, len); + const char **str = split_message(msg, len, 16); layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", address ? "Decrypted signed message" : "Decrypted message", str[0], str[1], str[2], str[3], NULL, NULL); @@ -253,20 +235,7 @@ void layoutAddress(const char *address) } } - int len = strlen(address); - char str[4][10]; - memset(str, 0, sizeof(str)); - - strlcpy(str[0], (char *)address, 10); - if (len > 9) { - strlcpy(str[1], (char *)address + 9, 10); - } - if (len > 18) { - strlcpy(str[2], (char *)address + 18, 10); - } - if (len > 27) { - strlcpy(str[3], (char *)address + 27, 10); - } + const char **str = split_message((const uint8_t *)address, strlen(address), 9); oledDrawString(68, 0 * 9, str[0]); oledDrawString(68, 1 * 9, str[1]); From 91451f88b557af9c291ab30fef383935635c3557 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 6 Dec 2014 19:12:55 +0100 Subject: [PATCH 0054/1154] multisig --- firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 15 +++++++----- firmware/signing.c | 29 +++++++++++++++++++--- firmware/transaction.c | 50 +++++++++++++++++++++++++++++++++++++- firmware/transaction.h | 4 ++- trezor-common | 2 +- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 66c417590d..5e6e1298af 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -29,9 +29,10 @@ const pb_field_t CoinType_fields[5] = { PB_LAST_FIELD }; -const pb_field_t MultisigRedeemScriptType_fields[3] = { +const pb_field_t MultisigRedeemScriptType_fields[4] = { PB_FIELD( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), PB_FIELD( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 3b91af9293..11df556d67 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -102,6 +102,8 @@ typedef struct _MultisigRedeemScriptType { MultisigRedeemScriptType_pubkeys_t pubkeys[5]; pb_size_t signatures_count; MultisigRedeemScriptType_signatures_t signatures[4]; + bool has_m; + uint32_t m; } MultisigRedeemScriptType; typedef PB_BYTES_ARRAY_T(520) TxOutputBinType_script_pubkey_t; @@ -191,7 +193,7 @@ extern const InputScriptType TxInputType_script_type_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define CoinType_init_default {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_default {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}} +#define MultisigRedeemScriptType_init_default {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} #define TxOutputBinType_init_default {0, {0, {0}}} @@ -200,7 +202,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_zero {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}} +#define MultisigRedeemScriptType_init_zero {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} #define TxOutputBinType_init_zero {0, {0, {0}}} @@ -221,6 +223,7 @@ extern const InputScriptType TxInputType_script_type_default; #define HDNodeType_public_key_tag 6 #define MultisigRedeemScriptType_pubkeys_tag 1 #define MultisigRedeemScriptType_signatures_tag 2 +#define MultisigRedeemScriptType_m_tag 3 #define TxOutputBinType_amount_tag 1 #define TxOutputBinType_script_pubkey_tag 2 #define TxOutputType_address_tag 1 @@ -254,7 +257,7 @@ extern const InputScriptType TxInputType_script_type_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t CoinType_fields[5]; -extern const pb_field_t MultisigRedeemScriptType_fields[3]; +extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; extern const pb_field_t TxOutputType_fields[5]; extern const pb_field_t TxOutputBinType_fields[3]; @@ -265,11 +268,11 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define CoinType_size 47 -#define MultisigRedeemScriptType_size 663 -#define TxInputType_size 1289 +#define MultisigRedeemScriptType_size 669 +#define TxInputType_size 1295 #define TxOutputType_size 102 #define TxOutputBinType_size 534 -#define TransactionType_size 1957 +#define TransactionType_size 1963 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 1115 diff --git a/firmware/signing.c b/firmware/signing.c index 4c21cc4b3d..4193e96b9a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -282,8 +282,12 @@ void signing_txack(TransactionType *tx) for (k = 0; k < tx->inputs[0].address_n_count; k++) { hdnode_private_ckd(&node, tx->inputs[0].address_n[k]); } - ecdsa_get_pubkeyhash(node.public_key, hash); - tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); + if (tx->inputs[0].has_multisig) { + tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes); + } else { + ecdsa_get_pubkeyhash(node.public_key, hash); + tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); + } if (tx->inputs[0].script_sig.size == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -362,7 +366,26 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(privkey, hash, sig); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); + if (input.has_multisig) { + // fill in the signature + int i, pubkey_idx = -1; + for (i = 0; i < input.multisig.pubkeys_count; i++) { + if (input.multisig.pubkeys[i].size == 33 && memcmp(input.multisig.pubkeys[i].bytes, pubkey, 33) == 0) { + pubkey_idx = i; + break; + } + } + if (pubkey_idx == -1) { + fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + signing_abort(); + return; + } + memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); + } else { + input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); + } resp.serialized.serialized_tx.size = tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, resp.serialized.serialized_tx.bytes); if (idx1i < inputs_count - 1) { idx1i++; diff --git a/firmware/transaction.c b/firmware/transaction.c index fc3d6e1447..958e740f1a 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -130,7 +130,37 @@ uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uin } } -int serialize_script_sig(uint8_t *signature, uint32_t signature_len, uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out) +// if out == NULL just compute the length +uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) +{ + if (!multisig->has_m) return 0; + uint32_t m = multisig->m; + uint32_t n = multisig->pubkeys_count; + if (m < 2 || m > 3) return 0; + if (n < 2 || n > 3) return 0; + uint32_t i, r = 0; + if (out) { + out[r] = 0x50 + m; r++; + for (i = 0; i < n; i++) { + r += op_push(multisig->pubkeys[i].size, out + r); + memcpy(out + r, multisig->pubkeys[i].bytes, multisig->pubkeys[i].size); r += multisig->pubkeys[i].size; + } + out[r] = 0x50 + n; r++; + out[r] = 0xAE; r++; // OP_CHECKMULTISIG + } else { + r++; + for (i = 0; i < n; i++) { + uint8_t dummy[8]; + r += op_push(multisig->pubkeys[i].size, dummy); + r += multisig->pubkeys[i].size; + } + r++; + r++; + } + return r; +} + +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out) { uint32_t r = 0; r += op_push(signature_len + 1, out + r); @@ -141,6 +171,24 @@ int serialize_script_sig(uint8_t *signature, uint32_t signature_len, uint8_t *pu return r; } +uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) +{ + uint32_t i, r = 0; + out[r] = 0x00; r++; + for (i = 0; i < multisig->signatures_count; i++) { + if (multisig->signatures[i].size == 0) { + continue; + } + r += op_push(multisig->signatures[i].size + 1, out + r); + memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; + out[r] = 0x01; r++; + } + uint32_t script_len = compile_script_multisig(multisig, 0); + r += op_push(script_len, out + r); + r += compile_script_multisig(multisig, out + r); + return r; +} + // tx methods uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) diff --git a/firmware/transaction.h b/firmware/transaction.h index 2a2e098492..eca3c16fa9 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -42,7 +42,9 @@ typedef struct { } TxStruct; uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out); -int serialize_script_sig(uint8_t *signature, uint32_t signature_len, uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); +uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); +uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out); diff --git a/trezor-common b/trezor-common index e675d5fd76..3670728fd2 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit e675d5fd7684e437bb35fb24330234d43ee2e4db +Subproject commit 3670728fd205ccfc75571ec3a49bfc7d07d11b17 From d07f6026e9c611b9787a910256f48b58f026dbf3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 7 Dec 2014 13:11:29 +0100 Subject: [PATCH 0055/1154] detect multisig by SPENDMULTISIG flag --- firmware/signing.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 4193e96b9a..38f1d5f39c 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -282,9 +282,14 @@ void signing_txack(TransactionType *tx) for (k = 0; k < tx->inputs[0].address_n_count; k++) { hdnode_private_ckd(&node, tx->inputs[0].address_n[k]); } - if (tx->inputs[0].has_multisig) { + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { + if (!tx->inputs[0].has_multisig) { + fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); + signing_abort(); + return; + } tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes); - } else { + } else { // SPENDADDRESS ecdsa_get_pubkeyhash(node.public_key, hash); tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); } @@ -366,7 +371,12 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(privkey, hash, sig); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (input.has_multisig) { + if (input.script_type == InputScriptType_SPENDMULTISIG) { + if (!input.has_multisig) { + fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); + signing_abort(); + return; + } // fill in the signature int i, pubkey_idx = -1; for (i = 0; i < input.multisig.pubkeys_count; i++) { @@ -383,7 +393,7 @@ void signing_txack(TransactionType *tx) memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); - } else { + } else { // SPENDADDRESS input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); } resp.serialized.serialized_tx.size = tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, resp.serialized.serialized_tx.bytes); From 983d1ff4b5ee09780ac4ecd353ac60a006c2655f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 Dec 2014 19:32:18 +0100 Subject: [PATCH 0056/1154] use space for non-printable chars such as enter, tab, etc. --- oled.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/oled.c b/oled.c index a62b3c5190..2d90105ed0 100644 --- a/oled.c +++ b/oled.c @@ -193,7 +193,11 @@ void oledDrawChar(int x, int y, char c) if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - if ((c < FONT_START) || (c > FONT_END)) { + if (c < FONT_START) { + c = ' '; + } + + if (c > FONT_END) { c = '_'; } From 10fc0b69fc42f1455450c347e5db7dad94fa48b8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 Dec 2014 19:58:13 +0100 Subject: [PATCH 0057/1154] check LoadDevice.skip_checksum field --- firmware/fsm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index bdd0232b2d..e4c07312a3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -42,6 +42,7 @@ #include "hmac.h" #include "crypto.h" #include "base58.h" +#include "bip39.h" // message methods @@ -295,6 +296,14 @@ void fsm_msgLoadDevice(LoadDevice *msg) return; } + if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { + if (!mnemonic_check(msg->mnemonic)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Mnemonic with wrong checksum provided"); + layoutHome(); + return; + } + } + storage_loadDevice(msg); storage_commit(); fsm_sendSuccess("Device loaded"); From 86dd83f93b4764b04abd4788aab5731b67c02b5f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 Dec 2014 21:21:44 +0100 Subject: [PATCH 0058/1154] sign message speedup see https://github.com/spesmilo/electrum/pull/695/files#diff-3 --- firmware/crypto.c | 26 ++++++++------------------ firmware/crypto.h | 2 +- firmware/fsm.c | 8 ++++---- firmware/signing.c | 2 +- trezor-crypto | 2 +- 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 8aea82658e..2b092a93a7 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -63,7 +63,7 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } -int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, const uint8_t *address_raw, uint8_t *signature) +int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -75,15 +75,10 @@ int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8 uint8_t hash[32]; sha256_Final(hash, &ctx); sha256_Raw(hash, 32, hash); - ecdsa_sign_digest(privkey, hash, signature + 1); - uint8_t i; - for (i = 27 + 4; i < 27 + 4 + 4; i++) { - signature[0] = i; - if (cryptoMessageVerify(message, message_len, address_raw, signature) == 0) { - return 0; - } - } - return 1; + uint8_t pby; + ecdsa_sign_digest(privkey, hash, signature + 1, &pby); + signature[0] = 27 + pby + 4; + return 0; } int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature) @@ -106,13 +101,8 @@ int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uin // read r and s bn_read_be(signature + 1, &r); bn_read_be(signature + 33, &s); - // x = r + (recid / 2) * order - bn_zero(&cp.x); - uint8_t i; - for (i = 0; i < recid / 2; i++) { - bn_addmod(&cp.x, &order256k1, &prime256k1); - } - bn_addmod(&cp.x, &r, &prime256k1); + // x = r + memcpy(&cp.x, &r, sizeof(bignum256)); // compute y from x uncompress_coords(recid % 2, &cp.x, &cp.y); // calculate hash @@ -161,7 +151,7 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_ uint32_t l = ser_length(msg_size, payload + 1); memcpy(payload + 1 + l, msg, msg_size); memcpy(payload + 1 + l + msg_size, address_raw, 21); - if (cryptoMessageSign(msg, msg_size, privkey, address_raw, payload + 1 + l + msg_size + 21) != 0) { + if (cryptoMessageSign(msg, msg_size, privkey, payload + 1 + l + msg_size + 21) != 0) { return 1; } *payload_len = 1 + l + msg_size + 21 + 65; diff --git a/firmware/crypto.h b/firmware/crypto.h index 603c52edc9..74bc348205 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -28,7 +28,7 @@ uint32_t ser_length(uint32_t len, uint8_t *out); -int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, const uint8_t *address_raw, uint8_t *signature); +int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index e4c07312a3..f72d768178 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -537,12 +537,12 @@ void fsm_msgSignMessage(SignMessage *msg) } fsm_deriveKey(node, msg->address_n, msg->address_n_count); - uint8_t addr_raw[21]; - ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); - base58_encode_check(addr_raw, 21, resp->address); layoutProgressSwipe("Signing", 0, 0); - if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, addr_raw, resp->signature.bytes) == 0) { + if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; + uint8_t addr_raw[21]; + ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); + base58_encode_check(addr_raw, 21, resp->address); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); diff --git a/firmware/signing.c b/firmware/signing.c index 38f1d5f39c..c6b5643be1 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -369,7 +369,7 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1i; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(privkey, hash, sig); + ecdsa_sign_digest(privkey, hash, sig, 0); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (input.script_type == InputScriptType_SPENDMULTISIG) { if (!input.has_multisig) { diff --git a/trezor-crypto b/trezor-crypto index 9469a64a0a..b4cdba8489 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 9469a64a0a1ec032b829e7a1465d0e4b2996cd61 +Subproject commit b4cdba8489201e623b948469609a48495f2eeed2 From 6561647d6b64fa5d4d37eaadc090c46a0e78869c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Dec 2014 15:44:26 +0100 Subject: [PATCH 0059/1154] update pb --- firmware/protob/messages.pb.c | 5 +++-- firmware/protob/messages.pb.h | 11 +++++++---- trezor-common | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 72b7d04385..892abd02b5 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -130,10 +130,11 @@ const pb_field_t PublicKey_fields[3] = { PB_LAST_FIELD }; -const pb_field_t GetAddress_fields[4] = { +const pb_field_t GetAddress_fields[5] = { PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; @@ -352,7 +353,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +PB_STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 41f70a2f51..038e7acc8b 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -336,6 +336,8 @@ typedef struct _GetAddress { char coin_name[17]; bool has_show_display; bool show_display; + bool has_multisig; + MultisigRedeemScriptType multisig; } GetAddress; typedef struct _GetEntropy { @@ -534,7 +536,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Entropy_init_default {{0, {0}}} #define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define PublicKey_init_default {HDNodeType_init_default, false, ""} -#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0} +#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} #define Address_init_default {""} #define WipeDevice_init_default {0} #define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} @@ -585,7 +587,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Entropy_init_zero {{0, {0}}} #define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} -#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} +#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} #define Address_init_zero {""} #define WipeDevice_init_zero {0} #define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0} @@ -686,6 +688,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 +#define GetAddress_multisig_tag 4 #define GetEntropy_size_tag 1 #define GetPublicKey_address_n_tag 1 #define LoadDevice_mnemonic_tag 1 @@ -759,7 +762,7 @@ extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[2]; extern const pb_field_t PublicKey_fields[3]; -extern const pb_field_t GetAddress_fields[4]; +extern const pb_field_t GetAddress_fields[5]; extern const pb_field_t Address_fields[2]; extern const pb_field_t WipeDevice_fields[1]; extern const pb_field_t LoadDevice_fields[8]; @@ -812,7 +815,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define Entropy_size 1027 #define GetPublicKey_size 48 #define PublicKey_size (121 + HDNodeType_size) -#define GetAddress_size 69 +#define GetAddress_size (75 + MultisigRedeemScriptType_size) #define Address_size 37 #define WipeDevice_size 0 #define LoadDevice_size (320 + HDNodeType_size) diff --git a/trezor-common b/trezor-common index 3670728fd2..437eff319f 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 3670728fd205ccfc75571ec3a49bfc7d07d11b17 +Subproject commit 437eff319f0673aae9f3416bd771d52dcc983e37 From 92cfcd156534dbc135759ff056d7cebcea842c0c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Dec 2014 18:04:51 +0100 Subject: [PATCH 0060/1154] implement GetAddress.multisig field --- firmware/crypto.c | 11 +++++++++++ firmware/crypto.h | 3 +++ firmware/fsm.c | 20 +++++++++++++++++++- firmware/signing.c | 11 +++-------- firmware/transaction.c | 32 +++++++++++++++++++++++++++++++- firmware/transaction.h | 1 + 6 files changed, 68 insertions(+), 10 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 2b092a93a7..40c219b4d8 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -251,3 +251,14 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload *msg_len = o; return 0; } + +int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey, uint32_t pubkey_len) +{ + int i; + for (i = 0; i < multisig->pubkeys_count; i++) { + if (multisig->pubkeys[i].size == pubkey_len && memcmp(multisig->pubkeys[i].bytes, pubkey, pubkey_len) == 0) { + return i; + } + } + return -1; +} diff --git a/firmware/crypto.h b/firmware/crypto.h index 74bc348205..9435f0c2fd 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -25,6 +25,7 @@ #include #include #include +#include "types.pb.h" uint32_t ser_length(uint32_t len, uint8_t *out); @@ -38,4 +39,6 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); +int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey, uint32_t pubkey_len); + #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index f72d768178..59a9bdb4e7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -43,6 +43,7 @@ #include "crypto.h" #include "base58.h" #include "bip39.h" +#include "ripemd160.h" // message methods @@ -487,7 +488,24 @@ void fsm_msgGetAddress(GetAddress *msg) fsm_deriveKey(node, msg->address_n, msg->address_n_count); - ecdsa_get_address(node->public_key, coin->address_type, resp->address); + if (msg->has_multisig) { + if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key, 33) < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + layoutHome(); + return; + } + uint8_t buf[32]; + if (compile_script_multisig_hash(&(msg->multisig), buf) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script"); + layoutHome(); + return; + } + ripemd160(buf, 32, buf + 1); + buf[0] = 0x05; // multisig cointype + base58_encode_check(buf, 21, resp->address); + } else { + ecdsa_get_address(node->public_key, coin->address_type, resp->address); + } if (msg->has_show_display && msg->show_display) { layoutAddress(resp->address); diff --git a/firmware/signing.c b/firmware/signing.c index c6b5643be1..6b0411468b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -24,6 +24,7 @@ #include "transaction.h" #include "ecdsa.h" #include "protect.h" +#include "crypto.h" static uint32_t inputs_count; static uint32_t outputs_count; @@ -378,14 +379,8 @@ void signing_txack(TransactionType *tx) return; } // fill in the signature - int i, pubkey_idx = -1; - for (i = 0; i < input.multisig.pubkeys_count; i++) { - if (input.multisig.pubkeys[i].size == 33 && memcmp(input.multisig.pubkeys[i].bytes, pubkey, 33) == 0) { - pubkey_idx = i; - break; - } - } - if (pubkey_idx == -1) { + int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey, 33); + if (pubkey_idx < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); signing_abort(); return; diff --git a/firmware/transaction.c b/firmware/transaction.c index 958e740f1a..34c730e7dd 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -149,8 +149,8 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 out[r] = 0xAE; r++; // OP_CHECKMULTISIG } else { r++; + uint8_t dummy[8]; for (i = 0; i < n; i++) { - uint8_t dummy[8]; r += op_push(multisig->pubkeys[i].size, dummy); r += multisig->pubkeys[i].size; } @@ -160,6 +160,36 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 return r; } +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash) +{ + if (!multisig->has_m) return 0; + uint32_t m = multisig->m; + uint32_t n = multisig->pubkeys_count; + if (m < 2 || m > 3) return 0; + if (n < 2 || n > 3) return 0; + + SHA256_CTX ctx; + sha256_Init(&ctx); + + uint8_t d, dummy[8]; + d = 0x50 + m; + sha256_Update(&ctx, &d, 1); + uint32_t i, r; + for (i = 0; i < n; i++) { + r = op_push(multisig->pubkeys[i].size, dummy); + sha256_Update(&ctx, dummy, r); + sha256_Update(&ctx, multisig->pubkeys[i].bytes, multisig->pubkeys[i].size); + } + d = 0x50 + n; + sha256_Update(&ctx, &d, 1); + d = 0xAE; + sha256_Update(&ctx, &d, 1); + + sha256_Final(hash, &ctx); + + return 1; +} + uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out) { uint32_t r = 0; diff --git a/firmware/transaction.h b/firmware/transaction.h index eca3c16fa9..7fb819aa3a 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -43,6 +43,7 @@ typedef struct { uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); From 43ff5baeab4eda797c57b00b1e60f8017e52c77f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Dec 2014 18:11:12 +0100 Subject: [PATCH 0061/1154] such happy doge --- firmware/coins.c | 9 +++++---- firmware/coins.h | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 9c028f6758..c22fd4a5e7 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,10 +21,11 @@ #include "coins.h" const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 10000}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000}, - {true, "Litecoin", true, "LTC", true, 48, true, 10000000}, + {true, "Bitcoin", true, "BTC", true, 0, true, 10000}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000}, + {true, "Litecoin", true, "LTC", true, 48, true, 10000000}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/coins.h b/firmware/coins.h index 6ce02c2d2d..1995bb797d 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 4 +#define COINS_COUNT 5 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index cd887bb650..25df542fdd 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:4 +Features.coins max_count:5 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 038e7acc8b..ef6a02fa78 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -312,7 +312,7 @@ typedef struct _Features { bool has_label; char label[33]; pb_size_t coins_count; - CoinType coins[4]; + CoinType coins[5]; bool has_initialized; bool initialized; bool has_revision; @@ -518,7 +518,7 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Initializer values for message structs */ #define Initialize_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, ""} #define ChangePin_init_default {false, 0} @@ -569,7 +569,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkStop_init_default {0} #define DebugLinkLog_init_default {false, 0, false, "", false, ""} #define Initialize_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, ""} #define ChangePin_init_zero {false, 0} @@ -797,7 +797,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 -#define Features_size (224 + 4*CoinType_size) +#define Features_size (230 + 5*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 54 #define ChangePin_size 2 From 7e27275ec8cefb2fe859527d4bd3f26ab854e414 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Dec 2014 19:50:10 +0100 Subject: [PATCH 0062/1154] allow 15/15 multisig --- firmware/fsm.c | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 4 ++-- firmware/protob/types.options | 10 +++++----- firmware/protob/types.pb.h | 26 +++++++++++++------------- firmware/transaction.c | 8 ++++---- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 59a9bdb4e7..d86134ca8b 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -606,7 +606,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) return; } curve_point pubkey; - if ((msg->pubkey.size != 33 && msg->pubkey.size != 65) || ecdsa_read_pubkey(msg->pubkey.bytes, &pubkey) == 0) { + if (msg->pubkey.size != 33 || ecdsa_read_pubkey(msg->pubkey.bytes, &pubkey) == 0) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); return; } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 25df542fdd..542ff906f8 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -58,7 +58,7 @@ VerifyMessage.message max_size:1024 MessageSignature.address max_size:35 MessageSignature.signature max_size:65 -EncryptMessage.pubkey max_size:65 +EncryptMessage.pubkey max_size:33 EncryptMessage.message max_size:1024 EncryptMessage.address_n max_count:8 EncryptMessage.coin_name max_size:17 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index ef6a02fa78..c9ad776c80 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -227,7 +227,7 @@ typedef struct _DecryptedMessage { char address[35]; } DecryptedMessage; -typedef PB_BYTES_ARRAY_T(65) EncryptMessage_pubkey_t; +typedef PB_BYTES_ARRAY_T(33) EncryptMessage_pubkey_t; typedef PB_BYTES_ARRAY_T(1024) EncryptMessage_message_t; @@ -828,7 +828,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SignMessage_size 1094 #define VerifyMessage_size 1131 #define MessageSignature_size 104 -#define EncryptMessage_size 1163 +#define EncryptMessage_size 1131 #define EncryptedMessage_size 1168 #define DecryptMessage_size 1216 #define DecryptedMessage_size 1064 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 747eb75a31..8832018ba7 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -7,7 +7,7 @@ CoinType.coin_shortcut max_size:9 TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 -TxInputType.script_sig max_size:520 +TxInputType.script_sig max_size:1650 TxOutputType.address max_size:35 TxOutputType.address_n max_count:8 @@ -20,8 +20,8 @@ TransactionType.outputs max_count:1 TxRequestDetailsType.tx_hash max_size:32 -TxRequestSerializedType.signature max_size:80 -TxRequestSerializedType.serialized_tx max_size:1024 +TxRequestSerializedType.signature max_size:73 +TxRequestSerializedType.serialized_tx max_size:2048 -MultisigRedeemScriptType.pubkeys max_count:5 max_size:65 -MultisigRedeemScriptType.signatures max_count:4 max_size:80 +MultisigRedeemScriptType.pubkeys max_count:15 max_size:33 +MultisigRedeemScriptType.signatures max_count:15 max_size:73 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 11df556d67..d8c4ffbcc7 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -93,15 +93,15 @@ typedef struct _HDNodeType { HDNodeType_public_key_t public_key; } HDNodeType; -typedef PB_BYTES_ARRAY_T(65) MultisigRedeemScriptType_pubkeys_t; +typedef PB_BYTES_ARRAY_T(33) MultisigRedeemScriptType_pubkeys_t; -typedef PB_BYTES_ARRAY_T(80) MultisigRedeemScriptType_signatures_t; +typedef PB_BYTES_ARRAY_T(73) MultisigRedeemScriptType_signatures_t; typedef struct _MultisigRedeemScriptType { pb_size_t pubkeys_count; - MultisigRedeemScriptType_pubkeys_t pubkeys[5]; + MultisigRedeemScriptType_pubkeys_t pubkeys[15]; pb_size_t signatures_count; - MultisigRedeemScriptType_signatures_t signatures[4]; + MultisigRedeemScriptType_signatures_t signatures[15]; bool has_m; uint32_t m; } MultisigRedeemScriptType; @@ -131,9 +131,9 @@ typedef struct _TxRequestDetailsType { TxRequestDetailsType_tx_hash_t tx_hash; } TxRequestDetailsType; -typedef PB_BYTES_ARRAY_T(80) TxRequestSerializedType_signature_t; +typedef PB_BYTES_ARRAY_T(73) TxRequestSerializedType_signature_t; -typedef PB_BYTES_ARRAY_T(1024) TxRequestSerializedType_serialized_tx_t; +typedef PB_BYTES_ARRAY_T(2048) TxRequestSerializedType_serialized_tx_t; typedef struct _TxRequestSerializedType { bool has_signature_index; @@ -146,7 +146,7 @@ typedef struct _TxRequestSerializedType { typedef PB_BYTES_ARRAY_T(32) TxInputType_prev_hash_t; -typedef PB_BYTES_ARRAY_T(520) TxInputType_script_sig_t; +typedef PB_BYTES_ARRAY_T(1650) TxInputType_script_sig_t; typedef struct _TxInputType { pb_size_t address_n_count; @@ -193,7 +193,7 @@ extern const InputScriptType TxInputType_script_type_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define CoinType_init_default {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_default {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} +#define MultisigRedeemScriptType_init_default {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, {{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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} #define TxOutputBinType_init_default {0, {0, {0}}} @@ -202,7 +202,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_zero {0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} +#define MultisigRedeemScriptType_init_zero {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, {{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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} #define TxOutputBinType_init_zero {0, {0, {0}}} @@ -268,13 +268,13 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define CoinType_size 47 -#define MultisigRedeemScriptType_size 669 -#define TxInputType_size 1295 +#define MultisigRedeemScriptType_size 1656 +#define TxInputType_size 3412 #define TxOutputType_size 102 #define TxOutputBinType_size 534 -#define TransactionType_size 1963 +#define TransactionType_size 4080 #define TxRequestDetailsType_size 40 -#define TxRequestSerializedType_size 1115 +#define TxRequestSerializedType_size 2132 #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/transaction.c b/firmware/transaction.c index 34c730e7dd..63be253cea 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -136,8 +136,8 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 if (!multisig->has_m) return 0; uint32_t m = multisig->m; uint32_t n = multisig->pubkeys_count; - if (m < 2 || m > 3) return 0; - if (n < 2 || n > 3) return 0; + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; uint32_t i, r = 0; if (out) { out[r] = 0x50 + m; r++; @@ -165,8 +165,8 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, if (!multisig->has_m) return 0; uint32_t m = multisig->m; uint32_t n = multisig->pubkeys_count; - if (m < 2 || m > 3) return 0; - if (n < 2 || n > 3) return 0; + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; SHA256_CTX ctx; sha256_Init(&ctx); From 961566c9b7494e1110bfbdc46b83c3281a8ac7ab Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Dec 2014 19:29:27 +0100 Subject: [PATCH 0063/1154] implement ApplySetttings.use_passphrase --- firmware/fsm.c | 34 ++++++++++++++++++++++++---------- firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 11 +++++++---- firmware/storage.c | 9 +++++++++ firmware/storage.h | 2 ++ trezor-common | 2 +- 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index d86134ca8b..89c36e7997 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -441,21 +441,32 @@ void fsm_msgClearSession(ClearSession *msg) void fsm_msgApplySettings(ApplySettings *msg) { - if (msg->has_label && msg->has_language) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "and language to", msg->language, "?"); - } else if (msg->has_label) { layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); - } else + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + layoutHome(); + return; + } + } if (msg->has_language) { layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); - return; + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + layoutHome(); + return; + } } - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); - layoutHome(); + if (msg->has_use_passphrase) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "protection?", NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + layoutHome(); + return; + } + } + if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); return; } if (!protectPin(true)) { @@ -468,6 +479,9 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_language) { storage_setLanguage(msg->language); } + if (msg->has_use_passphrase) { + storage_setPassphraseProtection(msg->use_passphrase); + } storage_commit(); fsm_sendSuccess("Settings applied"); layoutHome(); diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 892abd02b5..9dacf83b30 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -46,9 +46,10 @@ const pb_field_t ClearSession_fields[1] = { PB_LAST_FIELD }; -const pb_field_t ApplySettings_fields[3] = { +const pb_field_t ApplySettings_fields[4] = { PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), + PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index c9ad776c80..75892f9f91 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -123,6 +123,8 @@ typedef struct _ApplySettings { char language[17]; bool has_label; char label[33]; + bool has_use_passphrase; + bool use_passphrase; } ApplySettings; typedef struct _ButtonRequest { @@ -520,7 +522,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Initialize_init_default {0} #define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_default {0} -#define ApplySettings_init_default {false, "", false, ""} +#define ApplySettings_init_default {false, "", false, "", false, 0} #define ChangePin_init_default {false, 0} #define Ping_init_default {false, "", false, 0, false, 0, false, 0} #define Success_init_default {false, ""} @@ -571,7 +573,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Initialize_init_zero {0} #define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_zero {0} -#define ApplySettings_init_zero {false, "", false, ""} +#define ApplySettings_init_zero {false, "", false, "", false, 0} #define ChangePin_init_zero {false, 0} #define Ping_init_zero {false, "", false, 0, false, 0, false, 0} #define Success_init_zero {false, ""} @@ -624,6 +626,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Address_address_tag 1 #define ApplySettings_language_tag 1 #define ApplySettings_label_tag 2 +#define ApplySettings_use_passphrase_tag 3 #define ButtonRequest_code_tag 1 #define ButtonRequest_data_tag 2 #define ChangePin_remove_tag 1 @@ -746,7 +749,7 @@ extern const char SimpleSignTx_coin_name_default[17]; extern const pb_field_t Initialize_fields[1]; extern const pb_field_t Features_fields[16]; extern const pb_field_t ClearSession_fields[1]; -extern const pb_field_t ApplySettings_fields[3]; +extern const pb_field_t ApplySettings_fields[4]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; extern const pb_field_t Success_fields[2]; @@ -799,7 +802,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define Initialize_size 0 #define Features_size (230 + 5*CoinType_size) #define ClearSession_size 0 -#define ApplySettings_size 54 +#define ApplySettings_size 56 #define ChangePin_size 2 #define Ping_size 265 #define Success_size 259 diff --git a/firmware/storage.c b/firmware/storage.c index 7524741214..99f21558b8 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -205,6 +205,15 @@ void storage_setLanguage(const char *lang) } } +void storage_setPassphraseProtection(bool passphrase_protection) +{ + sessionRootNodeCached = false; + sessionPassphraseCached = false; + + storage.has_passphrase_protection = true; + storage.passphrase_protection = passphrase_protection; +} + void get_root_node_callback(uint32_t iter, uint32_t total) { static uint8_t i; diff --git a/firmware/storage.h b/firmware/storage.h index f68ab78fd8..58021b8f28 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -41,6 +41,8 @@ void storage_setLabel(const char *label); const char *storage_getLanguage(void); void storage_setLanguage(const char *lang); +void storage_setPassphraseProtection(bool passphrase_protection); + void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); diff --git a/trezor-common b/trezor-common index 437eff319f..40b3cb4148 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 437eff319f0673aae9f3416bd771d52dcc983e37 +Subproject commit 40b3cb414864f970d627651f8be0669be95c5efc From 567537cd034d80842bed2d36ffccf588aa10930c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Dec 2014 20:33:49 +0100 Subject: [PATCH 0064/1154] update to new multisig api --- firmware/crypto.c | 16 +++++- firmware/crypto.h | 5 +- firmware/fsm.c | 2 +- firmware/protob/types.options | 4 +- firmware/protob/types.pb.c | 13 +++-- firmware/protob/types.pb.h | 92 ++++++++++++++++++++--------------- firmware/signing.c | 2 +- firmware/transaction.c | 31 ++++-------- trezor-common | 2 +- trezor-crypto | 2 +- 10 files changed, 98 insertions(+), 71 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 40c219b4d8..04cb9549dd 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -24,6 +24,7 @@ #include "pbkdf2.h" #include "aes.h" #include "hmac.h" +#include "bip32.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -252,11 +253,22 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload return 0; } -int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey, uint32_t pubkey_len) +uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) +{ + static HDNode node; + hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node); + uint32_t i; + for (i = 0; i < hdnodepath->address_n_count; i++) { + hdnode_public_ckd(&node, hdnodepath->address_n[i]); + } + return node.public_key; +} + +int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { int i; for (i = 0; i < multisig->pubkeys_count; i++) { - if (multisig->pubkeys[i].size == pubkey_len && memcmp(multisig->pubkeys[i].bytes, pubkey, pubkey_len) == 0) { + if (memcmp(cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), pubkey, 33) == 0) { return i; } } diff --git a/firmware/crypto.h b/firmware/crypto.h index 9435f0c2fd..7afa10545e 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -39,6 +39,9 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); -int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey, uint32_t pubkey_len); +uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); + +int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); + #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 89c36e7997..1851605689 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -503,7 +503,7 @@ void fsm_msgGetAddress(GetAddress *msg) fsm_deriveKey(node, msg->address_n, msg->address_n_count); if (msg->has_multisig) { - if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key, 33) < 0) { + if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); layoutHome(); return; diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 8832018ba7..ec464a60fd 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -2,6 +2,8 @@ HDNodeType.chain_code max_size:32 HDNodeType.private_key max_size:32 HDNodeType.public_key max_size:33 +HDNodePathType.address_n max_count:8 + CoinType.coin_name max_size:17 CoinType.coin_shortcut max_size:9 @@ -23,5 +25,5 @@ TxRequestDetailsType.tx_hash max_size:32 TxRequestSerializedType.signature max_size:73 TxRequestSerializedType.serialized_tx max_size:2048 -MultisigRedeemScriptType.pubkeys max_count:15 max_size:33 +MultisigRedeemScriptType.pubkeys max_count:15 MultisigRedeemScriptType.signatures max_count:15 max_size:73 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 5e6e1298af..ab937186c6 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -21,6 +21,12 @@ const pb_field_t HDNodeType_fields[7] = { PB_LAST_FIELD }; +const pb_field_t HDNodePathType_fields[3] = { + PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, HDNodePathType, node, node, &HDNodeType_fields), + PB_FIELD( 2, UINT32 , REPEATED, STATIC , OTHER, HDNodePathType, address_n, node, 0), + PB_LAST_FIELD +}; + const pb_field_t CoinType_fields[5] = { PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), @@ -30,7 +36,7 @@ const pb_field_t CoinType_fields[5] = { }; const pb_field_t MultisigRedeemScriptType_fields[4] = { - PB_FIELD( 1, BYTES , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, 0), + PB_FIELD( 1, MESSAGE , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, &HDNodePathType_fields), PB_FIELD( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), PB_LAST_FIELD @@ -47,11 +53,12 @@ const pb_field_t TxInputType_fields[8] = { PB_LAST_FIELD }; -const pb_field_t TxOutputType_fields[5] = { +const pb_field_t TxOutputType_fields[6] = { PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), PB_FIELD( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), PB_FIELD( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), PB_FIELD( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; @@ -147,7 +154,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +PB_STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index d8c4ffbcc7..59fea49576 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -30,7 +30,8 @@ typedef enum _FailureType { typedef enum _OutputScriptType { OutputScriptType_PAYTOADDRESS = 0, - OutputScriptType_PAYTOSCRIPTHASH = 1 + OutputScriptType_PAYTOSCRIPTHASH = 1, + OutputScriptType_PAYTOMULTISIG = 2 } OutputScriptType; typedef enum _InputScriptType { @@ -93,19 +94,6 @@ typedef struct _HDNodeType { HDNodeType_public_key_t public_key; } HDNodeType; -typedef PB_BYTES_ARRAY_T(33) MultisigRedeemScriptType_pubkeys_t; - -typedef PB_BYTES_ARRAY_T(73) MultisigRedeemScriptType_signatures_t; - -typedef struct _MultisigRedeemScriptType { - pb_size_t pubkeys_count; - MultisigRedeemScriptType_pubkeys_t pubkeys[15]; - pb_size_t signatures_count; - MultisigRedeemScriptType_signatures_t signatures[15]; - bool has_m; - uint32_t m; -} MultisigRedeemScriptType; - typedef PB_BYTES_ARRAY_T(520) TxOutputBinType_script_pubkey_t; typedef struct _TxOutputBinType { @@ -113,15 +101,6 @@ typedef struct _TxOutputBinType { TxOutputBinType_script_pubkey_t script_pubkey; } TxOutputBinType; -typedef struct _TxOutputType { - bool has_address; - char address[35]; - pb_size_t address_n_count; - uint32_t address_n[8]; - uint64_t amount; - OutputScriptType script_type; -} TxOutputType; - typedef PB_BYTES_ARRAY_T(32) TxRequestDetailsType_tx_hash_t; typedef struct _TxRequestDetailsType { @@ -144,6 +123,23 @@ typedef struct _TxRequestSerializedType { TxRequestSerializedType_serialized_tx_t serialized_tx; } TxRequestSerializedType; +typedef struct _HDNodePathType { + HDNodeType node; + pb_size_t address_n_count; + uint32_t address_n[8]; +} HDNodePathType; + +typedef PB_BYTES_ARRAY_T(73) MultisigRedeemScriptType_signatures_t; + +typedef struct _MultisigRedeemScriptType { + pb_size_t pubkeys_count; + HDNodePathType pubkeys[15]; + pb_size_t signatures_count; + MultisigRedeemScriptType_signatures_t signatures[15]; + bool has_m; + uint32_t m; +} MultisigRedeemScriptType; + typedef PB_BYTES_ARRAY_T(32) TxInputType_prev_hash_t; typedef PB_BYTES_ARRAY_T(1650) TxInputType_script_sig_t; @@ -163,6 +159,17 @@ typedef struct _TxInputType { MultisigRedeemScriptType multisig; } TxInputType; +typedef struct _TxOutputType { + bool has_address; + char address[35]; + pb_size_t address_n_count; + uint32_t address_n[8]; + uint64_t amount; + OutputScriptType script_type; + bool has_multisig; + MultisigRedeemScriptType multisig; +} TxOutputType; + typedef struct _TransactionType { bool has_version; uint32_t version; @@ -192,19 +199,21 @@ extern const InputScriptType TxInputType_script_type_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define CoinType_init_default {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_default {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, {{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}}}, false, 0} +#define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} -#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} +#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default} #define TxOutputBinType_init_default {0, {0, {0}}} #define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} #define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0} -#define MultisigRedeemScriptType_init_zero {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, {{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}}}, false, 0} +#define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} -#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0} +#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputBinType_init_zero {0, {0, {0}}} #define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} #define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} @@ -221,20 +230,18 @@ extern const InputScriptType TxInputType_script_type_default; #define HDNodeType_chain_code_tag 4 #define HDNodeType_private_key_tag 5 #define HDNodeType_public_key_tag 6 -#define MultisigRedeemScriptType_pubkeys_tag 1 -#define MultisigRedeemScriptType_signatures_tag 2 -#define MultisigRedeemScriptType_m_tag 3 #define TxOutputBinType_amount_tag 1 #define TxOutputBinType_script_pubkey_tag 2 -#define TxOutputType_address_tag 1 -#define TxOutputType_address_n_tag 2 -#define TxOutputType_amount_tag 3 -#define TxOutputType_script_type_tag 4 #define TxRequestDetailsType_request_index_tag 1 #define TxRequestDetailsType_tx_hash_tag 2 #define TxRequestSerializedType_signature_index_tag 1 #define TxRequestSerializedType_signature_tag 2 #define TxRequestSerializedType_serialized_tx_tag 3 +#define HDNodePathType_node_tag 1 +#define HDNodePathType_address_n_tag 2 +#define MultisigRedeemScriptType_pubkeys_tag 1 +#define MultisigRedeemScriptType_signatures_tag 2 +#define MultisigRedeemScriptType_m_tag 3 #define TxInputType_address_n_tag 1 #define TxInputType_prev_hash_tag 2 #define TxInputType_prev_index_tag 3 @@ -242,6 +249,11 @@ extern const InputScriptType TxInputType_script_type_default; #define TxInputType_sequence_tag 5 #define TxInputType_script_type_tag 6 #define TxInputType_multisig_tag 7 +#define TxOutputType_address_tag 1 +#define TxOutputType_address_n_tag 2 +#define TxOutputType_amount_tag 3 +#define TxOutputType_script_type_tag 4 +#define TxOutputType_multisig_tag 5 #define TransactionType_version_tag 1 #define TransactionType_inputs_tag 2 #define TransactionType_bin_outputs_tag 3 @@ -256,10 +268,11 @@ extern const InputScriptType TxInputType_script_type_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; +extern const pb_field_t HDNodePathType_fields[3]; extern const pb_field_t CoinType_fields[5]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; -extern const pb_field_t TxOutputType_fields[5]; +extern const pb_field_t TxOutputType_fields[6]; extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TxRequestDetailsType_fields[3]; @@ -267,12 +280,13 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 +#define HDNodePathType_size 171 #define CoinType_size 47 -#define MultisigRedeemScriptType_size 1656 -#define TxInputType_size 3412 -#define TxOutputType_size 102 +#define MultisigRedeemScriptType_size 3741 +#define TxInputType_size 5497 +#define TxOutputType_size 3846 #define TxOutputBinType_size 534 -#define TransactionType_size 4080 +#define TransactionType_size 9910 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 diff --git a/firmware/signing.c b/firmware/signing.c index 6b0411468b..565cd4f196 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -379,7 +379,7 @@ void signing_txack(TransactionType *tx) return; } // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey, 33); + int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); if (pubkey_idx < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 63be253cea..a3a9103d13 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -142,20 +142,13 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 if (out) { out[r] = 0x50 + m; r++; for (i = 0; i < n; i++) { - r += op_push(multisig->pubkeys[i].size, out + r); - memcpy(out + r, multisig->pubkeys[i].bytes, multisig->pubkeys[i].size); r += multisig->pubkeys[i].size; + out[r] = 33; r++; // OP_PUSH 33 + memcpy(out + r, cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), 33); r += 33; } out[r] = 0x50 + n; r++; out[r] = 0xAE; r++; // OP_CHECKMULTISIG } else { - r++; - uint8_t dummy[8]; - for (i = 0; i < n; i++) { - r += op_push(multisig->pubkeys[i].size, dummy); - r += multisig->pubkeys[i].size; - } - r++; - r++; + r = 1 + 34 * n + 2; } return r; } @@ -171,19 +164,15 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, SHA256_CTX ctx; sha256_Init(&ctx); - uint8_t d, dummy[8]; - d = 0x50 + m; - sha256_Update(&ctx, &d, 1); - uint32_t i, r; + uint8_t d; + d = 0x50 + m; sha256_Update(&ctx, &d, 1); + uint32_t i; for (i = 0; i < n; i++) { - r = op_push(multisig->pubkeys[i].size, dummy); - sha256_Update(&ctx, dummy, r); - sha256_Update(&ctx, multisig->pubkeys[i].bytes, multisig->pubkeys[i].size); + d = 33; sha256_Update(&ctx, &d, 1); // OP_PUSH 33 + sha256_Update(&ctx, cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), 33); } - d = 0x50 + n; - sha256_Update(&ctx, &d, 1); - d = 0xAE; - sha256_Update(&ctx, &d, 1); + d = 0x50 + n; sha256_Update(&ctx, &d, 1); + d = 0xAE; sha256_Update(&ctx, &d, 1); sha256_Final(hash, &ctx); diff --git a/trezor-common b/trezor-common index 40b3cb4148..94d17ef8bc 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 40b3cb414864f970d627651f8be0669be95c5efc +Subproject commit 94d17ef8bc56d7c0e6ddfed39e84987543259e05 diff --git a/trezor-crypto b/trezor-crypto index b4cdba8489..10a92c3c62 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit b4cdba8489201e623b948469609a48495f2eeed2 +Subproject commit 10a92c3c6276d5b1955331b7a33ebe9d6a32c37e From 1385de1154b8d8c19ea959ced70d27d202980d56 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Dec 2014 16:50:12 +0100 Subject: [PATCH 0065/1154] use const where appropriate --- firmware/transaction.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index a3a9103d13..0e7a0e71b9 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -134,8 +134,8 @@ uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uin uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) { if (!multisig->has_m) return 0; - uint32_t m = multisig->m; - uint32_t n = multisig->pubkeys_count; + const uint32_t m = multisig->m; + const uint32_t n = multisig->pubkeys_count; if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; uint32_t i, r = 0; @@ -156,8 +156,8 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash) { if (!multisig->has_m) return 0; - uint32_t m = multisig->m; - uint32_t n = multisig->pubkeys_count; + const uint32_t m = multisig->m; + const uint32_t n = multisig->pubkeys_count; if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; From 0e92d4c58825868ffa7265b5a9954e9b74de5083 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Dec 2014 18:28:46 +0100 Subject: [PATCH 0066/1154] error checking of hdnode functions return values --- firmware/crypto.c | 8 ++++++-- firmware/fsm.c | 25 +++++++++++++++---------- firmware/signing.c | 6 +++++- firmware/storage.c | 8 ++++++-- firmware/transaction.c | 4 +++- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 04cb9549dd..84450c9350 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -256,10 +256,14 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { static HDNode node; - hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node); + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node) == 0) { + return 0; + } uint32_t i; for (i = 0; i < hdnodepath->address_n_count; i++) { - hdnode_public_ckd(&node, hdnodepath->address_n[i]); + if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { + return 0; + }; } return node.public_key; } diff --git a/firmware/fsm.c b/firmware/fsm.c index 1851605689..8f8af81b5a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -89,18 +89,23 @@ HDNode *fsm_getRootNode(void) return &node; } -void fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) +int fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) { size_t i; if (address_n_count > 3) { layoutProgressSwipe("Preparing keys", 0, 0); } for (i = 0; i < address_n_count; i++) { - hdnode_private_ckd(node, address_n[i]); + if (hdnode_private_ckd(node, address_n[i]) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + layoutHome(); + return 0; + } if (address_n_count > 3) { layoutProgress("Preparing keys", 1000 * i / address_n_count, i); } } + return 1; } void fsm_msgInitialize(Initialize *msg) @@ -265,8 +270,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) HDNode *node = fsm_getRootNode(); if (!node) return; - - fsm_deriveKey(node, msg->address_n, msg->address_n_count); + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; resp->node.depth = node->depth; resp->node.fingerprint = node->fingerprint; @@ -395,7 +399,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) } HDNode *node = fsm_getRootNode(); if (!node) return; - fsm_deriveKey(node, msg->address_n, msg->address_n_count); + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; bool encrypt = msg->has_encrypt && msg->encrypt; bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; @@ -499,8 +503,7 @@ void fsm_msgGetAddress(GetAddress *msg) layoutHome(); return; } - - fsm_deriveKey(node, msg->address_n, msg->address_n_count); + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; if (msg->has_multisig) { if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { @@ -567,8 +570,8 @@ void fsm_msgSignMessage(SignMessage *msg) layoutHome(); return; } + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; - fsm_deriveKey(node, msg->address_n, msg->address_n_count); layoutProgressSwipe("Signing", 0, 0); if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; @@ -642,7 +645,8 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) } node = fsm_getRootNode(); if (!node) return; - fsm_deriveKey(node, msg->address_n, msg->address_n_count); + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; + hdnode_fill_public_key(node); ecdsa_get_address_raw(node->public_key, coin->address_type, address_raw); } @@ -690,7 +694,8 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) } HDNode *node = fsm_getRootNode(); if (!node) return; - fsm_deriveKey(node, msg->address_n, msg->address_n_count); + if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; + layoutProgressSwipe("Decrypting", 0, 0); RESP_INIT(DecryptedMessage); bool display_only = false; diff --git a/firmware/signing.c b/firmware/signing.c index 565cd4f196..1ee9e0e8cf 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -281,7 +281,11 @@ void signing_txack(TransactionType *tx) memcpy(&node, root, sizeof(HDNode)); uint32_t k; for (k = 0; k < tx->inputs[0].address_n_count; k++) { - hdnode_private_ckd(&node, tx->inputs[0].address_n[k]); + if (hdnode_private_ckd(&node, tx->inputs[0].address_n[k]) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + signing_abort(); + return; + } } if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { if (!tx->inputs[0].has_multisig) { diff --git a/firmware/storage.c b/firmware/storage.c index 99f21558b8..05dc8cbea1 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -233,7 +233,9 @@ bool storage_getRootNode(HDNode *node) if (!protectPassphrase()) { return false; } - hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode); + if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode) == 0) { + return false; + } if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) { // decrypt hd node uint8_t secret[64]; @@ -257,7 +259,9 @@ bool storage_getRootNode(HDNode *node) uint8_t seed[64]; layoutProgressSwipe("Waking up", 0, 0); mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039 - hdnode_from_seed(seed, sizeof(seed), &sessionRootNode); + if (hdnode_from_seed(seed, sizeof(seed), &sessionRootNode) == 0) { + return false; + } memcpy(node, &sessionRootNode, sizeof(HDNode)); sessionRootNodeCached = true; return true; diff --git a/firmware/transaction.c b/firmware/transaction.c index 0e7a0e71b9..e9bfa840a6 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -60,7 +60,9 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T uint32_t k; memcpy(&node, root, sizeof(HDNode)); for (k = 0; k < in->address_n_count; k++) { - hdnode_private_ckd(&node, in->address_n[k]); + if (hdnode_private_ckd(&node, in->address_n[k]) == 0) { + return 0; + } } ecdsa_get_address(node.public_key, coin->address_type, in->address); } else From 309604d286bf9dbe7ae7a61710c83d864772c85f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Dec 2014 18:45:39 +0100 Subject: [PATCH 0067/1154] change setup wording --- firmware/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index 6070b76895..56d4d95f18 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -106,7 +106,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) i++; j++; } current_word[j] = 0; if (storage.mnemonic[i] != 0) i++; - char desc[] = "##th word"; + char desc[] = "##th word is:"; if (word_pos < 10) { desc[0] = ' '; } else { From 4122b56e1ce42f54a0d7719483820d86f725f667 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Dec 2014 18:49:49 +0100 Subject: [PATCH 0068/1154] check return value of cryptoHDNodePathToPubkey --- firmware/crypto.c | 4 +++- firmware/messages.h | 4 ++-- firmware/transaction.c | 8 ++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 84450c9350..779b1d25b1 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -255,6 +255,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { + if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node) == 0) { return 0; @@ -272,7 +273,8 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui { int i; for (i = 0; i < multisig->pubkeys_count; i++) { - if (memcmp(cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), pubkey, 33) == 0) { + const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { return i; } } diff --git a/firmware/messages.h b/firmware/messages.h index d2a5136040..a32e3ce8be 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -24,9 +24,9 @@ #include #include "trezor.h" -#define MSG_IN_SIZE (9*1024) +#define MSG_IN_SIZE (12*1024) -#define MSG_OUT_SIZE (9*1024) +#define MSG_OUT_SIZE (12*1024) #define msg_read(buf, len) msg_read_common('n', (buf), (len)) #define msg_write(id, ptr) msg_write_common('n', (id), (ptr)) diff --git a/firmware/transaction.c b/firmware/transaction.c index e9bfa840a6..2a75685ae5 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -145,7 +145,9 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 out[r] = 0x50 + m; r++; for (i = 0; i < n; i++) { out[r] = 33; r++; // OP_PUSH 33 - memcpy(out + r, cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), 33); r += 33; + const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + if (!pubkey) return 0; + memcpy(out + r, pubkey, 33); r += 33; } out[r] = 0x50 + n; r++; out[r] = 0xAE; r++; // OP_CHECKMULTISIG @@ -171,7 +173,9 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint32_t i; for (i = 0; i < n; i++) { d = 33; sha256_Update(&ctx, &d, 1); // OP_PUSH 33 - sha256_Update(&ctx, cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])), 33); + const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + if (!pubkey) return 0; + sha256_Update(&ctx, pubkey, 33); } d = 0x50 + n; sha256_Update(&ctx, &d, 1); d = 0xAE; sha256_Update(&ctx, &d, 1); From cce9d783a6ec9583bc887719c73e953aa757e4fd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Dec 2014 18:56:44 +0100 Subject: [PATCH 0069/1154] introduce cryptoMultisigFingerprint --- firmware/crypto.c | 41 +++++++++++++++++++++++++++++++++++++++++ firmware/crypto.h | 1 + 2 files changed, 42 insertions(+) diff --git a/firmware/crypto.c b/firmware/crypto.c index 779b1d25b1..9da57667f4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -280,3 +280,44 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui } return -1; } + +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) +{ + const uint32_t n = multisig->pubkeys_count; + const int max_pubkeys = pb_arraysize(MultisigRedeemScriptType, pubkeys); + uint8_t order[max_pubkeys], swap; + uint32_t i, j; + const HDNodeType *a, *b; + // check sanity + for (i = 0; i < n; i++) { + order[i] = i; + a = &(multisig->pubkeys[i].node); + if (!a->has_public_key || a->public_key.size != 33) return 0; + if (a->chain_code.size != 32) return 0; + } + // (bubble) sort according to pubkey + for (i = 0; i < n; i++) { + for (j = i; j < n; j++) { + a = &(multisig->pubkeys[order[i]].node); + b = &(multisig->pubkeys[order[j]].node); + if (memcmp(a->public_key.bytes, b->public_key.bytes, 33) > 0) { + swap = order[i]; + order[i] = order[j]; + order[j] = swap; + } + } + } + // hash sorted nodes + SHA256_CTX ctx; + sha256_Init(&ctx); + for (i = 0; i < n; i++) { + a = &(multisig->pubkeys[order[i]].node); + sha256_Update(&ctx, (const uint8_t *)a->depth, sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)a->fingerprint, sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)a->child_num, sizeof(uint32_t)); + sha256_Update(&ctx, a->chain_code.bytes, 32); + sha256_Update(&ctx, a->public_key.bytes, 33); + } + sha256_Final(hash, &ctx); + return 1; +} diff --git a/firmware/crypto.h b/firmware/crypto.h index 7afa10545e..83af40c0d9 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -43,5 +43,6 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); #endif From 0d427f2cd28123ee29932dda7c71d8c57af7e3e7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 20 Dec 2014 02:36:28 +0100 Subject: [PATCH 0070/1154] fix confirm layouts in multisig operation --- firmware/crypto.c | 3 ++- firmware/signing.c | 7 +++++++ firmware/transaction.c | 3 +++ trezor-crypto | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 9da57667f4..e8146f38a4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -25,6 +25,7 @@ #include "aes.h" #include "hmac.h" #include "bip32.h" +#include "layout2.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -264,7 +265,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) for (i = 0; i < hdnodepath->address_n_count; i++) { if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { return 0; - }; + } } return node.public_key; } diff --git a/firmware/signing.c b/firmware/signing.c index 1ee9e0e8cf..80643432d2 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -323,6 +323,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_3_OUTPUT: layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; co = compile_output(coin, root, tx->outputs, &bin_output, idx1i == 0); + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); signing_abort(); @@ -392,6 +393,11 @@ void signing_txack(TransactionType *tx) memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); + if (input.script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize multisig script"); + signing_abort(); + return; + } } else { // SPENDADDRESS input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); } @@ -422,6 +428,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; send_req_4_output(); } } diff --git a/firmware/transaction.c b/firmware/transaction.c index 2a75685ae5..0e45fba829 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -209,6 +209,9 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin out[r] = 0x01; r++; } uint32_t script_len = compile_script_multisig(multisig, 0); + if (script_len == 0) { + return 0; + } r += op_push(script_len, out + r); r += compile_script_multisig(multisig, out + r); return r; diff --git a/trezor-crypto b/trezor-crypto index 10a92c3c62..c6ca89a850 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 10a92c3c6276d5b1955331b7a33ebe9d6a32c37e +Subproject commit c6ca89a8507bd9310c0c92c180525989629fb7d4 From 7000451f71b924f99c6e03a9b610147369b912fb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 20 Dec 2014 20:34:19 +0100 Subject: [PATCH 0071/1154] implement OutputScriptType_PAYTOMULTISIG, reorganize compile_output code --- firmware/transaction.c | 103 +++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index 0e45fba829..3d45983789 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -26,6 +26,8 @@ #include "protect.h" #include "layout2.h" #include "crypto.h" +#include "ripemd160.h" +#include "base58.h" #include "messages.pb.h" uint32_t op_push(uint32_t i, uint8_t *out) { @@ -54,44 +56,45 @@ uint32_t op_push(uint32_t i, uint8_t *out) { int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) { - // address_n provided-> change address -> calculate from address_n - if (in->address_n_count > 0) { - HDNode node; - uint32_t k; - memcpy(&node, root, sizeof(HDNode)); - for (k = 0; k < in->address_n_count; k++) { - if (hdnode_private_ckd(&node, in->address_n[k]) == 0) { - return 0; - } - } - ecdsa_get_address(node.public_key, coin->address_type, in->address); - } else - if (in->has_address) { // address provided -> regular output - if (needs_confirm) { - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; - } - } - } else { // does not have address_n neither address - return 0; - } - memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; + uint8_t addr_raw[21]; if (in->script_type == OutputScriptType_PAYTOADDRESS) { + + // address_n provided-> change address -> calculate from address_n + if (in->address_n_count > 0) { + HDNode node; + uint32_t k; + memcpy(&node, root, sizeof(HDNode)); + for (k = 0; k < in->address_n_count; k++) { + if (hdnode_private_ckd(&node, in->address_n[k]) == 0) { + return 0; + } + } + ecdsa_get_address_raw(node.public_key, coin->address_type, addr_raw); + } else + if (in->has_address) { // address provided -> regular output + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; + } + } + if (!ecdsa_address_decode(in->address, addr_raw)) { + return 0; + } + if (addr_raw[0] != coin->address_type) { + return 0; + } + } else { // does not have address_n neither address -> error + return 0; + } + out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - uint8_t decoded[21]; - if (!ecdsa_address_decode(in->address, decoded)) { - return 0; - } - if (decoded[0] != coin->address_type) { - return 0; - } - memcpy(out->script_pubkey.bytes + 3, decoded + 1, 20); + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; @@ -99,16 +102,46 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) { + if (!in->has_address || !ecdsa_address_decode(in->address, addr_raw)) { + return 0; + } + if (addr_raw[0] != 0x05) { // 0x05 is P2SH + return 0; + } + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; + } + } out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - uint8_t decoded[21]; - if (!ecdsa_address_decode(in->address, decoded)) { + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + return 23; + } + + if (in->script_type == OutputScriptType_PAYTOMULTISIG) { + uint8_t buf[32]; + if (!in->has_multisig) { return 0; } - if (decoded[0] != 0x05) { // 0x05 is P2SH + if (compile_script_multisig_hash(&(in->multisig), buf) == 0) { return 0; } - memcpy(out->script_pubkey.bytes + 2, decoded + 1, 20); + addr_raw[0] = 0x05; + ripemd160(buf, 32, addr_raw + 1); + if (needs_confirm) { + base58_encode_check(addr_raw, 21, in->address); + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; + } + } + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; return 23; From 0898c707d97f03416d9a0d070f4c2c81dabca6da Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 20 Dec 2014 20:55:32 +0100 Subject: [PATCH 0072/1154] move change logic before confirmation --- firmware/signing.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 80643432d2..e71b208b5e 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -322,7 +322,26 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_3_OUTPUT: layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; - co = compile_output(coin, root, tx->outputs, &bin_output, idx1i == 0); + bool is_change = false; + if (idx1i == 0) { + if (tx->outputs[0].has_multisig) { + is_change = false; // TODO: detect when not needed + } else + if (tx->outputs[0].address_n_count > 0) { // address_n set -> change address + is_change = true; + } + if (is_change) { + if (change_spend == 0) { // not set + change_spend = tx->outputs[0].amount; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + signing_abort(); + return; + } + } + spending += tx->outputs[0].amount; + } + co = compile_output(coin, root, tx->outputs, &bin_output, idx1i == 0 && !is_change); layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); @@ -343,18 +362,6 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx1i == 0) { - if (tx->outputs[0].address_n_count > 0) { // address_n set -> change address - if (change_spend == 0) { // not set - change_spend = tx->outputs[0].amount; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); - signing_abort(); - return; - } - } - spending += tx->outputs[0].amount; - } if (idx3o < outputs_count - 1) { idx3o++; send_req_3_output(); From 03a053c944a1da30d3524a6df7d6d7e698b82018 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 21 Dec 2014 00:15:46 +0100 Subject: [PATCH 0073/1154] implement change logic for multisig --- firmware/crypto.c | 41 +++++++++++++++++++---------------------- firmware/signing.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 25 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index e8146f38a4..bfa7122758 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -285,26 +285,24 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { const uint32_t n = multisig->pubkeys_count; - const int max_pubkeys = pb_arraysize(MultisigRedeemScriptType, pubkeys); - uint8_t order[max_pubkeys], swap; + if (n > 15) { + return 0; + } + const HDNodePathType *ptr[n], *swap; uint32_t i, j; - const HDNodeType *a, *b; // check sanity for (i = 0; i < n; i++) { - order[i] = i; - a = &(multisig->pubkeys[i].node); - if (!a->has_public_key || a->public_key.size != 33) return 0; - if (a->chain_code.size != 32) return 0; + ptr[i] = &(multisig->pubkeys[i]); + if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; + if (ptr[i]->node.chain_code.size != 32) return 0; } - // (bubble) sort according to pubkey - for (i = 0; i < n; i++) { - for (j = i; j < n; j++) { - a = &(multisig->pubkeys[order[i]].node); - b = &(multisig->pubkeys[order[j]].node); - if (memcmp(a->public_key.bytes, b->public_key.bytes, 33) > 0) { - swap = order[i]; - order[i] = order[j]; - order[j] = swap; + // minsort according to pubkey + for (i = 0; i < n - 1; i++) { + for (j = n - 1; j > i; j--) { + if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, 33) > 0) { + swap = ptr[i]; + ptr[i] = ptr[j]; + ptr[j] = swap; } } } @@ -312,12 +310,11 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t SHA256_CTX ctx; sha256_Init(&ctx); for (i = 0; i < n; i++) { - a = &(multisig->pubkeys[order[i]].node); - sha256_Update(&ctx, (const uint8_t *)a->depth, sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)a->fingerprint, sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)a->child_num, sizeof(uint32_t)); - sha256_Update(&ctx, a->chain_code.bytes, 32); - sha256_Update(&ctx, a->public_key.bytes, 33); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), sizeof(uint32_t)); + sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); + sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); } sha256_Final(hash, &ctx); return 1; diff --git a/firmware/signing.c b/firmware/signing.c index e71b208b5e..00ec93165d 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -218,6 +218,8 @@ void signing_txack(TransactionType *tx) } int co; + static bool multisig_fp_set, multisig_fp_mismatch; + static uint8_t multisig_fp[32]; memset(&resp, 0, sizeof(TxRequest)); @@ -225,6 +227,8 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; memcpy(&input, tx->inputs, sizeof(TxInputType)); + multisig_fp_set = false; + multisig_fp_mismatch = false; send_req_2_prev_meta(); return; case STAGE_REQUEST_2_PREV_META: @@ -277,6 +281,29 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + if (idx1i == 0) { + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && + tx->inputs[0].has_multisig && !multisig_fp_mismatch) { + if (multisig_fp_set) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + multisig_fp_set = true; + } + } + } if (idx3i == idx1i) { memcpy(&node, root, sizeof(HDNode)); uint32_t k; @@ -324,10 +351,21 @@ void signing_txack(TransactionType *tx) layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; bool is_change = false; if (idx1i == 0) { - if (tx->outputs[0].has_multisig) { - is_change = false; // TODO: detect when not needed + if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && + tx->outputs[0].has_multisig && + multisig_fp_set && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) == 0) { + is_change = true; + } } else - if (tx->outputs[0].address_n_count > 0) { // address_n set -> change address + if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && + tx->outputs[0].address_n_count > 0) { is_change = true; } if (is_change) { From 2a2eba7de5c363778a8c6ee2605f58c338a4b233 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 21 Dec 2014 18:58:56 +0100 Subject: [PATCH 0074/1154] rework layoutProgress functions --- bootloader/usb.c | 8 +++++--- firmware/crypto.c | 5 ++++- firmware/fsm.c | 12 ++++++------ firmware/layout2.c | 4 ++-- firmware/layout2.h | 2 +- firmware/signing.c | 43 ++++++++++++++++++++++++++++-------------- firmware/storage.c | 7 +++---- firmware/transaction.c | 13 ++++++++----- layout.c | 14 ++++++++++++-- layout.h | 4 +++- 10 files changed, 73 insertions(+), 39 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 1e36c95228..4de353c030 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -320,7 +320,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) buttonUpdate(); } while (!button.YesUp && !button.NoUp); if (button.YesUp) { - layoutProgress("INSTALLING ... Please wait", 0, 0); + layoutProgress("INSTALLING ... Please wait", 0); // backup metadata memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); flash_unlock(); @@ -392,7 +392,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } p = buf + 1; - layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len, flash_anim / 8); + if (flash_anim % 8 == 4) { + layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); + } flash_anim++; flash_unlock(); while (p < buf + 64 && flash_pos < flash_len) { @@ -440,7 +442,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) bool hash_check_ok = button.YesUp; - layoutProgress("INSTALLING ... Please wait", 1000, 0); + layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); // check if to restore old storage area but only if signatures are ok if ((flags & 0x01) && signatures_ok()) { diff --git a/firmware/crypto.c b/firmware/crypto.c index bfa7122758..ea094fbdd0 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -25,7 +25,7 @@ #include "aes.h" #include "hmac.h" #include "bip32.h" -#include "layout2.h" +#include "layout.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -261,11 +261,13 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node) == 0) { return 0; } + layoutProgressUpdate(true); uint32_t i; for (i = 0; i < hdnodepath->address_n_count; i++) { if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { return 0; } + layoutProgressUpdate(true); } return node.public_key; } @@ -317,5 +319,6 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); } sha256_Final(hash, &ctx); + layoutProgressUpdate(true); return 1; } diff --git a/firmware/fsm.c b/firmware/fsm.c index 8f8af81b5a..128aee1967 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -93,7 +93,7 @@ int fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) { size_t i; if (address_n_count > 3) { - layoutProgressSwipe("Preparing keys", 0, 0); + layoutProgressSwipe("Preparing keys", 0); } for (i = 0; i < address_n_count; i++) { if (hdnode_private_ckd(node, address_n[i]) == 0) { @@ -102,7 +102,7 @@ int fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) return 0; } if (address_n_count > 3) { - layoutProgress("Preparing keys", 1000 * i / address_n_count, i); + layoutProgress("Preparing keys", 1000 * i / address_n_count); } } return 1; @@ -572,7 +572,7 @@ void fsm_msgSignMessage(SignMessage *msg) } if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; - layoutProgressSwipe("Signing", 0, 0); + layoutProgressSwipe("Signing", 0); if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; @@ -597,7 +597,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) fsm_sendFailure(FailureType_Failure_Other, "No message provided"); return; } - layoutProgressSwipe("Verifying", 0, 0); + layoutProgressSwipe("Verifying", 0); uint8_t addr_raw[21]; if (!ecdsa_address_decode(msg->address, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); @@ -656,7 +656,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) layoutHome(); return; } - layoutProgressSwipe("Encrypting", 0, 0); + layoutProgressSwipe("Encrypting", 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error encrypting message"); layoutHome(); @@ -696,7 +696,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) if (!node) return; if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; - layoutProgressSwipe("Decrypting", 0, 0); + layoutProgressSwipe("Decrypting", 0); RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; diff --git a/firmware/layout2.c b/firmware/layout2.c index 454fdfdc21..0e6291884f 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -37,7 +37,7 @@ void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btn layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, line6); } -void layoutProgressSwipe(const char *desc, int permil, int gearstep) +void layoutProgressSwipe(const char *desc, int permil) { if (layoutLast == layoutProgressSwipe) { oledClear(); @@ -45,7 +45,7 @@ void layoutProgressSwipe(const char *desc, int permil, int gearstep) layoutLast = layoutProgressSwipe; oledSwipeLeft(); } - layoutProgress(desc, permil, gearstep); + layoutProgress(desc, permil); } void layoutHome(void) diff --git a/firmware/layout2.h b/firmware/layout2.h index df4c0d2ff3..bd9be4cb84 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -24,7 +24,7 @@ #include "types.pb.h" void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); -void layoutProgressSwipe(const char *desc, int permil, int gearstep); +void layoutProgressSwipe(const char *desc, int permil); void layoutHome(void); void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); diff --git a/firmware/signing.c b/firmware/signing.c index 00ec93165d..a9f33672a4 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -51,6 +51,8 @@ static uint64_t to_spend, spending, change_spend; const uint32_t version = 1; const uint32_t lock_time = 0; static uint32_t progress, progress_total; +static bool multisig_fp_set, multisig_fp_mismatch; +static uint8_t multisig_fp[32]; /* Workflow of streamed signing @@ -96,6 +98,7 @@ foreach I: void send_req_1_input(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); idx2i = idx2o = idx3i = idx3o = 0; signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; @@ -108,6 +111,7 @@ void send_req_1_input(void) void send_req_2_prev_meta(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_META; resp.has_request_type = true; resp.request_type = RequestType_TXMETA; @@ -120,6 +124,7 @@ void send_req_2_prev_meta(void) void send_req_2_prev_input(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; @@ -134,6 +139,7 @@ void send_req_2_prev_input(void) void send_req_2_prev_output(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -148,6 +154,7 @@ void send_req_2_prev_output(void) void send_req_3_input(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_3_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; @@ -159,6 +166,7 @@ void send_req_3_input(void) void send_req_3_output(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_3_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -170,6 +178,7 @@ void send_req_3_output(void) void send_req_4_output(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_4_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -181,6 +190,7 @@ void send_req_4_output(void) void send_req_finished(void) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); resp.has_request_type = true; resp.request_type = RequestType_TXFINISHED; msg_write(MessageType_MessageType_TxRequest, &resp); @@ -202,10 +212,15 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp signing = true; progress = 1; - progress_total = inputs_count * (1 + inputs_count + outputs_count) + outputs_count; + progress_total = inputs_count * (1 + inputs_count + outputs_count) + outputs_count + 1; + + multisig_fp_set = false; + multisig_fp_mismatch = false; tx_init(&to, inputs_count, outputs_count, version, lock_time, false); + layoutProgressSwipe("Signing transaction", 0); + send_req_1_input(); } @@ -217,18 +232,15 @@ void signing_txack(TransactionType *tx) return; } - int co; - static bool multisig_fp_set, multisig_fp_mismatch; - static uint8_t multisig_fp[32]; + layoutProgress("Signing transaction", 1000 * progress / progress_total); + int co; memset(&resp, 0, sizeof(TxRequest)); switch (signing_stage) { case STAGE_REQUEST_1_INPUT: - layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; + progress++; memcpy(&input, tx->inputs, sizeof(TxInputType)); - multisig_fp_set = false; - multisig_fp_mismatch = false; send_req_2_prev_meta(); return; case STAGE_REQUEST_2_PREV_META: @@ -275,7 +287,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_3_INPUT: - layoutProgress("Preparing", 1000 * progress / progress_total, progress); progress++; + progress++; if (!tx_hash_input(&tc, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); @@ -348,9 +360,9 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_3_OUTPUT: - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; - bool is_change = false; + progress++; if (idx1i == 0) { + bool is_change = false; if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && tx->outputs[0].has_multisig && multisig_fp_set && !multisig_fp_mismatch) { @@ -378,9 +390,13 @@ void signing_txack(TransactionType *tx) } } spending += tx->outputs[0].amount; + co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); + if (!is_change) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); + } + } else { + co = compile_output(coin, root, tx->outputs, &bin_output, false); } - co = compile_output(coin, root, tx->outputs, &bin_output, idx1i == 0 && !is_change); - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); signing_abort(); @@ -473,13 +489,12 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; send_req_4_output(); } } return; case STAGE_REQUEST_4_OUTPUT: - layoutProgress("Signing", 1000 * progress / progress_total, progress); progress++; + progress++; if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); signing_abort(); diff --git a/firmware/storage.c b/firmware/storage.c index 05dc8cbea1..369dabfbce 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -216,8 +216,7 @@ void storage_setPassphraseProtection(bool passphrase_protection) void get_root_node_callback(uint32_t iter, uint32_t total) { - static uint8_t i; - layoutProgress("Waking up", 1000 * iter / total, i++); + layoutProgress("Waking up", 1000 * iter / total); } bool storage_getRootNode(HDNode *node) @@ -239,7 +238,7 @@ bool storage_getRootNode(HDNode *node) if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) { // decrypt hd node uint8_t secret[64]; - layoutProgressSwipe("Waking up", 0, 0); + layoutProgressSwipe("Waking up", 0); pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (uint8_t *)"TREZORHD", 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); @@ -257,7 +256,7 @@ bool storage_getRootNode(HDNode *node) return false; } uint8_t seed[64]; - layoutProgressSwipe("Waking up", 0, 0); + layoutProgressSwipe("Waking up", 0); mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039 if (hdnode_from_seed(seed, sizeof(seed), &sessionRootNode) == 0) { return false; diff --git a/firmware/transaction.c b/firmware/transaction.c index 3d45983789..e851399c46 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -67,10 +67,12 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T HDNode node; uint32_t k; memcpy(&node, root, sizeof(HDNode)); + layoutProgressUpdate(true); for (k = 0; k < in->address_n_count; k++) { if (hdnode_private_ckd(&node, in->address_n[k]) == 0) { return 0; } + layoutProgressUpdate(true); } ecdsa_get_address_raw(node.public_key, coin->address_type, addr_raw); } else @@ -201,17 +203,18 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, SHA256_CTX ctx; sha256_Init(&ctx); - uint8_t d; - d = 0x50 + m; sha256_Update(&ctx, &d, 1); + uint8_t d[2]; + d[0] = 0x50 + m; sha256_Update(&ctx, d, 1); uint32_t i; for (i = 0; i < n; i++) { - d = 33; sha256_Update(&ctx, &d, 1); // OP_PUSH 33 + d[0] = 33; sha256_Update(&ctx, d, 1); // OP_PUSH 33 const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (!pubkey) return 0; sha256_Update(&ctx, pubkey, 33); } - d = 0x50 + n; sha256_Update(&ctx, &d, 1); - d = 0xAE; sha256_Update(&ctx, &d, 1); + d[0] = 0x50 + n; + d[1] = 0xAE; + sha256_Update(&ctx, d, 2); sha256_Final(hash, &ctx); diff --git a/layout.c b/layout.c index 6513c7cf5b..ae082eea7e 100644 --- a/layout.c +++ b/layout.c @@ -79,11 +79,21 @@ void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, oledRefresh(); } -void layoutProgress(const char *desc, int permil, int gearstep) +void layoutProgressUpdate(bool refresh) { + static uint8_t step = 0; const BITMAP *bmp_gears[4] = { &bmp_gears0, &bmp_gears1, &bmp_gears2, &bmp_gears3 }; + oledDrawBitmap(40, 0, bmp_gears[step]); + step = (step + 1) % 4; + if (refresh) { + oledRefresh(); + } +} + +void layoutProgress(const char *desc, int permil) +{ oledClear(); - oledDrawBitmap(40, 0, bmp_gears[gearstep % 4]); + layoutProgressUpdate(false); // progressbar oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); diff --git a/layout.h b/layout.h index 71e8191890..c7f127a92d 100644 --- a/layout.h +++ b/layout.h @@ -21,6 +21,7 @@ #define __LAYOUT_H__ #include +#include typedef enum { DIALOG_NOICON = 0, @@ -32,6 +33,7 @@ typedef enum { } LayoutDialogIcon; void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); -void layoutProgress(const char *desc, int permil, int gearstep); +void layoutProgressUpdate(bool refresh); +void layoutProgress(const char *desc, int permil); #endif From 30a55829e5b31f0f437ce03782b74a692178ecdf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 21 Dec 2014 19:39:20 +0100 Subject: [PATCH 0075/1154] rework hashing of transactions --- firmware/crypto.c | 18 +++++++ firmware/crypto.h | 3 ++ firmware/signing.c | 16 +++--- firmware/transaction.c | 113 +++++++++++++++++++++++++++++++---------- firmware/transaction.h | 8 +-- 5 files changed, 118 insertions(+), 40 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index ea094fbdd0..82d4ed7b6d 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -47,6 +47,24 @@ uint32_t ser_length(uint32_t len, uint8_t *out) return 5; } +uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len) +{ + if (len < 253) { + sha256_Update(ctx, (const uint8_t *)&len, 1); + return 1; + } + if (len < 0x10000) { + uint8_t d = 253; + sha256_Update(ctx, &d, 1); + sha256_Update(ctx, (const uint8_t *)&len, 2); + return 3; + } + uint8_t d = 254; + sha256_Update(ctx, &d, 1); + sha256_Update(ctx, (const uint8_t *)&len, 4); + return 5; +} + uint32_t deser_length(const uint8_t *in, uint32_t *out) { if (in[0] < 253) { diff --git a/firmware/crypto.h b/firmware/crypto.h index 83af40c0d9..63b011c673 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -24,11 +24,14 @@ #include #include #include +#include #include #include "types.pb.h" uint32_t ser_length(uint32_t len, uint8_t *out); +uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); + int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/signing.c b/firmware/signing.c index a9f33672a4..f3f8bf6dbb 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -248,7 +248,7 @@ void signing_txack(TransactionType *tx) send_req_2_prev_input(); return; case STAGE_REQUEST_2_PREV_INPUT: - if (!tx_hash_input(&tp, tx->inputs)) { + if (!tx_serialize_input_hash(&tp, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); return; @@ -261,7 +261,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_OUTPUT: - if (!tx_hash_output(&tp, tx->bin_outputs)) { + if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); return; @@ -288,7 +288,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_3_INPUT: progress++; - if (!tx_hash_input(&tc, tx->inputs)) { + if (!tx_serialize_input_hash(&tc, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); return; @@ -347,7 +347,7 @@ void signing_txack(TransactionType *tx) } else { tx->inputs[0].script_sig.size = 0; } - if (!tx_hash_input(&ti, tx->inputs)) { + if (!tx_serialize_input_hash(&ti, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); return; @@ -406,12 +406,12 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (!tx_hash_output(&tc, &bin_output)) { + if (!tx_serialize_output_hash(&tc, &bin_output)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); return; } - if (!tx_hash_output(&ti, &bin_output)) { + if (!tx_serialize_output_hash(&ti, &bin_output)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); return; @@ -462,7 +462,7 @@ void signing_txack(TransactionType *tx) } else { // SPENDADDRESS input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); } - resp.serialized.serialized_tx.size = tx_serialize_input(&to, input.prev_hash.bytes, input.prev_index, input.script_sig.bytes, input.script_sig.size, input.sequence, resp.serialized.serialized_tx.bytes); + resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); if (idx1i < inputs_count - 1) { idx1i++; send_req_1_input(); @@ -502,7 +502,7 @@ void signing_txack(TransactionType *tx) } resp.has_serialized = true; resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_output(&to, bin_output.amount, bin_output.script_pubkey.bytes, bin_output.script_pubkey.size, resp.serialized.serialized_tx.bytes); + resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); if (idx4o < outputs_count - 1) { idx4o++; send_req_4_output(); diff --git a/firmware/transaction.c b/firmware/transaction.c index e851399c46..c224f4191d 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -29,6 +29,7 @@ #include "ripemd160.h" #include "base58.h" #include "messages.pb.h" +#include "types.pb.h" uint32_t op_push(uint32_t i, uint8_t *out) { if (i < 0x4C) { @@ -261,7 +262,13 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) return 4 + ser_length(tx->inputs_len, out + 4); } -uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out) +uint32_t tx_serialize_header_hash(TxStruct *tx) +{ + sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4); + return 4 + ser_length_hash(&(tx->ctx), tx->inputs_len); +} + +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) { int i; if (tx->have_inputs >= tx->inputs_len) { @@ -273,13 +280,39 @@ uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_inde r += tx_serialize_header(tx, out + r); } for (i = 0; i < 32; i++) { - *(out + r + i) = prev_hash[31 - i]; + *(out + r + i) = input->prev_hash.bytes[31 - i]; } r += 32; - memcpy(out + r, &prev_index, 4); r += 4; - r += ser_length(script_sig_len, out + r); - memcpy(out + r, script_sig, script_sig_len); r+= script_sig_len; - memcpy(out + r, &sequence, 4); r += 4; + memcpy(out + r, &input->prev_index, 4); r += 4; + r += ser_length(input->script_sig.size, out + r); + memcpy(out + r, input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; + memcpy(out + r, &input->sequence, 4); r += 4; + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) +{ + int i; + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + for (i = 0; i < 32; i++) { + sha256_Update(&(tx->ctx), &(input->prev_hash.bytes[31 - i]), 1); + } + r += 32; + sha256_Update(&(tx->ctx), (const uint8_t *)&input->prev_index, 4); r += 4; + r += ser_length_hash(&(tx->ctx), input->script_sig.size); + sha256_Update(&(tx->ctx), input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; + sha256_Update(&(tx->ctx), (const uint8_t *)&input->sequence, 4); r += 4; tx->have_inputs++; tx->size += r; @@ -292,6 +325,11 @@ uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) return ser_length(tx->outputs_len, out); } +uint32_t tx_serialize_middle_hash(TxStruct *tx) +{ + return ser_length_hash(&(tx->ctx), tx->outputs_len); +} + uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); @@ -304,7 +342,19 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) } } -uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out) +uint32_t tx_serialize_footer_hash(TxStruct *tx) +{ + sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->lock_time), 4); + if (tx->add_hash_type) { + uint32_t ht = 1; + sha256_Update(&(tx->ctx), (const uint8_t *)&ht, 4); + return 8; + } else { + return 4; + } +} + +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) { if (tx->have_inputs < tx->inputs_len) { // not all inputs provided @@ -318,9 +368,9 @@ uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubk if (tx->have_outputs == 0) { r += tx_serialize_middle(tx, out + r); } - memcpy(out + r, &amount, 8); r += 8; - r += ser_length(script_pubkey_len, out + r); - memcpy(out + r, script_pubkey, script_pubkey_len); r+= script_pubkey_len; + memcpy(out + r, &output->amount, 8); r += 8; + r += ser_length(output->script_pubkey.size, out + r); + memcpy(out + r, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; tx->have_outputs++; if (tx->have_outputs == tx->outputs_len) { r += tx_serialize_footer(tx, out + r); @@ -329,6 +379,31 @@ uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubk return r; } +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) +{ + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle_hash(tx); + } + sha256_Update(&(tx->ctx), (const uint8_t *)&output->amount, 8); r += 8; + r += ser_length_hash(&(tx->ctx), output->script_pubkey.size); + sha256_Update(&(tx->ctx), output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len) { + r += tx_serialize_footer_hash(tx); + } + tx->size += r; + return r; +} + void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type) { tx->inputs_len = inputs_len; @@ -342,24 +417,6 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v sha256_Init(&(tx->ctx)); } -bool tx_hash_input(TxStruct *t, TxInputType *input) -{ - uint8_t buf[1024]; - uint32_t r = tx_serialize_input(t, input->prev_hash.bytes, input->prev_index, input->script_sig.bytes, input->script_sig.size, input->sequence, buf); - if (!r) return false; - sha256_Update(&(t->ctx), buf, r); - return true; -} - -bool tx_hash_output(TxStruct *t, TxOutputBinType *output) -{ - uint8_t buf[1024]; - uint32_t r = tx_serialize_output(t, output->amount, output->script_pubkey.bytes, output->script_pubkey.size, buf); - if (!r) return false; - sha256_Update(&(t->ctx), buf, r); - return true; -} - void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { sha256_Final(hash, &(t->ctx)); diff --git a/firmware/transaction.h b/firmware/transaction.h index 7fb819aa3a..e6980a0416 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -47,12 +47,12 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); -uint32_t tx_serialize_input(TxStruct *tx, uint8_t *prev_hash, uint32_t prev_index, uint8_t *script_sig, uint32_t script_sig_len, uint32_t sequence, uint8_t *out); -uint32_t tx_serialize_output(TxStruct *tx, uint64_t amount, uint8_t *script_pubkey, uint32_t script_pubkey_len, uint8_t *out); +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type); -bool tx_hash_input(TxStruct *t, TxInputType *input); -bool tx_hash_output(TxStruct *t, TxOutputBinType *output); +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); From 1674edcbacf9f0d4dd8e214a2db8fd4f04143fe1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 22 Dec 2014 21:16:49 +0100 Subject: [PATCH 0076/1154] p2sh addresses can have 35 characters --- firmware/protob/messages.options | 8 ++++---- firmware/protob/messages.pb.h | 16 ++++++++-------- firmware/protob/types.options | 2 +- firmware/protob/types.pb.h | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 542ff906f8..11fdc49c01 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -30,7 +30,7 @@ PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 GetAddress.coin_name max_size:17 -Address.address max_size:35 +Address.address max_size:36 LoadDevice.mnemonic max_size:241 LoadDevice.pin max_size:10 @@ -51,11 +51,11 @@ SignMessage.address_n max_count:8 SignMessage.message max_size:1024 SignMessage.coin_name max_size:17 -VerifyMessage.address max_size:35 +VerifyMessage.address max_size:36 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 -MessageSignature.address max_size:35 +MessageSignature.address max_size:36 MessageSignature.signature max_size:65 EncryptMessage.pubkey max_size:33 @@ -72,7 +72,7 @@ DecryptMessage.nonce max_size:33 DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 DecryptMessage.hmac max_size:8 -DecryptedMessage.address max_size:35 +DecryptedMessage.address max_size:36 DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 75892f9f91..435f8d6b46 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -115,7 +115,7 @@ typedef struct _WordRequest { } WordRequest; typedef struct _Address { - char address[35]; + char address[36]; } Address; typedef struct _ApplySettings { @@ -226,7 +226,7 @@ typedef struct _DecryptedMessage { bool has_message; DecryptedMessage_message_t message; bool has_address; - char address[35]; + char address[36]; } DecryptedMessage; typedef PB_BYTES_ARRAY_T(33) EncryptMessage_pubkey_t; @@ -372,7 +372,7 @@ typedef PB_BYTES_ARRAY_T(65) MessageSignature_signature_t; typedef struct _MessageSignature { bool has_address; - char address[35]; + char address[36]; bool has_signature; MessageSignature_signature_t signature; } MessageSignature; @@ -495,7 +495,7 @@ typedef PB_BYTES_ARRAY_T(1024) VerifyMessage_message_t; typedef struct _VerifyMessage { bool has_address; - char address[35]; + char address[36]; bool has_signature; VerifyMessage_signature_t signature; bool has_message; @@ -819,7 +819,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define GetPublicKey_size 48 #define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size (75 + MultisigRedeemScriptType_size) -#define Address_size 37 +#define Address_size 38 #define WipeDevice_size 0 #define LoadDevice_size (320 + HDNodeType_size) #define ResetDevice_size 66 @@ -829,12 +829,12 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define WordRequest_size 0 #define WordAck_size 14 #define SignMessage_size 1094 -#define VerifyMessage_size 1131 -#define MessageSignature_size 104 +#define VerifyMessage_size 1132 +#define MessageSignature_size 105 #define EncryptMessage_size 1131 #define EncryptedMessage_size 1168 #define DecryptMessage_size 1216 -#define DecryptedMessage_size 1064 +#define DecryptedMessage_size 1065 #define CipherKeyValue_size 1340 #define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index ec464a60fd..c19d603a29 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -11,7 +11,7 @@ TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 -TxOutputType.address max_size:35 +TxOutputType.address max_size:36 TxOutputType.address_n max_count:8 TxOutputBinType.script_pubkey max_size:520 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 59fea49576..a71313c125 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -161,7 +161,7 @@ typedef struct _TxInputType { typedef struct _TxOutputType { bool has_address; - char address[35]; + char address[36]; pb_size_t address_n_count; uint32_t address_n[8]; uint64_t amount; @@ -284,9 +284,9 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; #define CoinType_size 47 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5497 -#define TxOutputType_size 3846 +#define TxOutputType_size 3847 #define TxOutputBinType_size 534 -#define TransactionType_size 9910 +#define TransactionType_size 9911 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 From 48cc36b1b9fe152312419acb8999c92d774e77c5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Dec 2014 01:33:08 +0100 Subject: [PATCH 0077/1154] adapt to new base58 api, use CoinType.address_type_p2sh field --- firmware/coins.c | 10 +++++----- firmware/fsm.c | 13 +++++++------ firmware/protob/types.pb.c | 7 +++++-- firmware/protob/types.pb.h | 13 +++++++++---- firmware/transaction.c | 6 +++--- trezor-common | 2 +- trezor-crypto | 2 +- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index c22fd4a5e7..db811e3619 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,11 +21,11 @@ #include "coins.h" const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 10000}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000}, - {true, "Litecoin", true, "LTC", true, 48, true, 10000000}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000}, + {true, "Bitcoin", true, "BTC", true, 0, true, 10000, true, 5}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, + {true, "Litecoin", true, "LTC", true, 48, true, 10000000, true, 5}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000, true, 22}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/fsm.c b/firmware/fsm.c index 128aee1967..7263f1f187 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -282,7 +282,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); resp->has_xpub = true; - hdnode_serialize_public(node, resp->xpub); + hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } @@ -506,6 +506,7 @@ void fsm_msgGetAddress(GetAddress *msg) if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; if (msg->has_multisig) { + layoutProgressSwipe("Preparing", 0); if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); layoutHome(); @@ -518,10 +519,10 @@ void fsm_msgGetAddress(GetAddress *msg) return; } ripemd160(buf, 32, buf + 1); - buf[0] = 0x05; // multisig cointype - base58_encode_check(buf, 21, resp->address); + buf[0] = coin->address_type_p2sh; // multisig cointype + base58_encode_check(buf, 21, resp->address, sizeof(resp->address)); } else { - ecdsa_get_address(node->public_key, coin->address_type, resp->address); + ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address)); } if (msg->has_show_display && msg->show_display) { @@ -577,7 +578,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); - base58_encode_check(addr_raw, 21, resp->address); + base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); @@ -707,7 +708,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) return; } if (signing) { - base58_encode_check(address_raw, 21, resp->address); + base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); } layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); protectButton(ButtonRequestType_ButtonRequest_Other, true); diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index ab937186c6..fa11a45766 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -7,6 +7,8 @@ #error Regenerate this file with the current version of nanopb generator. #endif +const uint32_t CoinType_address_type_default = 0u; +const uint32_t CoinType_address_type_p2sh_default = 5u; const uint32_t TxInputType_sequence_default = 4294967295u; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; @@ -27,11 +29,12 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[5] = { +const pb_field_t CoinType_fields[6] = { PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), - PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, 0), + PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), PB_FIELD( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index a71313c125..215ad3e766 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -75,6 +75,8 @@ typedef struct _CoinType { uint32_t address_type; bool has_maxfee_kb; uint64_t maxfee_kb; + bool has_address_type_p2sh; + uint32_t address_type_p2sh; } CoinType; typedef PB_BYTES_ARRAY_T(32) HDNodeType_chain_code_t; @@ -194,13 +196,15 @@ extern const pb_extension_type_t wire_debug_in; extern const pb_extension_type_t wire_debug_out; /* Default values for struct fields */ +extern const uint32_t CoinType_address_type_default; +extern const uint32_t CoinType_address_type_p2sh_default; extern const uint32_t TxInputType_sequence_default; extern const InputScriptType TxInputType_script_type_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0, false, 0} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default} @@ -210,7 +214,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero} @@ -224,6 +228,7 @@ extern const InputScriptType TxInputType_script_type_default; #define CoinType_coin_shortcut_tag 2 #define CoinType_address_type_tag 3 #define CoinType_maxfee_kb_tag 4 +#define CoinType_address_type_p2sh_tag 5 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -269,7 +274,7 @@ extern const InputScriptType TxInputType_script_type_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[5]; +extern const pb_field_t CoinType_fields[6]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; extern const pb_field_t TxOutputType_fields[6]; @@ -281,7 +286,7 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 47 +#define CoinType_size 53 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5497 #define TxOutputType_size 3847 diff --git a/firmware/transaction.c b/firmware/transaction.c index c224f4191d..08cca087ca 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -108,7 +108,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (!in->has_address || !ecdsa_address_decode(in->address, addr_raw)) { return 0; } - if (addr_raw[0] != 0x05) { // 0x05 is P2SH + if (addr_raw[0] != coin->address_type_p2sh) { return 0; } if (needs_confirm) { @@ -133,10 +133,10 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (compile_script_multisig_hash(&(in->multisig), buf) == 0) { return 0; } - addr_raw[0] = 0x05; + addr_raw[0] = coin->address_type_p2sh; ripemd160(buf, 32, addr_raw + 1); if (needs_confirm) { - base58_encode_check(addr_raw, 21, in->address); + base58_encode_check(addr_raw, 21, in->address, sizeof(in->address)); layoutConfirmOutput(coin, in); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; diff --git a/trezor-common b/trezor-common index 94d17ef8bc..60bcde46f5 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 94d17ef8bc56d7c0e6ddfed39e84987543259e05 +Subproject commit 60bcde46f584062e3a454bcdfdcf01bff927c8ea diff --git a/trezor-crypto b/trezor-crypto index c6ca89a850..89a7d7797b 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit c6ca89a8507bd9310c0c92c180525989629fb7d4 +Subproject commit 89a7d7797b806face0d023095c6f39c7869c5ff1 From 8660f675121eb1d77d457ec03fcec1db4da21e5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Dec 2014 18:18:53 +0100 Subject: [PATCH 0078/1154] update trezor-crypto --- trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezor-crypto b/trezor-crypto index 89a7d7797b..795579cbac 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 89a7d7797b806face0d023095c6f39c7869c5ff1 +Subproject commit 795579cbacb5e4bd072d7cef2a2638f1d44c2d0d From b06780e0a7c0cb99b054e166109666d8af8bd618 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 25 Dec 2014 14:43:32 +0100 Subject: [PATCH 0079/1154] prepare 1.3.0 release --- Dockerfile | 6 +++--- firmware-docker-build.sh | 11 ++--------- firmware/trezor.h | 4 ++-- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 81c4cf840d..57509c83a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497E # install build tools and dependencies -ENV GCC_ARM_VERSION 4-8-2014q2-0trusty10 +ENV GCC_ARM_VERSION 4.9.3.2014q4-0trusty12 RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION python # clone the source code @@ -17,10 +17,10 @@ RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://gith # build libopencm3 -ENV LIBOPENCM3_GITREV f6b6d62ec5628ebb0602c466ee9fd7a6070ef1f0 +ENV LIBOPENCM3_GITREV 8a15cec6bf99f59065879a14895fb8af8a8a53e7 RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make # build the firmware -ENV TREZOR_MCU_GITREV v1.2.1 +ENV TREZOR_MCU_GITREV v1.3.0 RUN cd trezor-mcu && git checkout $TREZOR_MCU_GITREV && git submodule update --init && make && cd firmware && make diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 3df89a88b3..21128d7e65 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,16 +1,9 @@ #!/bin/bash - -dirname $0 - IMAGETAG=trezor-mcu-build + docker rmi $IMAGETAG || : docker build -t $IMAGETAG . - -CONTAINERTAG=trezor-mcu-build -docker rm $CONTAINERTAG || : -docker run --name $CONTAINERTAG $IMAGETAG true - -docker cp $CONTAINERTAG:/trezor-mcu/firmware/trezor.bin . +docker run -t -v $(pwd):/output $IMAGETAG /bin/cp /trezor-mcu/firmware/trezor.bin /output echo "---------------------" echo "Firmware fingerprint:" diff --git a/firmware/trezor.h b/firmware/trezor.h index 001b7a4499..9ef2e81dd7 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,8 +21,8 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 2 -#define VERSION_PATCH 1 +#define VERSION_MINOR 3 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From b5eecb30be7712855cfa76fe671ef0b2e98e4aa9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 27 Dec 2014 14:32:25 +0100 Subject: [PATCH 0080/1154] downgrade nanopb to LTS version 0.2.9.1 --- firmware/Makefile | 2 +- firmware/crypto.c | 10 +- firmware/crypto.h | 8 +- firmware/protob/messages.pb.c | 250 +++++++++++++++++----------------- firmware/protob/messages.pb.h | 140 +++++++++++++------ firmware/protob/pb.h | 97 ++++++------- firmware/protob/pb_common.c | 90 ------------ firmware/protob/pb_common.h | 42 ------ firmware/protob/pb_decode.c | 196 +++++++++++++++++--------- firmware/protob/pb_decode.h | 6 +- firmware/protob/pb_encode.c | 55 ++++---- firmware/protob/pb_encode.h | 6 +- firmware/protob/storage.pb.c | 28 ++-- firmware/protob/storage.pb.h | 10 +- firmware/protob/types.pb.c | 100 +++++++------- firmware/protob/types.pb.h | 76 +++++++---- 16 files changed, 562 insertions(+), 554 deletions(-) delete mode 100644 firmware/protob/pb_common.c delete mode 100644 firmware/protob/pb_common.h diff --git a/firmware/Makefile b/firmware/Makefile index 5f97591157..74a642814e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -38,7 +38,7 @@ OBJS += ../trezor-crypto/aes_modes.o OBJS += ../trezor-qrenc/qr_encode.o -OBJS += protob/pb_common.o +# OBJS += protob/pb_common.o OBJS += protob/pb_decode.o OBJS += protob/pb_encode.o OBJS += protob/messages.pb.o diff --git a/firmware/crypto.c b/firmware/crypto.c index 82d4ed7b6d..ee2338ccab 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -83,7 +83,7 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } -int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature) +int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -101,7 +101,7 @@ int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8 return 0; } -int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) { bignum256 r, s, e; curve_point cp, cp2; @@ -164,7 +164,7 @@ int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uin // internal from ecdsa.c int generate_k_random(bignum256 *k); -int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_size, bool display_only, uint8_t *nonce, pb_size_t *nonce_len, uint8_t *payload, pb_size_t *payload_len, uint8_t *hmac, pb_size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) { if (privkey && address_raw) { // signing == true payload[0] = display_only ? 0x81 : 0x01; @@ -216,7 +216,7 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_ return 0; } -int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) { if (hmac_len != 8) { return 1; @@ -292,7 +292,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { - int i; + size_t i; for (i = 0; i < multisig->pubkeys_count; i++) { const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { diff --git a/firmware/crypto.h b/firmware/crypto.h index 63b011c673..4353aa635e 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -32,15 +32,15 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); -int cryptoMessageSign(const uint8_t *message, pb_size_t message_len, const uint8_t *privkey, uint8_t *signature); +int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); -int cryptoMessageVerify(const uint8_t *message, pb_size_t message_len, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); // ECIES: http://memwallet.info/btcmssgs.html -int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, pb_size_t msg_size, bool display_only, uint8_t *nonce, pb_size_t *nonce_len, uint8_t *payload, pb_size_t *payload_len, uint8_t *hmac, pb_size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); -int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, pb_size_t payload_len, const uint8_t *hmac, pb_size_t hmac_len, const uint8_t *privkey, uint8_t *msg, pb_size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 9dacf83b30..ac71a5b8da 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -1,12 +1,8 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ #include "messages.pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - const char GetAddress_coin_name_default[17] = "Bitcoin"; const char LoadDevice_language_default[17] = "english"; const uint32_t ResetDevice_strength_default = 128u; @@ -24,21 +20,21 @@ const pb_field_t Initialize_fields[1] = { }; const pb_field_t Features_fields[16] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), - PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), - PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), - PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), - PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), - PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), - PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), - PB_FIELD( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), - PB_FIELD( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), - PB_FIELD( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), - PB_FIELD( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), - PB_FIELD( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), - PB_FIELD( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), - PB_FIELD( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), - PB_FIELD( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), + PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), + PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), + PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), + PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), + PB_FIELD2( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), + PB_FIELD2( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), + PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), + PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), + PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), + PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), PB_LAST_FIELD }; @@ -47,39 +43,39 @@ const pb_field_t ClearSession_fields[1] = { }; const pb_field_t ApplySettings_fields[4] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), PB_LAST_FIELD }; const pb_field_t ChangePin_fields[2] = { - PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), + PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), PB_LAST_FIELD }; const pb_field_t Ping_fields[5] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), - PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), PB_LAST_FIELD }; const pb_field_t Success_fields[2] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), PB_LAST_FIELD }; const pb_field_t Failure_fields[3] = { - PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), PB_LAST_FIELD }; const pb_field_t ButtonRequest_fields[3] = { - PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), PB_LAST_FIELD }; @@ -88,12 +84,12 @@ const pb_field_t ButtonAck_fields[1] = { }; const pb_field_t PinMatrixRequest_fields[2] = { - PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), PB_LAST_FIELD }; const pb_field_t PinMatrixAck_fields[2] = { - PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), PB_LAST_FIELD }; @@ -106,41 +102,41 @@ const pb_field_t PassphraseRequest_fields[1] = { }; const pb_field_t PassphraseAck_fields[2] = { - PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), PB_LAST_FIELD }; const pb_field_t GetEntropy_fields[2] = { - PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), PB_LAST_FIELD }; const pb_field_t Entropy_fields[2] = { - PB_FIELD( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), + PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), PB_LAST_FIELD }; const pb_field_t GetPublicKey_fields[2] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), PB_LAST_FIELD }; const pb_field_t PublicKey_fields[3] = { - PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), + PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), PB_LAST_FIELD }; const pb_field_t GetAddress_fields[5] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), - PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), + PB_FIELD2( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; const pb_field_t Address_fields[2] = { - PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), PB_LAST_FIELD }; @@ -149,23 +145,23 @@ const pb_field_t WipeDevice_fields[1] = { }; const pb_field_t LoadDevice_fields[8] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), - PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), - PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), - PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), - PB_FIELD( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), + PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), PB_LAST_FIELD }; const pb_field_t ResetDevice_fields[7] = { - PB_FIELD( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), - PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), - PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), - PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), + PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), PB_LAST_FIELD }; @@ -174,17 +170,17 @@ const pb_field_t EntropyRequest_fields[1] = { }; const pb_field_t EntropyAck_fields[2] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), PB_LAST_FIELD }; const pb_field_t RecoveryDevice_fields[7] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), - PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), - PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), - PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), - PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), PB_LAST_FIELD }; @@ -193,111 +189,111 @@ const pb_field_t WordRequest_fields[1] = { }; const pb_field_t WordAck_fields[2] = { - PB_FIELD( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), + PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), PB_LAST_FIELD }; const pb_field_t SignMessage_fields[4] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), - PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), PB_LAST_FIELD }; const pb_field_t VerifyMessage_fields[4] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), PB_LAST_FIELD }; const pb_field_t MessageSignature_fields[3] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), PB_LAST_FIELD }; const pb_field_t EncryptMessage_fields[6] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), - PB_FIELD( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), - PB_FIELD( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), - PB_FIELD( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), + PB_FIELD2( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), PB_LAST_FIELD }; const pb_field_t EncryptedMessage_fields[4] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptedMessage, nonce, nonce, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, message, nonce, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, hmac, message, 0), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptedMessage, nonce, nonce, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, message, nonce, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, hmac, message, 0), PB_LAST_FIELD }; const pb_field_t DecryptMessage_fields[5] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, nonce, address_n, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, nonce, 0), - PB_FIELD( 4, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, hmac, message, 0), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, nonce, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, nonce, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, hmac, message, 0), PB_LAST_FIELD }; const pb_field_t DecryptedMessage_fields[3] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, DecryptedMessage, message, message, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptedMessage, address, message, 0), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DecryptedMessage, message, message, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptedMessage, address, message, 0), PB_LAST_FIELD }; const pb_field_t CipherKeyValue_fields[7] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), - PB_FIELD( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), - PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), + PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), PB_LAST_FIELD }; const pb_field_t CipheredKeyValue_fields[2] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, CipheredKeyValue, value, value, 0), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, CipheredKeyValue, value, value, 0), PB_LAST_FIELD }; const pb_field_t EstimateTxSize_fields[4] = { - PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), - PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), PB_LAST_FIELD }; const pb_field_t TxSize_fields[2] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), PB_LAST_FIELD }; const pb_field_t SignTx_fields[4] = { - PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), - PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), PB_LAST_FIELD }; const pb_field_t SimpleSignTx_fields[5] = { - PB_FIELD( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), - PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), - PB_FIELD( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), - PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), + PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), + PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), + PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), PB_LAST_FIELD }; const pb_field_t TxRequest_fields[4] = { - PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), - PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), - PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), + PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), PB_LAST_FIELD }; const pb_field_t TxAck_fields[2] = { - PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), + PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), PB_LAST_FIELD }; @@ -306,12 +302,12 @@ const pb_field_t FirmwareErase_fields[1] = { }; const pb_field_t FirmwareUpload_fields[2] = { - PB_FIELD( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), + PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), PB_LAST_FIELD }; const pb_field_t DebugLinkDecision_fields[2] = { - PB_FIELD( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), + PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), PB_LAST_FIELD }; @@ -320,16 +316,16 @@ const pb_field_t DebugLinkGetState_fields[1] = { }; const pb_field_t DebugLinkState_fields[11] = { - PB_FIELD( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), - PB_FIELD( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), - PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), - PB_FIELD( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), - PB_FIELD( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), - PB_FIELD( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), - PB_FIELD( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), - PB_FIELD( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), + PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), + PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), + PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), + PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), + PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), + PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), PB_LAST_FIELD }; @@ -338,9 +334,9 @@ const pb_field_t DebugLinkStop_fields[1] = { }; const pb_field_t DebugLinkLog_fields[4] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), PB_LAST_FIELD }; @@ -354,7 +350,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 435f8d6b46..aae1b549d9 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -1,15 +1,11 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ -#ifndef PB_MESSAGES_PB_H_INCLUDED -#define PB_MESSAGES_PB_H_INCLUDED +#ifndef _PB_MESSAGES_PB_H_ +#define _PB_MESSAGES_PB_H_ #include "pb.h" #include "types.pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - #ifdef __cplusplus extern "C" { #endif @@ -139,10 +135,13 @@ typedef struct _ChangePin { bool remove; } ChangePin; -typedef PB_BYTES_ARRAY_T(1024) CipherKeyValue_value_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} CipherKeyValue_value_t; typedef struct _CipherKeyValue { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; bool has_key; char key[256]; @@ -156,7 +155,10 @@ typedef struct _CipherKeyValue { bool ask_on_decrypt; } CipherKeyValue; -typedef PB_BYTES_ARRAY_T(1024) CipheredKeyValue_value_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} CipheredKeyValue_value_t; typedef struct _CipheredKeyValue { bool has_value; @@ -176,9 +178,15 @@ typedef struct _DebugLinkLog { char text[256]; } DebugLinkLog; -typedef PB_BYTES_ARRAY_T(1024) DebugLinkState_layout_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DebugLinkState_layout_t; -typedef PB_BYTES_ARRAY_T(128) DebugLinkState_reset_entropy_t; +typedef struct { + size_t size; + uint8_t bytes[128]; +} DebugLinkState_reset_entropy_t; typedef struct _DebugLinkState { bool has_layout; @@ -203,14 +211,23 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; -typedef PB_BYTES_ARRAY_T(33) DecryptMessage_nonce_t; +typedef struct { + size_t size; + uint8_t bytes[33]; +} DecryptMessage_nonce_t; -typedef PB_BYTES_ARRAY_T(1120) DecryptMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1120]; +} DecryptMessage_message_t; -typedef PB_BYTES_ARRAY_T(8) DecryptMessage_hmac_t; +typedef struct { + size_t size; + uint8_t bytes[8]; +} DecryptMessage_hmac_t; typedef struct _DecryptMessage { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; bool has_nonce; DecryptMessage_nonce_t nonce; @@ -220,7 +237,10 @@ typedef struct _DecryptMessage { DecryptMessage_hmac_t hmac; } DecryptMessage; -typedef PB_BYTES_ARRAY_T(1024) DecryptedMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DecryptedMessage_message_t; typedef struct _DecryptedMessage { bool has_message; @@ -229,9 +249,15 @@ typedef struct _DecryptedMessage { char address[36]; } DecryptedMessage; -typedef PB_BYTES_ARRAY_T(33) EncryptMessage_pubkey_t; +typedef struct { + size_t size; + uint8_t bytes[33]; +} EncryptMessage_pubkey_t; -typedef PB_BYTES_ARRAY_T(1024) EncryptMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EncryptMessage_message_t; typedef struct _EncryptMessage { bool has_pubkey; @@ -240,17 +266,26 @@ typedef struct _EncryptMessage { EncryptMessage_message_t message; bool has_display_only; bool display_only; - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; bool has_coin_name; char coin_name[17]; } EncryptMessage; -typedef PB_BYTES_ARRAY_T(33) EncryptedMessage_nonce_t; +typedef struct { + size_t size; + uint8_t bytes[33]; +} EncryptedMessage_nonce_t; -typedef PB_BYTES_ARRAY_T(1120) EncryptedMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1120]; +} EncryptedMessage_message_t; -typedef PB_BYTES_ARRAY_T(8) EncryptedMessage_hmac_t; +typedef struct { + size_t size; + uint8_t bytes[8]; +} EncryptedMessage_hmac_t; typedef struct _EncryptedMessage { bool has_nonce; @@ -261,13 +296,19 @@ typedef struct _EncryptedMessage { EncryptedMessage_hmac_t hmac; } EncryptedMessage; -typedef PB_BYTES_ARRAY_T(1024) Entropy_entropy_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} Entropy_entropy_t; typedef struct _Entropy { Entropy_entropy_t entropy; } Entropy; -typedef PB_BYTES_ARRAY_T(128) EntropyAck_entropy_t; +typedef struct { + size_t size; + uint8_t bytes[128]; +} EntropyAck_entropy_t; typedef struct _EntropyAck { bool has_entropy; @@ -288,9 +329,15 @@ typedef struct _Failure { char message[256]; } Failure; -typedef PB_BYTES_ARRAY_T(20) Features_revision_t; +typedef struct { + size_t size; + uint8_t bytes[20]; +} Features_revision_t; -typedef PB_BYTES_ARRAY_T(32) Features_bootloader_hash_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} Features_bootloader_hash_t; typedef struct _Features { bool has_vendor; @@ -313,7 +360,7 @@ typedef struct _Features { char language[17]; bool has_label; char label[33]; - pb_size_t coins_count; + size_t coins_count; CoinType coins[5]; bool has_initialized; bool initialized; @@ -325,14 +372,17 @@ typedef struct _Features { bool imported; } Features; -typedef PB_BYTES_ARRAY_T(0) FirmwareUpload_payload_t; +typedef struct { + size_t size; + uint8_t bytes[0]; +} FirmwareUpload_payload_t; typedef struct _FirmwareUpload { FirmwareUpload_payload_t payload; } FirmwareUpload; typedef struct _GetAddress { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; bool has_coin_name; char coin_name[17]; @@ -347,7 +397,7 @@ typedef struct _GetEntropy { } GetEntropy; typedef struct _GetPublicKey { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; } GetPublicKey; @@ -368,7 +418,10 @@ typedef struct _LoadDevice { bool skip_checksum; } LoadDevice; -typedef PB_BYTES_ARRAY_T(65) MessageSignature_signature_t; +typedef struct { + size_t size; + uint8_t bytes[65]; +} MessageSignature_signature_t; typedef struct _MessageSignature { bool has_address; @@ -437,10 +490,13 @@ typedef struct _ResetDevice { char label[33]; } ResetDevice; -typedef PB_BYTES_ARRAY_T(1024) SignMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} SignMessage_message_t; typedef struct _SignMessage { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; SignMessage_message_t message; bool has_coin_name; @@ -455,11 +511,11 @@ typedef struct _SignTx { } SignTx; typedef struct _SimpleSignTx { - pb_size_t inputs_count; + size_t inputs_count; TxInputType inputs[0]; - pb_size_t outputs_count; + size_t outputs_count; TxOutputType outputs[0]; - pb_size_t transactions_count; + size_t transactions_count; TransactionType transactions[0]; bool has_coin_name; char coin_name[17]; @@ -489,9 +545,15 @@ typedef struct _TxSize { uint32_t tx_size; } TxSize; -typedef PB_BYTES_ARRAY_T(65) VerifyMessage_signature_t; +typedef struct { + size_t size; + uint8_t bytes[65]; +} VerifyMessage_signature_t; -typedef PB_BYTES_ARRAY_T(1024) VerifyMessage_message_t; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} VerifyMessage_message_t; typedef struct _VerifyMessage { bool has_address; diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h index 34d14b0405..228ee55c14 100644 --- a/firmware/protob/pb.h +++ b/firmware/protob/pb.h @@ -2,8 +2,8 @@ * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. */ -#ifndef PB_H_INCLUDED -#define PB_H_INCLUDED +#ifndef _PB_H_ +#define _PB_H_ /***************************************************************** * Nanopb compilation time options. You can change these here by * @@ -46,7 +46,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.3.1 +#define NANOPB_VERSION nanopb-0.2.9.1 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: @@ -98,27 +98,23 @@ #endif /* Handly macro for suppressing unreferenced-parameter compiler warnings. */ -#ifndef PB_UNUSED -#define PB_UNUSED(x) (void)(x) +#ifndef UNUSED +#define UNUSED(x) (void)(x) #endif /* Compile-time assertion, used for checking compatible compilation options. - * If this does not work properly on your compiler, use - * #define PB_NO_STATIC_ASSERT to disable it. + * If this does not work properly on your compiler, use #define STATIC_ASSERT + * to disable it. * * But before doing that, check carefully the error message / place where it * comes from to see if the error has a real cause. Unfortunately the error * message is not always very clear to read, but you can see the reason better - * in the place where the PB_STATIC_ASSERT macro was called. + * in the place where the STATIC_ASSERT macro was called. */ -#ifndef PB_NO_STATIC_ASSERT -#ifndef PB_STATIC_ASSERT -#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; -#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) -#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER -#endif -#else -#define PB_STATIC_ASSERT(COND,MSG) +#ifndef STATIC_ASSERT +#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER #endif /* Number of required fields to keep track of. */ @@ -191,15 +187,12 @@ typedef uint8_t pb_type_t; * and array counts. */ #if defined(PB_FIELD_32BIT) -#define PB_SIZE_MAX ((uint32_t)-1) typedef uint32_t pb_size_t; typedef int32_t pb_ssize_t; #elif defined(PB_FIELD_16BIT) -#define PB_SIZE_MAX ((uint16_t)-1) typedef uint16_t pb_size_t; typedef int16_t pb_ssize_t; #else -#define PB_SIZE_MAX ((uint8_t)-1) typedef uint8_t pb_size_t; typedef int8_t pb_ssize_t; #endif @@ -213,8 +206,8 @@ typedef uint8_t pb_type_t; * PB_FIELD_32BIT. */ PB_PACKED_STRUCT_START -typedef struct pb_field_s pb_field_t; -struct pb_field_s { +typedef struct _pb_field_t pb_field_t; +struct _pb_field_t { pb_size_t tag; pb_type_t type; pb_size_t data_offset; /* Offset of field data, relative to previous field. */ @@ -235,27 +228,27 @@ PB_PACKED_STRUCT_END * If you get errors here, it probably means that your stdint.h is not * correct for your platform. */ -PB_STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) +STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) /* This structure is used for 'bytes' arrays. * It has the number of bytes in the beginning, and after that an array. * Note that actual structs used will have a different length of bytes array. */ -#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; uint8_t bytes[n]; } +#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; } #define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) -struct pb_bytes_array_s { - pb_size_t size; +struct _pb_bytes_array_t { + size_t size; uint8_t bytes[1]; }; -typedef struct pb_bytes_array_s pb_bytes_array_t; +typedef struct _pb_bytes_array_t pb_bytes_array_t; /* This structure is used for giving the callback function. * It is stored in the message structure and filled in by the method that @@ -275,10 +268,10 @@ typedef struct pb_bytes_array_s pb_bytes_array_t; * * The callback can be null if you want to skip a field. */ -typedef struct pb_istream_s pb_istream_t; -typedef struct pb_ostream_s pb_ostream_t; -typedef struct pb_callback_s pb_callback_t; -struct pb_callback_s { +typedef struct _pb_istream_t pb_istream_t; +typedef struct _pb_ostream_t pb_ostream_t; +typedef struct _pb_callback_t pb_callback_t; +struct _pb_callback_t { #ifdef PB_OLD_CALLBACK_STYLE /* Deprecated since nanopb-0.2.1 */ union { @@ -311,9 +304,9 @@ typedef enum { * if you want to catch all unknown fields, you can also create a custom * pb_extension_type_t with your own callback. */ -typedef struct pb_extension_type_s pb_extension_type_t; -typedef struct pb_extension_s pb_extension_t; -struct pb_extension_type_s { +typedef struct _pb_extension_type_t pb_extension_type_t; +typedef struct _pb_extension_t pb_extension_t; +struct _pb_extension_type_t { /* Called for each unknown field in the message. * If you handle the field, read off all of its data and return true. * If you do not handle the field, do not read anything and return true. @@ -335,7 +328,7 @@ struct pb_extension_type_s { const void *arg; }; -struct pb_extension_s { +struct _pb_extension_t { /* Type describing the extension field. Usually you'll initialize * this to a pointer to the automatically generated structure. */ const pb_extension_type_t *type; @@ -365,9 +358,6 @@ struct pb_extension_s { # endif #endif -/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ -#define PB_PROTO_HEADER_VERSION 30 - /* These macros are used to declare pb_field_t's in the constant array. */ /* Size of a structure member, in bytes. */ #define pb_membersize(st, m) (sizeof ((st*)0)->m) @@ -479,15 +469,26 @@ struct pb_extension_s { * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION * - Field rules: REQUIRED, OPTIONAL or REPEATED * - Allocation: STATIC or CALLBACK - * - Placement: FIRST or OTHER, depending on if this is the first field in structure. * - Message name * - Field name * - Previous field name (or field name again for first field) * - Pointer to default value or submsg fields. */ -#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ +#define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_CHOOSE(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* This is a new version of the macro used by nanopb generator from + * version 0.2.3 onwards. It avoids the use of a ternary expression in + * the initialization, which confused some compilers. + * + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * + */ +#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ PB_DATAOFFSET_ ## placement(message, field, prevfield), \ PB_LTYPE_MAP_ ## type, ptr) @@ -501,7 +502,7 @@ struct pb_extension_s { #ifdef PB_NO_ERRMSG #define PB_RETURN_ERROR(stream,msg) \ do {\ - PB_UNUSED(stream); \ + UNUSED(stream); \ return false; \ } while(0) #define PB_GET_ERROR(stream) "(errmsg disabled)" diff --git a/firmware/protob/pb_common.c b/firmware/protob/pb_common.c deleted file mode 100644 index a9cade6391..0000000000 --- a/firmware/protob/pb_common.c +++ /dev/null @@ -1,90 +0,0 @@ -/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. - * - * 2014 Petteri Aimonen - */ - -#include "pb_common.h" - -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) -{ - iter->start = fields; - iter->pos = fields; - iter->required_field_index = 0; - iter->dest_struct = dest_struct; - iter->pData = (char*)dest_struct + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - - return (iter->pos->tag != 0); -} - -bool pb_field_iter_next(pb_field_iter_t *iter) -{ - const pb_field_t *prev_field = iter->pos; - - if (prev_field->tag == 0) - { - /* Handle empty message types, where the first field is already the terminator. - * In other cases, the iter->pos never points to the terminator. */ - return false; - } - - iter->pos++; - - if (iter->pos->tag == 0) - { - /* Wrapped back to beginning, reinitialize */ - (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); - return false; - } - else - { - /* Increment the pointers based on previous field size */ - size_t prev_size = prev_field->data_size; - - if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && - PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) - { - /* In static arrays, the data_size tells the size of a single entry and - * array_size is the number of entries */ - prev_size *= prev_field->array_size; - } - else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) - { - /* Pointer fields always have a constant size in the main structure. - * The data_size only applies to the dynamically allocated area. */ - prev_size = sizeof(void*); - } - - if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) - { - /* Count the required fields, in order to check their presence in the - * decoder. */ - iter->required_field_index++; - } - - iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - return true; - } -} - -bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) -{ - const pb_field_t *start = iter->pos; - - do { - if (iter->pos->tag == tag && - PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) - { - /* Found the wanted field */ - return true; - } - - (void)pb_field_iter_next(iter); - } while (iter->pos != start); - - /* Searched all the way back to start, and found nothing. */ - return false; -} - - diff --git a/firmware/protob/pb_common.h b/firmware/protob/pb_common.h deleted file mode 100644 index 60b3d37491..0000000000 --- a/firmware/protob/pb_common.h +++ /dev/null @@ -1,42 +0,0 @@ -/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. - * These functions are rarely needed by applications directly. - */ - -#ifndef PB_COMMON_H_INCLUDED -#define PB_COMMON_H_INCLUDED - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Iterator for pb_field_t list */ -struct pb_field_iter_s { - const pb_field_t *start; /* Start of the pb_field_t array */ - const pb_field_t *pos; /* Current position of the iterator */ - unsigned required_field_index; /* Zero-based index that counts only the required fields */ - void *dest_struct; /* Pointer to start of the structure */ - void *pData; /* Pointer to current field value */ - void *pSize; /* Pointer to count/has field */ -}; -typedef struct pb_field_iter_s pb_field_iter_t; - -/* Initialize the field iterator structure to beginning. - * Returns false if the message type is empty. */ -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); - -/* Advance the iterator to the next field. - * Returns false when the iterator wraps back to the first field. */ -bool pb_field_iter_next(pb_field_iter_t *iter); - -/* Advance the iterator until it points at a field with the given tag. - * Returns false if no such field exists. */ -bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif - diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c index d1efd1b516..cebf59607d 100644 --- a/firmware/protob/pb_decode.c +++ b/firmware/protob/pb_decode.c @@ -15,23 +15,36 @@ #include "pb.h" #include "pb_decode.h" -#include "pb_common.h" /************************************** * Declarations internal to this file * **************************************/ +/* Iterator for pb_field_t list */ +typedef struct { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned field_index; /* Zero-based index of the field. */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to the destination structure to decode to */ + void *pData; /* Pointer where to store current field value */ + void *pSize; /* Pointer where to store the size of current array field */ +} pb_field_iterator_t; + typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); +static bool pb_field_next(pb_field_iterator_t *iter); +static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); -static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static bool checkreturn find_extension_field(pb_field_iterator_t *iter); static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); @@ -46,7 +59,7 @@ static bool checkreturn pb_skip_string(pb_istream_t *stream); #ifdef PB_ENABLE_MALLOC static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); -static void pb_release_single_field(const pb_field_iter_t *iter); +static void pb_release_single_field(const pb_field_iterator_t *iter); #endif /* --- Function pointers to field decoders --- @@ -330,11 +343,75 @@ void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) #endif } +static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = iter->pos = fields; + iter->field_index = 0; + iter->required_field_index = 0; + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + iter->dest_struct = dest_struct; +} + +static bool pb_field_next(pb_field_iterator_t *iter) +{ + bool notwrapped = true; + size_t prev_size = iter->pos->data_size; + + if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && + PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) + { + prev_size *= iter->pos->array_size; + } + else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + prev_size = sizeof(void*); + } + + if (iter->pos->tag == 0) + return false; /* Only happens with empty message types */ + + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) + iter->required_field_index++; + + iter->pos++; + iter->field_index++; + if (iter->pos->tag == 0) + { + iter->pos = iter->start; + iter->field_index = 0; + iter->required_field_index = 0; + iter->pData = iter->dest_struct; + prev_size = 0; + notwrapped = false; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return notwrapped; +} + +static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) +{ + unsigned start = iter->field_index; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + return true; + } + (void)pb_field_next(iter); + } while (iter->field_index != start); + + return false; +} + /************************* * Decode a single field * *************************/ -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) { pb_type_t type; pb_decoder_t func; @@ -357,7 +434,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t { /* Packed array */ bool status = true; - pb_size_t *size = (pb_size_t*)iter->pSize; + size_t *size = (size_t*)iter->pSize; pb_istream_t substream; if (!pb_make_string_substream(stream, &substream)) return false; @@ -382,7 +459,7 @@ static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t else { /* Repeated field */ - pb_size_t *size = (pb_size_t*)iter->pSize; + size_t *size = (size_t*)iter->pSize; void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); if (*size >= iter->pos->array_size) PB_RETURN_ERROR(stream, "array overflow"); @@ -437,7 +514,7 @@ static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t } /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ -static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) +static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) @@ -451,11 +528,11 @@ static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) } #endif -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) { #ifndef PB_ENABLE_MALLOC - PB_UNUSED(wire_type); - PB_UNUSED(iter); + UNUSED(wire_type); + UNUSED(iter); PB_RETURN_ERROR(stream, "no malloc support"); #else pb_type_t type; @@ -495,7 +572,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ { /* Packed array, multiple items come in at once. */ bool status = true; - pb_size_t *size = (pb_size_t*)iter->pSize; + size_t *size = (size_t*)iter->pSize; size_t allocated_size = *size; void *pItem; pb_istream_t substream; @@ -505,7 +582,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ while (substream.bytes_left) { - if ((size_t)*size + 1 > allocated_size) + if (*size + 1 > allocated_size) { /* Allocate more storage. This tries to guess the * number of remaining entries. Round the division @@ -527,16 +604,6 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ status = false; break; } - - if (*size == PB_SIZE_MAX) - { -#ifndef PB_NO_ERRMSG - stream->errmsg = "too many array entries"; -#endif - status = false; - break; - } - (*size)++; } pb_close_string_substream(stream, &substream); @@ -546,12 +613,9 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ else { /* Normal repeated field, i.e. only one item at a time. */ - pb_size_t *size = (pb_size_t*)iter->pSize; + size_t *size = (size_t*)iter->pSize; void *pItem; - if (*size == PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "too many array entries"); - (*size)++; if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) return false; @@ -567,7 +631,7 @@ static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_ #endif } -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) { pb_callback_t *pCallback = (pb_callback_t*)iter->pData; @@ -614,7 +678,7 @@ static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type } } -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) { switch (PB_ATYPE(iter->pos->type)) { @@ -638,15 +702,16 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) { const pb_field_t *field = (const pb_field_t*)extension->type->arg; - pb_field_iter_t iter; + pb_field_iterator_t iter; if (field->tag != tag) return true; - /* Fake a field iterator for the extension field. - * It is not actually safe to advance this iterator, but decode_field - * will not even try to. */ - (void)pb_field_iter_begin(&iter, field, extension->dest); + iter.start = field; + iter.pos = field; + iter.field_index = 0; + iter.required_field_index = 0; + iter.dest_struct = extension->dest; iter.pData = extension->dest; iter.pSize = &extension->found; @@ -656,7 +721,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, /* Try to decode an unknown field as an extension field. Tries each extension * decoder in turn, until one of them handles the field or loop ends. */ static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) + uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) { pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; size_t pos = stream->bytes_left; @@ -681,15 +746,15 @@ static bool checkreturn decode_extension(pb_istream_t *stream, /* Step through the iterator until an extension field is found or until all * entries have been checked. There can be only one extension field per * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iter_t *iter) +static bool checkreturn find_extension_field(pb_field_iterator_t *iter) { - const pb_field_t *start = iter->pos; + unsigned start = iter->field_index; do { if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) return true; - (void)pb_field_iter_next(iter); - } while (iter->pos != start); + (void)pb_field_next(iter); + } while (iter->field_index != start); return false; } @@ -697,15 +762,17 @@ static bool checkreturn find_extension_field(pb_field_iter_t *iter) /* Initialize message fields to default values, recursively */ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) { - pb_field_iter_t iter; - - if (!pb_field_iter_begin(&iter, fields, dest_struct)) - return; /* Empty message type */ + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); do { pb_type_t type; type = iter.pos->type; + + /* Avoid crash on empty message types (zero fields) */ + if (iter.pos->tag == 0) + continue; if (PB_ATYPE(type) == PB_ATYPE_STATIC) { @@ -718,7 +785,7 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { /* Set array count to 0, no need to initialize contents. */ - *(pb_size_t*)iter.pSize = 0; + *(size_t*)iter.pSize = 0; continue; } @@ -746,14 +813,14 @@ static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_str /* Initialize array count to 0. */ if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { - *(pb_size_t*)iter.pSize = 0; + *(size_t*)iter.pSize = 0; } } else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) { /* Don't overwrite callback */ } - } while (pb_field_iter_next(&iter)); + } while (pb_field_next(&iter)); } /********************* @@ -764,11 +831,9 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ { uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint32_t extension_range_start = 0; - pb_field_iter_t iter; + pb_field_iterator_t iter; - /* Return value ignored, as empty message types will be correctly handled by - * pb_field_iter_find() anyway. */ - (void)pb_field_iter_begin(&iter, fields, dest_struct); + pb_field_init(&iter, fields, dest_struct); while (stream->bytes_left) { @@ -784,7 +849,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ return false; } - if (!pb_field_iter_find(&iter, tag)) + if (!pb_field_find(&iter, tag)) { /* No match found, check if it matches an extension. */ if (tag >= extension_range_start) @@ -837,7 +902,7 @@ bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[ do { req_field_count = iter.required_field_index; last_type = iter.pos->type; - } while (pb_field_iter_next(&iter)); + } while (pb_field_next(&iter)); /* Fixup if last field was also required. */ if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) @@ -886,7 +951,7 @@ bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void * } #ifdef PB_ENABLE_MALLOC -static void pb_release_single_field(const pb_field_iter_t *iter) +static void pb_release_single_field(const pb_field_iterator_t *iter) { pb_type_t type; type = iter->pos->type; @@ -937,15 +1002,16 @@ static void pb_release_single_field(const pb_field_iter_t *iter) void pb_release(const pb_field_t fields[], void *dest_struct) { - pb_field_iter_t iter; - - if (!pb_field_iter_begin(&iter, fields, dest_struct)) + pb_field_iterator_t iter; + pb_field_init(&iter, fields, dest_struct); + + if (iter.pos->tag == 0) return; /* Empty message type */ do { pb_release_single_field(&iter); - } while (pb_field_iter_next(&iter)); + } while (pb_field_next(&iter)); } #endif @@ -1059,13 +1125,13 @@ static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *f static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) { - PB_UNUSED(field); + UNUSED(field); return pb_decode_fixed32(stream, dest); } static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) { - PB_UNUSED(field); + UNUSED(field); return pb_decode_fixed64(stream, dest); } @@ -1078,9 +1144,6 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie if (!pb_decode_varint32(stream, &size)) return false; - if (size > PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "bytes overflow"); - alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); if (size > alloc_size) PB_RETURN_ERROR(stream, "size too large"); @@ -1101,8 +1164,9 @@ static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *fie PB_RETURN_ERROR(stream, "bytes overflow"); bdest = (pb_bytes_array_t*)dest; } + + bdest->size = size; - bdest->size = (pb_size_t)size; return pb_read(stream, bdest->bytes, size); } diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h index 3d433155b8..8dc67408a8 100644 --- a/firmware/protob/pb_decode.h +++ b/firmware/protob/pb_decode.h @@ -3,8 +3,8 @@ * field descriptions created by nanopb_generator.py. */ -#ifndef PB_DECODE_H_INCLUDED -#define PB_DECODE_H_INCLUDED +#ifndef _PB_DECODE_H_ +#define _PB_DECODE_H_ #include "pb.h" @@ -25,7 +25,7 @@ extern "C" { * is different than from the main stream. Don't use bytes_left to compute * any pointers. */ -struct pb_istream_s +struct _pb_istream_t { #ifdef PB_BUFFER_ONLY /* Callback pointer is not used in buffer-only configuration. diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c index cdd789555a..dc5a273493 100644 --- a/firmware/protob/pb_encode.c +++ b/firmware/protob/pb_encode.c @@ -5,7 +5,6 @@ #include "pb.h" #include "pb_encode.h" -#include "pb_common.h" /* Use the GCC warn_unused_result attribute to check that all return values * are propagated correctly. On other compilers and gcc before 3.4.0 just @@ -246,7 +245,7 @@ static bool checkreturn encode_basic_field(pb_ostream_t *stream, break; case PB_HTYPE_REPEATED: - if (!encode_array(stream, field, pData, *(const pb_size_t*)pSize, func)) + if (!encode_array(stream, field, pData, *(const size_t*)pSize, func)) return false; break; @@ -311,7 +310,7 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData) { const pb_extension_t *extension = *(const pb_extension_t* const *)pData; - PB_UNUSED(field); + UNUSED(field); while (extension) { @@ -334,38 +333,42 @@ static bool checkreturn encode_extension_field(pb_ostream_t *stream, * Encode all fields * *********************/ -static void *remove_const(const void *p) -{ - /* Note: this casts away const, in order to use the common field iterator - * logic for both encoding and decoding. */ - union { - void *p1; - const void *p2; - } t; - t.p2 = p; - return t.p1; -} - bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) { - pb_field_iter_t iter; - if (!pb_field_iter_begin(&iter, fields, remove_const(src_struct))) - return true; /* Empty message type */ + const pb_field_t *field = fields; + const void *pData = src_struct; + size_t prev_size = 0; - do { - if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) + while (field->tag != 0) + { + pData = (const char*)pData + prev_size + field->data_offset; + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + prev_size = sizeof(const void*); + else + prev_size = field->data_size; + + /* Special case for static arrays */ + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + { + prev_size *= field->array_size; + } + + if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION) { /* Special case for the extension field placeholder */ - if (!encode_extension_field(stream, iter.pos, iter.pData)) + if (!encode_extension_field(stream, field, pData)) return false; } else { /* Regular field */ - if (!encode_field(stream, iter.pos, iter.pData)) + if (!encode_field(stream, field, pData)) return false; } - } while (pb_field_iter_next(&iter)); + + field++; + } return true; } @@ -599,13 +602,13 @@ static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *f static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - PB_UNUSED(field); + UNUSED(field); return pb_encode_fixed64(stream, src); } static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) { - PB_UNUSED(field); + UNUSED(field); return pb_encode_fixed32(stream, src); } @@ -630,6 +633,7 @@ static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *fie static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) { + /* strnlen() is not always available, so just use a loop */ size_t size = 0; size_t max_size = field->data_size; const char *p = (const char*)src; @@ -643,7 +647,6 @@ static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *fi } else { - /* strnlen() is not always available, so just use a loop */ while (size < max_size && *p != '\0') { size++; diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h index e992c8dca1..f82bac8f86 100644 --- a/firmware/protob/pb_encode.h +++ b/firmware/protob/pb_encode.h @@ -3,8 +3,8 @@ * field descriptions created by nanopb_generator.py. */ -#ifndef PB_ENCODE_H_INCLUDED -#define PB_ENCODE_H_INCLUDED +#ifndef _PB_ENCODE_H_ +#define _PB_ENCODE_H_ #include "pb.h" @@ -24,7 +24,7 @@ extern "C" { * 4) Substreams will modify max_size and bytes_written. Don't use them * to calculate any pointers. */ -struct pb_ostream_s +struct _pb_ostream_t { #ifdef PB_BUFFER_ONLY /* Callback pointer is not used in buffer-only configuration. diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index bd177d78e1..ec96bd54f4 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -1,24 +1,20 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ #include "storage.pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - const pb_field_t Storage_fields[10] = { - PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), - PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), - PB_FIELD( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), - PB_FIELD( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), - PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), - PB_FIELD( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), - PB_FIELD( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), - PB_FIELD( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), - PB_FIELD( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), + PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), + PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), + PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), + PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), + PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), + PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_LAST_FIELD }; @@ -32,7 +28,7 @@ const pb_field_t Storage_fields[10] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) +STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -43,7 +39,7 @@ PB_STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIEL * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) +STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) #endif diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 82d1ba0cf3..f9df1390ed 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -1,15 +1,11 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ -#ifndef PB_STORAGE_PB_H_INCLUDED -#define PB_STORAGE_PB_H_INCLUDED +#ifndef _PB_STORAGE_PB_H_ +#define _PB_STORAGE_PB_H_ #include "pb.h" #include "types.pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index fa11a45766..6eb4cdf0a8 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -1,12 +1,8 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ #include "types.pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_p2sh_default = 5u; const uint32_t TxInputType_sequence_default = 4294967295u; @@ -14,84 +10,84 @@ const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADD const pb_field_t HDNodeType_fields[7] = { - PB_FIELD( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), - PB_FIELD( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), - PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), - PB_FIELD( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), - PB_FIELD( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), - PB_FIELD( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), + PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), + PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), + PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), + PB_FIELD2( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), + PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), + PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), PB_LAST_FIELD }; const pb_field_t HDNodePathType_fields[3] = { - PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, HDNodePathType, node, node, &HDNodeType_fields), - PB_FIELD( 2, UINT32 , REPEATED, STATIC , OTHER, HDNodePathType, address_n, node, 0), + PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, HDNodePathType, node, node, &HDNodeType_fields), + PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, HDNodePathType, address_n, node, 0), PB_LAST_FIELD }; const pb_field_t CoinType_fields[6] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), - PB_FIELD( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), - PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), - PB_FIELD( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), - PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), + PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), PB_LAST_FIELD }; const pb_field_t MultisigRedeemScriptType_fields[4] = { - PB_FIELD( 1, MESSAGE , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, &HDNodePathType_fields), - PB_FIELD( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), - PB_FIELD( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), + PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, &HDNodePathType_fields), + PB_FIELD2( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), PB_LAST_FIELD }; const pb_field_t TxInputType_fields[8] = { - PB_FIELD( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), - PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), - PB_FIELD( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), - PB_FIELD( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), - PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), - PB_FIELD( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), - PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), + PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), + PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), + PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; const pb_field_t TxOutputType_fields[6] = { - PB_FIELD( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), - PB_FIELD( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), - PB_FIELD( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), - PB_FIELD( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), - PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), + PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), + PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), + PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), + PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), PB_LAST_FIELD }; const pb_field_t TxOutputBinType_fields[3] = { - PB_FIELD( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), - PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), + PB_FIELD2( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), PB_LAST_FIELD }; const pb_field_t TransactionType_fields[8] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), - PB_FIELD( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), - PB_FIELD( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), - PB_FIELD( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), - PB_FIELD( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), - PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), - PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), + PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), + PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), + PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), + PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), + PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), PB_LAST_FIELD }; const pb_field_t TxRequestDetailsType_fields[3] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), PB_LAST_FIELD }; const pb_field_t TxRequestSerializedType_fields[4] = { - PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), - PB_FIELD( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), - PB_FIELD( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), PB_LAST_FIELD }; @@ -100,7 +96,7 @@ typedef struct { } wire_in_struct; static const pb_field_t wire_in_field = - PB_FIELD(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); + PB_FIELD2(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); const pb_extension_type_t wire_in = { NULL, @@ -113,7 +109,7 @@ typedef struct { } wire_out_struct; static const pb_field_t wire_out_field = - PB_FIELD(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); + PB_FIELD2(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); const pb_extension_type_t wire_out = { NULL, @@ -126,7 +122,7 @@ typedef struct { } wire_debug_in_struct; static const pb_field_t wire_debug_in_field = - PB_FIELD(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); + PB_FIELD2(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); const pb_extension_type_t wire_debug_in = { NULL, @@ -139,7 +135,7 @@ typedef struct { } wire_debug_out_struct; static const pb_field_t wire_debug_out_field = - PB_FIELD(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); + PB_FIELD2(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); const pb_extension_type_t wire_debug_out = { NULL, @@ -157,7 +153,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 215ad3e766..dd7b30bea9 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -1,13 +1,9 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.1 */ +/* Generated by nanopb-0.2.9.1 */ -#ifndef PB_TYPES_PB_H_INCLUDED -#define PB_TYPES_PB_H_INCLUDED +#ifndef _PB_TYPES_PB_H_ +#define _PB_TYPES_PB_H_ #include "pb.h" -#if PB_PROTO_HEADER_VERSION != 30 -#error Regenerate this file with the current version of nanopb generator. -#endif - #ifdef __cplusplus extern "C" { #endif @@ -79,11 +75,20 @@ typedef struct _CoinType { uint32_t address_type_p2sh; } CoinType; -typedef PB_BYTES_ARRAY_T(32) HDNodeType_chain_code_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} HDNodeType_chain_code_t; -typedef PB_BYTES_ARRAY_T(32) HDNodeType_private_key_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} HDNodeType_private_key_t; -typedef PB_BYTES_ARRAY_T(33) HDNodeType_public_key_t; +typedef struct { + size_t size; + uint8_t bytes[33]; +} HDNodeType_public_key_t; typedef struct _HDNodeType { uint32_t depth; @@ -96,14 +101,20 @@ typedef struct _HDNodeType { HDNodeType_public_key_t public_key; } HDNodeType; -typedef PB_BYTES_ARRAY_T(520) TxOutputBinType_script_pubkey_t; +typedef struct { + size_t size; + uint8_t bytes[520]; +} TxOutputBinType_script_pubkey_t; typedef struct _TxOutputBinType { uint64_t amount; TxOutputBinType_script_pubkey_t script_pubkey; } TxOutputBinType; -typedef PB_BYTES_ARRAY_T(32) TxRequestDetailsType_tx_hash_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxRequestDetailsType_tx_hash_t; typedef struct _TxRequestDetailsType { bool has_request_index; @@ -112,9 +123,15 @@ typedef struct _TxRequestDetailsType { TxRequestDetailsType_tx_hash_t tx_hash; } TxRequestDetailsType; -typedef PB_BYTES_ARRAY_T(73) TxRequestSerializedType_signature_t; +typedef struct { + size_t size; + uint8_t bytes[73]; +} TxRequestSerializedType_signature_t; -typedef PB_BYTES_ARRAY_T(2048) TxRequestSerializedType_serialized_tx_t; +typedef struct { + size_t size; + uint8_t bytes[2048]; +} TxRequestSerializedType_serialized_tx_t; typedef struct _TxRequestSerializedType { bool has_signature_index; @@ -127,27 +144,36 @@ typedef struct _TxRequestSerializedType { typedef struct _HDNodePathType { HDNodeType node; - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; } HDNodePathType; -typedef PB_BYTES_ARRAY_T(73) MultisigRedeemScriptType_signatures_t; +typedef struct { + size_t size; + uint8_t bytes[73]; +} MultisigRedeemScriptType_signatures_t; typedef struct _MultisigRedeemScriptType { - pb_size_t pubkeys_count; + size_t pubkeys_count; HDNodePathType pubkeys[15]; - pb_size_t signatures_count; + size_t signatures_count; MultisigRedeemScriptType_signatures_t signatures[15]; bool has_m; uint32_t m; } MultisigRedeemScriptType; -typedef PB_BYTES_ARRAY_T(32) TxInputType_prev_hash_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} TxInputType_prev_hash_t; -typedef PB_BYTES_ARRAY_T(1650) TxInputType_script_sig_t; +typedef struct { + size_t size; + uint8_t bytes[1650]; +} TxInputType_script_sig_t; typedef struct _TxInputType { - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; TxInputType_prev_hash_t prev_hash; uint32_t prev_index; @@ -164,7 +190,7 @@ typedef struct _TxInputType { typedef struct _TxOutputType { bool has_address; char address[36]; - pb_size_t address_n_count; + size_t address_n_count; uint32_t address_n[8]; uint64_t amount; OutputScriptType script_type; @@ -175,13 +201,13 @@ typedef struct _TxOutputType { typedef struct _TransactionType { bool has_version; uint32_t version; - pb_size_t inputs_count; + size_t inputs_count; TxInputType inputs[1]; - pb_size_t bin_outputs_count; + size_t bin_outputs_count; TxOutputBinType bin_outputs[1]; bool has_lock_time; uint32_t lock_time; - pb_size_t outputs_count; + size_t outputs_count; TxOutputType outputs[1]; bool has_inputs_cnt; uint32_t inputs_cnt; From 62ce3c69886b624fb8afc28413daf0ab4fc12c37 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 27 Dec 2014 16:33:44 +0100 Subject: [PATCH 0081/1154] rework docker build script --- Dockerfile | 7 +------ firmware-docker-build.sh | 13 +++++++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 57509c83a0..17a3c088b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,14 +13,9 @@ RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION py # clone the source code -RUN git clone https://github.com/libopencm3/libopencm3 && git clone https://github.com/trezor/trezor-mcu +RUN git clone https://github.com/libopencm3/libopencm3 # build libopencm3 ENV LIBOPENCM3_GITREV 8a15cec6bf99f59065879a14895fb8af8a8a53e7 RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make - -# build the firmware - -ENV TREZOR_MCU_GITREV v1.3.0 -RUN cd trezor-mcu && git checkout $TREZOR_MCU_GITREV && git submodule update --init && make && cd firmware && make diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 21128d7e65..375bc7c90d 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,9 +1,18 @@ #!/bin/bash IMAGETAG=trezor-mcu-build +FIRMWARETAG=v1.3.0 -docker rmi $IMAGETAG || : docker build -t $IMAGETAG . -docker run -t -v $(pwd):/output $IMAGETAG /bin/cp /trezor-mcu/firmware/trezor.bin /output +docker run -t -v $(pwd):/output $IMAGETAG /bin/sh -c "\ + git clone https://github.com/trezor/trezor-mcu && \ + cd trezor-mcu && \ + git checkout $FIRMWARETAG && \ + git submodule update --init && \ + make && \ + cd firmware && \ + make && \ + cp trezor.bin /output \ + " echo "---------------------" echo "Firmware fingerprint:" From 880f0584823bc779672b283ecfdfab3f5b5ec9e9 Mon Sep 17 00:00:00 2001 From: cf18 Date: Sun, 18 Jan 2015 04:23:56 +0100 Subject: [PATCH 0082/1154] correcting transponed QR code --- firmware/layout2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 0e6291884f..099aeb8245 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -222,9 +222,10 @@ void layoutAddress(const char *address) if (side > 0 && side <= 29) { oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); + //not 100% sure why this is transponed for (i = 0; i < side; i++) { for (j = 0; j< side; j++) { - a = i * side + j; + a = j * side + i; if (bitdata[a / 8] & (1 << (7 - a % 8))) { oledClearPixel(2 + i * 2, 2 + j * 2); oledClearPixel(3 + i * 2, 2 + j * 2); From 8f48ffe63c3e1c78e533b826c09a23ff9328af49 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 12:51:56 +0100 Subject: [PATCH 0083/1154] extract fsm_getCoin --- firmware/coins.c | 2 ++ firmware/fsm.c | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index db811e3619..60a44429a4 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -30,6 +30,7 @@ const CoinType coins[COINS_COUNT] = { const CoinType *coinByShortcut(const char *shortcut) { + if (!shortcut) return 0; int i; for (i = 0; i < COINS_COUNT; i++) { if (strcmp(shortcut, coins[i].coin_shortcut) == 0) { @@ -41,6 +42,7 @@ const CoinType *coinByShortcut(const char *shortcut) const CoinType *coinByName(const char *name) { + if (!name) return 0; int i; for (i = 0; i < COINS_COUNT; i++) { if (strcmp(name, coins[i].coin_name) == 0) { diff --git a/firmware/fsm.c b/firmware/fsm.c index 7263f1f187..558761ad87 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -78,12 +78,23 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } +const CoinType *fsm_getCoin(const char *name) +{ + const CoinType *coin = coinByName(name); + if (!coin) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + layoutHome(); + return 0; + } + return coin; +} + HDNode *fsm_getRootNode(void) { static HDNode node; if (!storage_getRootNode(&node)) { - layoutHome(); fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); + layoutHome(); return 0; } return &node; @@ -351,14 +362,10 @@ void fsm_msgSignTx(SignTx *msg) return; } + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; HDNode *node = fsm_getRootNode(); if (!node) return; - const CoinType *coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return; - } signing_init(msg->inputs_count, msg->outputs_count, coin, node); } @@ -495,14 +502,10 @@ void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; HDNode *node = fsm_getRootNode(); if (!node) return; - const CoinType *coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return; - } if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; if (msg->has_multisig) { @@ -563,14 +566,10 @@ void fsm_msgSignMessage(SignMessage *msg) return; } + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; HDNode *node = fsm_getRootNode(); if (!node) return; - const CoinType *coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - layoutHome(); - return; - } if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; layoutProgressSwipe("Signing", 0); From 32158bbb5cbeb385ccd136d0446f06c6d124f9c0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 13:53:06 +0100 Subject: [PATCH 0084/1154] refactor fsm_getRootNode into fsm_getDerivedNode --- firmware/fsm.c | 42 +++++++++++++++++------------------------- firmware/signing.c | 2 +- firmware/signing.h | 2 +- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 558761ad87..bf233031ef 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -89,7 +89,7 @@ const CoinType *fsm_getCoin(const char *name) return coin; } -HDNode *fsm_getRootNode(void) +const HDNode *fsm_getDerivedNode(uint32_t *address_n, size_t address_n_count) { static HDNode node; if (!storage_getRootNode(&node)) { @@ -97,17 +97,15 @@ HDNode *fsm_getRootNode(void) layoutHome(); return 0; } - return &node; -} - -int fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) -{ + if (!address_n || address_n_count == 0) { + return &node; + } size_t i; if (address_n_count > 3) { layoutProgressSwipe("Preparing keys", 0); } for (i = 0; i < address_n_count; i++) { - if (hdnode_private_ckd(node, address_n[i]) == 0) { + if (hdnode_private_ckd(&node, address_n[i]) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); layoutHome(); return 0; @@ -116,7 +114,7 @@ int fsm_deriveKey(HDNode *node, uint32_t *address_n, size_t address_n_count) layoutProgress("Preparing keys", 1000 * i / address_n_count); } } - return 1; + return &node; } void fsm_msgInitialize(Initialize *msg) @@ -279,9 +277,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; resp->node.depth = node->depth; resp->node.fingerprint = node->fingerprint; @@ -364,7 +361,7 @@ void fsm_msgSignTx(SignTx *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(0, 0); if (!node) return; signing_init(msg->inputs_count, msg->outputs_count, coin, node); @@ -404,9 +401,8 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) layoutHome(); return; } - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; bool encrypt = msg->has_encrypt && msg->encrypt; bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; @@ -504,9 +500,8 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); @@ -568,9 +563,8 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; layoutProgressSwipe("Signing", 0); if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { @@ -631,7 +625,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) bool signing = msg->address_n_count > 0; RESP_INIT(EncryptedMessage); const CoinType *coin = 0; - HDNode *node = 0; + const HDNode *node = 0; uint8_t address_raw[21]; if (signing) { coin = coinByName(msg->coin_name); @@ -643,12 +637,11 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) layoutHome(); return; } - node = fsm_getRootNode(); + node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; - - hdnode_fill_public_key(node); - ecdsa_get_address_raw(node->public_key, coin->address_type, address_raw); + uint8_t public_key[33]; + ecdsa_get_public_key33(node->private_key, public_key); + ecdsa_get_address_raw(public_key, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -692,9 +685,8 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) layoutHome(); return; } - HDNode *node = fsm_getRootNode(); + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; - if (fsm_deriveKey(node, msg->address_n, msg->address_n_count) == 0) return; layoutProgressSwipe("Decrypting", 0); RESP_INIT(DecryptedMessage); diff --git a/firmware/signing.c b/firmware/signing.c index f3f8bf6dbb..e41d377e7f 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -196,7 +196,7 @@ void send_req_finished(void) msg_write(MessageType_MessageType_TxRequest, &resp); } -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, HDNode *_root) +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root) { inputs_count = _inputs_count; outputs_count = _outputs_count; diff --git a/firmware/signing.h b/firmware/signing.h index 84d609b877..bcb66fec6b 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -25,7 +25,7 @@ #include "bip32.h" #include "types.pb.h" -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, HDNode *_root); +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root); void signing_abort(void); void signing_txack(TransactionType *tx); From 31385f71f488ca6d29a578eb57220c2d1bb3134a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 14:02:14 +0100 Subject: [PATCH 0085/1154] update nanopb to 0.2.9.2 --- firmware/protob/messages.pb.c | 2 +- firmware/protob/messages.pb.h | 2 +- firmware/protob/pb.h | 2 +- firmware/protob/pb_decode.c | 88 ++++++++++++++++++++++++----------- firmware/protob/storage.pb.c | 2 +- firmware/protob/storage.pb.h | 2 +- firmware/protob/types.pb.c | 2 +- firmware/protob/types.pb.h | 2 +- 8 files changed, 67 insertions(+), 35 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index ac71a5b8da..d11890edf3 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #include "messages.pb.h" diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index aae1b549d9..0c85401a89 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #ifndef _PB_MESSAGES_PB_H_ #define _PB_MESSAGES_PB_H_ diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h index 228ee55c14..70911e4dbd 100644 --- a/firmware/protob/pb.h +++ b/firmware/protob/pb.h @@ -46,7 +46,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.2.9.1 +#define NANOPB_VERSION nanopb-0.2.9.2 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c index cebf59607d..9edc8b3abb 100644 --- a/firmware/protob/pb_decode.c +++ b/firmware/protob/pb_decode.c @@ -42,6 +42,7 @@ static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); +static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension); static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); static bool checkreturn find_extension_field(pb_field_iterator_t *iter); @@ -696,6 +697,19 @@ static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_t } } +static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + iter->start = field; + iter->pos = field; + iter->field_index = 0; + iter->required_field_index = 0; + iter->dest_struct = extension->dest; + iter->pData = extension->dest; + iter->pSize = &extension->found; +} + /* Default handler for extension fields. Expects a pb_field_t structure * in extension->type->arg. */ static bool checkreturn default_extension_decoder(pb_istream_t *stream, @@ -707,14 +721,7 @@ static bool checkreturn default_extension_decoder(pb_istream_t *stream, if (field->tag != tag) return true; - iter.start = field; - iter.pos = field; - iter.field_index = 0; - iter.required_field_index = 0; - iter.dest_struct = extension->dest; - iter.pData = extension->dest; - iter.pSize = &extension->found; - + iter_from_extension(&iter, extension); return decode_field(stream, wire_type, &iter); } @@ -956,6 +963,47 @@ static void pb_release_single_field(const pb_field_iterator_t *iter) pb_type_t type; type = iter->pos->type; + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iterator_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + count = *(pb_size_t*)iter->pSize; + } + + if (pItem) + { + while (count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (uint8_t*)pItem + iter->pos->data_size; + } + } + } + if (PB_ATYPE(type) == PB_ATYPE_POINTER) { if (PB_HTYPE(type) == PB_HTYPE_REPEATED && @@ -970,28 +1018,12 @@ static void pb_release_single_field(const pb_field_iterator_t *iter) pb_free(*pItem); *pItem++ = NULL; } - *(pb_size_t*)iter->pSize = 0; } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { - /* Release fields in submessages */ - void *pItem = *(void**)iter->pData; - if (pItem) - { - pb_size_t count = 1; - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - count = *(pb_size_t*)iter->pSize; - *(pb_size_t*)iter->pSize = 0; - } - - while (count--) - { - pb_release((const pb_field_t*)iter->pos->ptr, pItem); - pItem = (uint8_t*)pItem + iter->pos->data_size; - } - } + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; } /* Release main item */ diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index ec96bd54f4..34b40d3c88 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #include "storage.pb.h" diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index f9df1390ed..8251f47359 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #ifndef _PB_STORAGE_PB_H_ #define _PB_STORAGE_PB_H_ diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 6eb4cdf0a8..343df0748c 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #include "types.pb.h" diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index dd7b30bea9..84234008a7 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.1 */ +/* Generated by nanopb-0.2.9.2 */ #ifndef _PB_TYPES_PB_H_ #define _PB_TYPES_PB_H_ From 5f8a4f6da14590328ee80c583506d9f8a9af3157 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 20:24:07 +0100 Subject: [PATCH 0086/1154] use hdnode_private_ckd_cached where appropriate --- firmware/crypto.c | 3 --- firmware/fsm.c | 17 ++++------------- firmware/signing.c | 11 ++++------- firmware/transaction.c | 10 +++------- memory.c | 4 ++-- trezor-crypto | 2 +- 6 files changed, 14 insertions(+), 33 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index ee2338ccab..7cd4fd9f98 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -161,9 +161,6 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ return 0; } -// internal from ecdsa.c -int generate_k_random(bignum256 *k); - int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) { if (privkey && address_raw) { // signing == true diff --git a/firmware/fsm.c b/firmware/fsm.c index bf233031ef..3fc90d26ad 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -100,19 +100,10 @@ const HDNode *fsm_getDerivedNode(uint32_t *address_n, size_t address_n_count) if (!address_n || address_n_count == 0) { return &node; } - size_t i; - if (address_n_count > 3) { - layoutProgressSwipe("Preparing keys", 0); - } - for (i = 0; i < address_n_count; i++) { - if (hdnode_private_ckd(&node, address_n[i]) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); - layoutHome(); - return 0; - } - if (address_n_count > 3) { - layoutProgress("Preparing keys", 1000 * i / address_n_count); - } + if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + layoutHome(); + return 0; } return &node; } diff --git a/firmware/signing.c b/firmware/signing.c index e41d377e7f..2c3f526ad3 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -318,13 +318,10 @@ void signing_txack(TransactionType *tx) } if (idx3i == idx1i) { memcpy(&node, root, sizeof(HDNode)); - uint32_t k; - for (k = 0; k < tx->inputs[0].address_n_count; k++) { - if (hdnode_private_ckd(&node, tx->inputs[0].address_n[k]) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); - signing_abort(); - return; - } + if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + signing_abort(); + return; } if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { if (!tx->inputs[0].has_multisig) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 08cca087ca..88bd0d1752 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -66,15 +66,11 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T // address_n provided-> change address -> calculate from address_n if (in->address_n_count > 0) { HDNode node; - uint32_t k; memcpy(&node, root, sizeof(HDNode)); - layoutProgressUpdate(true); - for (k = 0; k < in->address_n_count; k++) { - if (hdnode_private_ckd(&node, in->address_n[k]) == 0) { - return 0; - } - layoutProgressUpdate(true); + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count) == 0) { + return 0; } + layoutProgressUpdate(true); ecdsa_get_address_raw(node.public_key, coin->address_type, addr_raw); } else if (in->has_address) { // address provided -> regular output diff --git a/memory.c b/memory.c index 5dcc8bd464..c9ed483a6f 100644 --- a/memory.c +++ b/memory.c @@ -32,8 +32,8 @@ void memory_protect(void) return; // already set up correctly - bail out } flash_unlock_option_bytes(); - // WRP + RDP - flash_program_option_bytes( 0xFFFC0000 + 0xCCFF); + // WRP + RDP + flash_program_option_bytes(0xFFFC0000 + 0xCCFF); flash_lock_option_bytes(); } diff --git a/trezor-crypto b/trezor-crypto index 795579cbac..aa1833ba3f 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 795579cbacb5e4bd072d7cef2a2638f1d44c2d0d +Subproject commit aa1833ba3fd9301dd275c1c34c1ce5dd9ae703be From 7dacfd69eeb5b021ab58490105bc1c9e50edf1f1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 21:10:51 +0100 Subject: [PATCH 0087/1154] check for flash operation failure --- firmware/storage.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/storage.c b/firmware/storage.c index 369dabfbce..1968f8bc53 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -130,6 +130,7 @@ void storage_commit(void) uint32_t *w; // backup meta memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); + flash_clear_status_flags(); flash_unlock(); // erase storage for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { @@ -145,6 +146,11 @@ void storage_commit(void) flash_program_word(FLASH_META_START + i * 4, *w); } flash_lock(); + // flash operation failed + if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) { } + } } void storage_loadDevice(LoadDevice *msg) From 012d38a9a03d4674a54e32e4b9437092b4c047b3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 21:41:43 +0100 Subject: [PATCH 0088/1154] increasePinFails before asking PIN --- firmware/protect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protect.c b/firmware/protect.c index 3067678fc9..79819c6cf7 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -156,6 +156,7 @@ bool protectPin(bool use_cached) delay(10000000); } } + storage_increasePinFails(); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); if (!pin) { fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); @@ -166,7 +167,6 @@ bool protectPin(bool use_cached) storage_resetPinFails(); return true; } else { - storage_increasePinFails(); fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); return false; } From 40efefc5716366618accc2e4871fdb7a6d92d15f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jan 2015 22:03:33 +0100 Subject: [PATCH 0089/1154] rework pin handling --- firmware/protect.c | 14 ++++++++------ firmware/storage.c | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 79819c6cf7..cf1dbddf77 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -145,24 +145,26 @@ bool protectPin(bool use_cached) if (!storage.has_pin || strlen(storage.pin) == 0 || (use_cached && session_isPinCached())) { return true; } - const char *pin; - uint32_t wait = storage_getPinFails(); - if (wait) { - if (wait > 2) { + uint32_t fails = storage_getPinFails(); + if (fails) { + if (fails > 2) { layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait ...", NULL, NULL, NULL); } - wait = (wait < 32) ? (1u << wait) : 0xFFFFFFFF; + uint32_t wait; + wait = (fails < 32) ? (1u << fails) : 0xFFFFFFFF; while (--wait > 0) { delay(10000000); } } storage_increasePinFails(); + bool increase_failed = (fails >= storage_getPinFails()); + const char *pin; pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); if (!pin) { fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); return false; } - if (storage_isPinCorrect(pin)) { + if (storage_isPinCorrect(pin) && !increase_failed) { session_cachePin(pin); storage_resetPinFails(); return true; diff --git a/firmware/storage.c b/firmware/storage.c index 1968f8bc53..f573ca6cb5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -350,6 +350,7 @@ void storage_increasePinFails(void) uint32_t storage_getPinFails(void) { + storage_from_flash(STORAGE_VERSION); // reload from flash return storage.has_pin_failed_attempts ? storage.pin_failed_attempts : 0; } From d35b741f08d58632f2bce1c370a1388e3cb7858f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Feb 2015 20:04:59 +0100 Subject: [PATCH 0090/1154] enable OP_RETURN --- firmware/layout2.c | 2 +- firmware/protob/types.options | 1 + firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 21 +++++++++++++++------ firmware/signing.c | 2 +- firmware/transaction.c | 10 ++++++++++ trezor-common | 2 +- trezor-crypto | 2 +- trezor-qrenc | 2 +- 9 files changed, 33 insertions(+), 12 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 9a21c78f09..d04ac026ba 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -126,7 +126,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ "Really send", str_out, "from your wallet?", - "Fee will be", + "Fee included:", str_fee, NULL ); diff --git a/firmware/protob/types.options b/firmware/protob/types.options index c19d603a29..c1a4c536ca 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -13,6 +13,7 @@ TxInputType.script_sig max_size:1650 TxOutputType.address max_size:36 TxOutputType.address_n max_count:8 +TxOutputType.op_return_data max_size:80 TxOutputBinType.script_pubkey max_size:520 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 343df0748c..8dca6cfe04 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -52,12 +52,13 @@ const pb_field_t TxInputType_fields[8] = { PB_LAST_FIELD }; -const pb_field_t TxOutputType_fields[6] = { +const pb_field_t TxOutputType_fields[7] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, TxOutputType, op_return_data, multisig, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 84234008a7..177df7b9ee 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -27,7 +27,8 @@ typedef enum _FailureType { typedef enum _OutputScriptType { OutputScriptType_PAYTOADDRESS = 0, OutputScriptType_PAYTOSCRIPTHASH = 1, - OutputScriptType_PAYTOMULTISIG = 2 + OutputScriptType_PAYTOMULTISIG = 2, + OutputScriptType_PAYTOOPRETURN = 3 } OutputScriptType; typedef enum _InputScriptType { @@ -187,6 +188,11 @@ typedef struct _TxInputType { MultisigRedeemScriptType multisig; } TxInputType; +typedef struct { + size_t size; + uint8_t bytes[80]; +} TxOutputType_op_return_data_t; + typedef struct _TxOutputType { bool has_address; char address[36]; @@ -196,6 +202,8 @@ typedef struct _TxOutputType { OutputScriptType script_type; bool has_multisig; MultisigRedeemScriptType multisig; + bool has_op_return_data; + TxOutputType_op_return_data_t op_return_data; } TxOutputType; typedef struct _TransactionType { @@ -233,7 +241,7 @@ extern const InputScriptType TxInputType_script_type_default; #define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} -#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default} +#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} #define TxOutputBinType_init_default {0, {0, {0}}} #define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} #define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} @@ -243,7 +251,7 @@ extern const InputScriptType TxInputType_script_type_default; #define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} -#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero} +#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} #define TxOutputBinType_init_zero {0, {0, {0}}} #define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} #define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} @@ -285,6 +293,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TxOutputType_amount_tag 3 #define TxOutputType_script_type_tag 4 #define TxOutputType_multisig_tag 5 +#define TxOutputType_op_return_data_tag 6 #define TransactionType_version_tag 1 #define TransactionType_inputs_tag 2 #define TransactionType_bin_outputs_tag 3 @@ -303,7 +312,7 @@ extern const pb_field_t HDNodePathType_fields[3]; extern const pb_field_t CoinType_fields[6]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; -extern const pb_field_t TxOutputType_fields[6]; +extern const pb_field_t TxOutputType_fields[7]; extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TxRequestDetailsType_fields[3]; @@ -315,9 +324,9 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; #define CoinType_size 53 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5497 -#define TxOutputType_size 3847 +#define TxOutputType_size 3929 #define TxOutputBinType_size 534 -#define TransactionType_size 9911 +#define TransactionType_size 9993 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 diff --git a/firmware/signing.c b/firmware/signing.c index 2c3f526ad3..aee2faf3e4 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -480,7 +480,7 @@ void signing_txack(TransactionType *tx) } } // last confirmation - layoutConfirmTx(coin, to_spend - change_spend - fee, fee); + layoutConfirmTx(coin, to_spend - change_spend, fee); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 88bd0d1752..61b98090bf 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -146,6 +146,16 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 23; } + if (in->script_type == OutputScriptType_PAYTOOPRETURN) { + if (in->amount != 0) return 0; // only 0 satoshi allowed for OP_RETURN + uint32_t r = 0; + out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN + r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); + memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; + out->script_pubkey.size = r; + return r; + } + return 0; } diff --git a/trezor-common b/trezor-common index 60bcde46f5..f5d880c96c 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 60bcde46f584062e3a454bcdfdcf01bff927c8ea +Subproject commit f5d880c96c72c298e0fb412bcb1abba6a4ddac02 diff --git a/trezor-crypto b/trezor-crypto index aa1833ba3f..54aa5a4482 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit aa1833ba3fd9301dd275c1c34c1ce5dd9ae703be +Subproject commit 54aa5a4482eaf6f11c0c6941be5e34aa3a5ff5e2 diff --git a/trezor-qrenc b/trezor-qrenc index f12996741c..1da1cedfd6 160000 --- a/trezor-qrenc +++ b/trezor-qrenc @@ -1 +1 @@ -Subproject commit f12996741ca0a73b09e324306c7e79755a84202c +Subproject commit 1da1cedfd6bbd08784a3a4d7d6310b46830893cb From b5221ce2e931f85cf059a867d3fefd23212f60d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Feb 2015 21:27:07 +0100 Subject: [PATCH 0091/1154] introduce homescreen --- firmware/fsm.c | 13 ++++++++++++- firmware/layout2.c | 17 +++++++++++++---- firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 16 ++++++++++++---- firmware/protob/storage.options | 1 + firmware/protob/storage.pb.c | 12 +++--------- firmware/protob/storage.pb.h | 16 ++++++++++++---- firmware/storage.c | 18 ++++++++++++++++++ firmware/storage.h | 3 +++ trezor-common | 2 +- 11 files changed, 78 insertions(+), 24 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 3fc90d26ad..115105ef5a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -463,7 +463,15 @@ void fsm_msgApplySettings(ApplySettings *msg) return; } } - if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase) { + if (msg->has_homescreen) { + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + layoutHome(); + return; + } + } + if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase && !msg->has_homescreen) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); return; } @@ -480,6 +488,9 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_use_passphrase) { storage_setPassphraseProtection(msg->use_passphrase); } + if (msg->has_homescreen) { + storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); + } storage_commit(); fsm_sendSuccess("Settings applied"); layoutHome(); diff --git a/firmware/layout2.c b/firmware/layout2.c index d04ac026ba..796d1f3bfc 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -57,11 +57,20 @@ void layoutHome(void) oledSwipeLeft(); } const char *label = storage_getLabel(); - if (label && strlen(label) > 0) { - oledDrawBitmap(44, 4, &bmp_logo48); - oledDrawStringCenter(OLED_HEIGHT - 8, label); + const uint8_t *homescreen = storage_getHomescreen(); + if (homescreen) { + BITMAP b; + b.width = 128; + b.height = 64; + b.data = homescreen; + oledDrawBitmap(0, 0, &b); } else { - oledDrawBitmap(40, 0, &bmp_logo64); + if (label && strlen(label) > 0) { + oledDrawBitmap(44, 4, &bmp_logo48); + oledDrawStringCenter(OLED_HEIGHT - 8, label); + } else { + oledDrawBitmap(40, 0, &bmp_logo64); + } } oledRefresh(); } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 11fdc49c01..64a5431f29 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -8,6 +8,7 @@ Features.bootloader_hash max_size:32 ApplySettings.language max_size:17 ApplySettings.label max_size:33 +ApplySettings.homescreen max_size:1024 Ping.message max_size:256 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index d11890edf3..874ebd04f1 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -42,10 +42,11 @@ const pb_field_t ClearSession_fields[1] = { PB_LAST_FIELD }; -const pb_field_t ApplySettings_fields[4] = { +const pb_field_t ApplySettings_fields[5] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, ApplySettings, homescreen, use_passphrase, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 0c85401a89..cec27de26e 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -114,6 +114,11 @@ typedef struct _Address { char address[36]; } Address; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} ApplySettings_homescreen_t; + typedef struct _ApplySettings { bool has_language; char language[17]; @@ -121,6 +126,8 @@ typedef struct _ApplySettings { char label[33]; bool has_use_passphrase; bool use_passphrase; + bool has_homescreen; + ApplySettings_homescreen_t homescreen; } ApplySettings; typedef struct _ButtonRequest { @@ -584,7 +591,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Initialize_init_default {0} #define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_default {0} -#define ApplySettings_init_default {false, "", false, "", false, 0} +#define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} #define Ping_init_default {false, "", false, 0, false, 0, false, 0} #define Success_init_default {false, ""} @@ -635,7 +642,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Initialize_init_zero {0} #define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_zero {0} -#define ApplySettings_init_zero {false, "", false, "", false, 0} +#define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} #define Ping_init_zero {false, "", false, 0, false, 0, false, 0} #define Success_init_zero {false, ""} @@ -689,6 +696,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define ApplySettings_language_tag 1 #define ApplySettings_label_tag 2 #define ApplySettings_use_passphrase_tag 3 +#define ApplySettings_homescreen_tag 4 #define ButtonRequest_code_tag 1 #define ButtonRequest_data_tag 2 #define ChangePin_remove_tag 1 @@ -811,7 +819,7 @@ extern const char SimpleSignTx_coin_name_default[17]; extern const pb_field_t Initialize_fields[1]; extern const pb_field_t Features_fields[16]; extern const pb_field_t ClearSession_fields[1]; -extern const pb_field_t ApplySettings_fields[4]; +extern const pb_field_t ApplySettings_fields[5]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; extern const pb_field_t Success_fields[2]; @@ -864,7 +872,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define Initialize_size 0 #define Features_size (230 + 5*CoinType_size) #define ClearSession_size 0 -#define ApplySettings_size 56 +#define ApplySettings_size 1083 #define ChangePin_size 2 #define Ping_size 265 #define Success_size 259 diff --git a/firmware/protob/storage.options b/firmware/protob/storage.options index eb495de973..b7b6db2e95 100644 --- a/firmware/protob/storage.options +++ b/firmware/protob/storage.options @@ -2,3 +2,4 @@ Storage.mnemonic max_size:241 Storage.pin max_size:10 Storage.language max_size:17 Storage.label max_size:33 +Storage.homescreen max_size:1024 diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 34b40d3c88..68da897f29 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -5,7 +5,7 @@ -const pb_field_t Storage_fields[10] = { +const pb_field_t Storage_fields[11] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -15,6 +15,7 @@ const pb_field_t Storage_fields[10] = { PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), + PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), PB_LAST_FIELD }; @@ -32,14 +33,7 @@ STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_3 #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_16BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in the default - * 8 bit descriptors. - */ -STATIC_ASSERT((pb_membersize(Storage, node) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_Storage) +#error Field descriptor for Storage.homescreen is too large. Define PB_FIELD_16BIT to fix this. #endif diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 8251f47359..2f51923fd2 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -12,6 +12,11 @@ extern "C" { /* Enum definitions */ /* Struct definitions */ +typedef struct { + size_t size; + uint8_t bytes[1024]; +} Storage_homescreen_t; + typedef struct _Storage { uint32_t version; bool has_node; @@ -30,13 +35,15 @@ typedef struct _Storage { char label[33]; bool has_imported; bool imported; + bool has_homescreen; + Storage_homescreen_t homescreen; } Storage; /* Default values for struct fields */ /* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0} +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 @@ -48,12 +55,13 @@ typedef struct _Storage { #define Storage_language_tag 7 #define Storage_label_tag 8 #define Storage_imported_tag 9 +#define Storage_homescreen_tag 10 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[10]; +extern const pb_field_t Storage_fields[11]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (332 + HDNodeType_size) +#define Storage_size (1359 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/storage.c b/firmware/storage.c index f573ca6cb5..bc9aaea8fe 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -220,6 +220,19 @@ void storage_setPassphraseProtection(bool passphrase_protection) storage.passphrase_protection = passphrase_protection; } +void storage_setHomescreen(const uint8_t *data, uint32_t size) +{ + if (data && size == 1024) { + storage.has_homescreen = true; + memcpy(storage.homescreen.bytes, data, size); + storage.homescreen.size = size; + } else { + storage.has_homescreen = false; + memset(storage.homescreen.bytes, 0, sizeof(storage.homescreen.bytes)); + storage.homescreen.size = 0; + } +} + void get_root_node_callback(uint32_t iter, uint32_t total) { layoutProgress("Waking up", 1000 * iter / total); @@ -285,6 +298,11 @@ const char *storage_getLanguage(void) return storage.has_language ? storage.language : 0; } +const uint8_t *storage_getHomescreen(void) +{ + return (storage.has_homescreen && storage.homescreen.size == 1024) ? storage.homescreen.bytes : 0; +} + bool storage_isPinCorrect(const char *pin) { return strcmp(storage.pin, pin) == 0; diff --git a/firmware/storage.h b/firmware/storage.h index 58021b8f28..828dea7b2f 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -43,6 +43,9 @@ void storage_setLanguage(const char *lang); void storage_setPassphraseProtection(bool passphrase_protection); +const uint8_t *storage_getHomescreen(void); +void storage_setHomescreen(const uint8_t *data, uint32_t size); + void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); diff --git a/trezor-common b/trezor-common index f5d880c96c..201b66a559 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit f5d880c96c72c298e0fb412bcb1abba6a4ddac02 +Subproject commit 201b66a559567031f74621615884946c8bf1e837 From ed3fbf901cb8c9f94439071b6ee4ab89b37b7796 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Feb 2015 18:59:43 +0100 Subject: [PATCH 0092/1154] passphrase protection -> encryption (in dialog) --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 115105ef5a..1f88c9d84f 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -456,7 +456,7 @@ void fsm_msgApplySettings(ApplySettings *msg) } } if (msg->has_use_passphrase) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "protection?", NULL, NULL, NULL); + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); layoutHome(); From 03faa85cc4c9beeb89740b8bb65c02e2de2ab66a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 Feb 2015 17:38:32 +0100 Subject: [PATCH 0093/1154] integrate signing reorder patch by Jochen --- firmware/signing.c | 414 +++++++++++++++++++++++++++------------------ trezor-crypto | 2 +- 2 files changed, 249 insertions(+), 167 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index aee2faf3e4..045ed1255a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -37,11 +37,12 @@ enum { STAGE_REQUEST_2_PREV_META, STAGE_REQUEST_2_PREV_INPUT, STAGE_REQUEST_2_PREV_OUTPUT, - STAGE_REQUEST_3_INPUT, STAGE_REQUEST_3_OUTPUT, - STAGE_REQUEST_4_OUTPUT + STAGE_REQUEST_4_INPUT, + STAGE_REQUEST_4_OUTPUT, + STAGE_REQUEST_5_OUTPUT } signing_stage; -static uint32_t idx1i, idx2i, idx2o, idx3i, idx3o, idx4o; +static uint32_t idx1, idx2; static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; @@ -55,57 +56,74 @@ static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; /* + Workflow of streamed signing +The STAGE_ constants describe the signing_stage when request is sent. I - input O - output -foreach I: - Request I STAGE_REQUEST_1_INPUT +Phase1 - check inputs, previous transactions, and outputs + - ask for confirmations + - check fee +========================================================= +foreach I (idx1): + Request I STAGE_REQUEST_1_INPUT + Add I to TransactionChecksum Calculate amount of I: Request prevhash I, META STAGE_REQUEST_2_PREV_META - foreach prevhash I: STAGE_REQUEST_2_PREV_INPUT - Request prevhash I - foreach prevhash O: STAGE_REQUEST_2_PREV_OUTPUT - Request prevhash O - Store amount of I + foreach prevhash I (idx2): + Request prevhash I STAGE_REQUEST_2_PREV_INPUT + foreach prevhash O (idx2): + Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT + Add amount of prevhash O (which is amount of I) Calculate hash of streamed tx, compare to prevhash I +foreach O (idx1): + Request O STAGE_REQUEST_3_OUTPUT + Add O to TransactionChecksum + Display output + Ask for confirmation - foreach I: STAGE_REQUEST_3_INPUT - Request I - If I == I-to-be-signed: +Check tx fee +Ask for confirmation + +Phase2: sign inputs, check that nothing changed +=============================================== + +foreach I (idx1): // input to sign + foreach I (idx2): + Request I STAGE_REQUEST_4_INPUT + If idx1 == idx2 + Remember key for signing Fill scriptsig Add I to StreamTransactionSign - foreach O: - Request O STAGE_REQUEST_3_OUTPUT - If I=0: - Display output - Ask for confirmation + Add I to TransactionChecksum + foreach O (idx2): + Request O STAGE_REQUEST_4_OUTPUT Add O to StreamTransactionSign + Add O to TransactionChecksum - If I=0: - Check tx fee - Calculate txhash - else: - Compare current hash with txhash - If different: - Failure - + Compare TransactionChecksum with checksum computed in Phase 1 + If different: + Failure Sign StreamTransactionSign Return signed chunk - */ +foreach O (idx1): + Request O STAGE_REQUEST_5_OUTPUT + Rewrite change address + Return O +*/ void send_req_1_input(void) { layoutProgress("Signing transaction", 1000 * progress / progress_total); - idx2i = idx2o = idx3i = idx3o = 0; signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; - resp.details.request_index = idx1i; + resp.details.request_index = idx1; msg_write(MessageType_MessageType_TxRequest, &resp); } @@ -130,7 +148,7 @@ void send_req_2_prev_input(void) resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; - resp.details.request_index = idx2i; + resp.details.request_index = idx2; resp.details.has_tx_hash = true; resp.details.tx_hash.size = input.prev_hash.size; memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); @@ -145,25 +163,13 @@ void send_req_2_prev_output(void) resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; - resp.details.request_index = idx2o; + resp.details.request_index = idx2; resp.details.has_tx_hash = true; resp.details.tx_hash.size = input.prev_hash.size; memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_3_input(void) -{ - layoutProgress("Signing transaction", 1000 * progress / progress_total); - signing_stage = STAGE_REQUEST_3_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx3i; - msg_write(MessageType_MessageType_TxRequest, &resp); -} - void send_req_3_output(void) { layoutProgress("Signing transaction", 1000 * progress / progress_total); @@ -172,7 +178,19 @@ void send_req_3_output(void) resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; - resp.details.request_index = idx3o; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_4_input(void) +{ + layoutProgress("Signing transaction", 1000 * progress / progress_total); + signing_stage = STAGE_REQUEST_4_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; msg_write(MessageType_MessageType_TxRequest, &resp); } @@ -184,7 +202,19 @@ void send_req_4_output(void) resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; - resp.details.request_index = idx4o; + resp.details.request_index = idx2; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_5_output(void) +{ + layoutProgress("Signing transaction", 1000 * progress / progress_total); + signing_stage = STAGE_REQUEST_5_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; msg_write(MessageType_MessageType_TxRequest, &resp); } @@ -203,7 +233,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp coin = _coin; root = _root; - idx1i = idx2i = idx2o = idx3i = idx3o = idx4o = 0; + idx1 = 0; to_spend = 0; spending = 0; change_spend = 0; @@ -218,6 +248,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp multisig_fp_mismatch = false; tx_init(&to, inputs_count, outputs_count, version, lock_time, false); + tx_init(&tc, inputs_count, outputs_count, version, lock_time, false); layoutProgressSwipe("Signing transaction", 0); @@ -240,11 +271,40 @@ void signing_txack(TransactionType *tx) switch (signing_stage) { case STAGE_REQUEST_1_INPUT: progress++; + /* compute multisig fingerprint */ + /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && + tx->inputs[0].has_multisig && !multisig_fp_mismatch) { + if (multisig_fp_set) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + multisig_fp_set = true; + } + } + if (!tx_serialize_input_hash(&tc, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + signing_abort(); + return; + } memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); return; case STAGE_REQUEST_2_PREV_META: tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false); + idx2 = 0; send_req_2_prev_input(); return; case STAGE_REQUEST_2_PREV_INPUT: @@ -253,10 +313,11 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx2i < tp.inputs_len - 1) { - idx2i++; + if (idx2 < tp.inputs_len - 1) { + idx2++; send_req_2_prev_input(); } else { + idx2 = 0; send_req_2_prev_output(); } return; @@ -266,57 +327,136 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx2o == input.prev_index) { + if (idx2 == input.prev_index) { to_spend += tx->bin_outputs[0].amount; } - if (idx2o < tp.outputs_len - 1) { - idx2o++; + if (idx2 < tp.outputs_len - 1) { + /* Check prevtx of next input */ + idx2++; send_req_2_prev_output(); } else { + /* Check next output */ tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); signing_abort(); return; } - tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); - tx_init(&tc, inputs_count, outputs_count, version, lock_time, true); - memset(privkey, 0, 32); - memset(pubkey, 0, 33); - send_req_3_input(); + if (idx1 < inputs_count - 1) { + idx1++; + send_req_1_input(); + } else { + idx1 = 0; + send_req_3_output(); + } } return; - case STAGE_REQUEST_3_INPUT: + case STAGE_REQUEST_3_OUTPUT: + { + /* Downloaded output idx1 the first time. + * Add it to transaction check + * Ask for permission. + */ + bool is_change = false; + if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && + tx->outputs[0].has_multisig && + multisig_fp_set && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) == 0) { + is_change = true; + } + } else + if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && + tx->outputs[0].address_n_count > 0) { + is_change = true; + } + + if (is_change) { + if (change_spend == 0) { // not set + change_spend = tx->outputs[0].amount; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + signing_abort(); + return; + } + } + + spending += tx->outputs[0].amount; + co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); + if (!is_change) { + layoutProgress("Signing transaction", 1000 * progress / progress_total); + } + if (co < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); + signing_abort(); + return; + } else if (co == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + signing_abort(); + return; + } + if (!tx_serialize_output_hash(&tc, &bin_output)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + signing_abort(); + return; + } + if (idx1 < outputs_count - 1) { + idx1++; + send_req_3_output(); + } else { + tx_hash_final(&tc, hash_check, false); + + // check fees + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); + layoutHome(); + return; + } + uint64_t fee = to_spend - spending; + uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); + if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee, tx_est_size); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); + layoutHome(); + return; + } + } + // last confirmation + layoutConfirmTx(coin, to_spend - change_spend, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + signing_abort(); + return; + } + + // Everything was checked, now phase 2 begins and the transaction is signed. + idx1 = 0; + idx2 = 0; + send_req_4_input(); + } + return; + } + case STAGE_REQUEST_4_INPUT: + if (idx2 == 0) { + tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); + tx_init(&tc, inputs_count, outputs_count, version, lock_time, false); + memset(privkey, 0, 32); + memset(pubkey, 0, 33); + } progress++; if (!tx_serialize_input_hash(&tc, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); return; } - if (idx1i == 0) { - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && - tx->inputs[0].has_multisig && !multisig_fp_mismatch) { - if (multisig_fp_set) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - multisig_fp_set = true; - } - } - } - if (idx3i == idx1i) { + if (idx2 == idx1) { + memcpy(&input, tx->inputs, sizeof(TxInputType)); memcpy(&node, root, sizeof(HDNode)); if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); @@ -349,51 +489,17 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx3i < inputs_count - 1) { - idx3i++; - send_req_3_input(); + if (idx2 < inputs_count - 1) { + idx2++; + send_req_4_input(); } else { - send_req_3_output(); + idx2 = 0; + send_req_4_output(); } return; - case STAGE_REQUEST_3_OUTPUT: + case STAGE_REQUEST_4_OUTPUT: progress++; - if (idx1i == 0) { - bool is_change = false; - if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && - tx->outputs[0].has_multisig && - multisig_fp_set && !multisig_fp_mismatch) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - if (memcmp(multisig_fp, h, 32) == 0) { - is_change = true; - } - } else - if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && - tx->outputs[0].address_n_count > 0) { - is_change = true; - } - if (is_change) { - if (change_spend == 0) { // not set - change_spend = tx->outputs[0].amount; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); - signing_abort(); - return; - } - } - spending += tx->outputs[0].amount; - co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); - if (!is_change) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); - } - } else { - co = compile_output(coin, root, tx->outputs, &bin_output, false); - } + co = compile_output(coin, root, tx->outputs, &bin_output, false); if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); signing_abort(); @@ -413,24 +519,20 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx3o < outputs_count - 1) { - idx3o++; - send_req_3_output(); + if (idx2 < outputs_count - 1) { + idx2++; + send_req_4_output(); } else { - if (idx1i == 0) { - tx_hash_final(&tc, hash_check, false); - } else { - tx_hash_final(&tc, hash, false); - if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); - signing_abort(); - return; - } + tx_hash_final(&tc, hash, false); + if (memcmp(hash, hash_check, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return; } tx_hash_final(&ti, hash, false); resp.has_serialized = true; resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1i; + resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(privkey, hash, sig, 0); @@ -460,39 +562,19 @@ void signing_txack(TransactionType *tx) input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); - if (idx1i < inputs_count - 1) { - idx1i++; - send_req_1_input(); + if (idx1 < inputs_count - 1) { + idx1++; + idx2 = 0; + send_req_4_input(); } else { - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); - layoutHome(); - return; - } - uint64_t fee = to_spend - spending; - uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); - if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, tx_est_size); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - layoutHome(); - return; - } - } - // last confirmation - layoutConfirmTx(coin, to_spend - change_spend, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - signing_abort(); - return; - } - send_req_4_output(); + idx1 = 0; + send_req_5_output(); } } return; - case STAGE_REQUEST_4_OUTPUT: + case STAGE_REQUEST_5_OUTPUT: progress++; - if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { + if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); signing_abort(); return; @@ -500,9 +582,9 @@ void signing_txack(TransactionType *tx) resp.has_serialized = true; resp.serialized.has_serialized_tx = true; resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); - if (idx4o < outputs_count - 1) { - idx4o++; - send_req_4_output(); + if (idx1 < outputs_count - 1) { + idx1++; + send_req_5_output(); } else { send_req_finished(); signing_abort(); diff --git a/trezor-crypto b/trezor-crypto index 54aa5a4482..f4fe7c9aa5 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 54aa5a4482eaf6f11c0c6941be5e34aa3a5ff5e2 +Subproject commit f4fe7c9aa5e85ec3898ce07a5af5fc99bb8f5de4 From ac8d9510278316eb8f18e9bcaae35f05bc1ab82b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 14:21:43 +0100 Subject: [PATCH 0094/1154] fix usage of font special characters --- gen/fonts.c | 14 +++++++++----- gen/fonts.h | 2 +- gen/fonts/font.png | Bin 1079 -> 1114 bytes layout.c | 12 ++++++------ 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/gen/fonts.c b/gen/fonts.c index b811732b62..d562c1dfc9 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -9,8 +9,8 @@ const uint8_t *font_data[FONT_END - FONT_START + 1] = { (uint8_t *)"\x06\xc0\xc6\x1c\x70\xc6\x06", (uint8_t *)"\x06\x5c\xfe\xb2\xfe\x4c\x1e", (uint8_t *)"\x01\xc0", - (uint8_t *)"\x03\x3c\x7e\x81", - (uint8_t *)"\x03\x81\x7e\x3c", + (uint8_t *)"\x03\x38\x7c\x82", + (uint8_t *)"\x03\x82\x7c\x38", (uint8_t *)"\x05\x6c\x38\xfe\x38\x6c", (uint8_t *)"\x05\x10\x10\x7c\x10\x10", (uint8_t *)"\x02\x03\x06", @@ -60,9 +60,9 @@ const uint8_t *font_data[FONT_END - FONT_START + 1] = { (uint8_t *)"\x06\xc6\xee\x38\x38\xee\xc6", (uint8_t *)"\x06\xc0\xe0\x3e\x3e\xe0\xc0", (uint8_t *)"\x05\x8e\x9e\xba\xf2\xe2", - (uint8_t *)"\x03\xff\xff\x81", + (uint8_t *)"\x03\xfe\xfe\x82", (uint8_t *)"\x03\xe0\x38\x0e", - (uint8_t *)"\x03\x81\xff\xff", + (uint8_t *)"\x03\x82\xfe\xfe", (uint8_t *)"\x03\x60\xc0\x60", (uint8_t *)"\x06\x02\x02\x02\x02\x02\x02", (uint8_t *)"\x02\x80\x40", @@ -92,8 +92,12 @@ const uint8_t *font_data[FONT_END - FONT_START + 1] = { (uint8_t *)"\x05\x36\x3e\x08\x3e\x36", (uint8_t *)"\x05\x38\x3d\x05\x3f\x3e", (uint8_t *)"\x05\x26\x2e\x3a\x32\x22", - (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", + (uint8_t *)"\x04\x10\x7c\xee\x82", (uint8_t *)"\x02\xff\xff", + (uint8_t *)"\x04\x82\xee\x7c\x10", + (uint8_t *)"\x04\x08\x10\x08\x10", + (uint8_t *)"\x02\x00\x00", + (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", (uint8_t *)"\x06\x10\x38\x7c\x10\x10\x10", (uint8_t *)"\x06\x10\x10\x10\x7c\x38\x10", diff --git a/gen/fonts.h b/gen/fonts.h index 0cd6b62200..b4465ea662 100644 --- a/gen/fonts.h +++ b/gen/fonts.h @@ -4,7 +4,7 @@ #include #define FONT_START 32 -#define FONT_END 128 +#define FONT_END 132 #define FONT_HEIGHT 8 int fontCharWidth(char c); diff --git a/gen/fonts/font.png b/gen/fonts/font.png index efc88495d6dc5fc311dc2323589921237abf321f..6aa04f5d2be9d38ad2eda1be1b65035ea510879b 100644 GIT binary patch literal 1114 zcmV-g1f~0lP)v((iUwh8hdfcnf-!p&m&~bGv-6rS-arEyM@= zp5_=uIPq&C8Jjr0$R~84N5YuMEgm?+D$-<9H&t2tb{5J93OFj#KvZqD^$c?axXwT{xa>Mv+Fw`qCg!(5{)-JFtoR)0`Qea0N|9-K?Dz-O^d0eXsagb!PO1?& z2;Lbb3`kZLtI%=3%cxqoj`L?R#`lyNb+I#Lc9XbsNkf<~D#|;{?O5ui4O(zgaf6_3 z{0V>IOsQE=+Zx!ZWGWDfp*ghq6`k)7g(L}xlSKNKQOAVoVi#7U`EWJM5{t+lr@5GF zs~80k&U1MQ2jaX3I|N~D1aK#!{UU!Qze!FbfElN@z5&YTk98*!4oVsnA3JeOdl6l>J>{x>fYF(Cl zxs4{B(7AH}qfsjxJ#}{EWdOxArV{on%JR6fP#eh93?BLy(x3&s&D;XP#IYS0g;MlB zIRnA@ZBperrk$(8kvO!hK!m?o<;dLea(*3)NDK2H-${2a<$yXu1R7k z8TbtXX3UYj*FtGE^ZN?=#N?E`EW=c>!@DZ%Pb)4g2)LjNl>lO!ebM>-P4x0S&0jdl z4O7B>N2v$AO%V1upFO)T7}S0^e<-%~vJaWu^cDO}#`D+ZJ<42ebf+-F>1syazDV$h zRk-XtM80=HUfVpp)G)06ZRQTynNgvSuy9w%D}MUPlH>uffS{xWP$D-F9)ii_vnOEj z!|7B$9#cYnr-)?^=UFJd?#BtZUt+n^HDw<&o#EvyQaN8nU_XF~SsiC`=ouieYsYs| z?j|3!bcKwbUrCOV07*qoM6N<$f}wyKYXATM literal 1079 zcmV-71jze|P)<9}F+Y19Ur+cIa*hUZp8~um{-mL!>e#w1&@*_d+~2c6ydi(S2SCVIsA7;z(8zC*!)Qij!xr6&LtNsUpxzz>rdPbD=aup$!f_ z@b0LcU}{DJP$wP4nOF~Rh71g?7cVkHM{{bASNTUu=L``qIub6Zrr?Luf;>;AQzZ&aD59a0k5TP^a{s=vsSAgVW>l)QB`VH*t&}(?K8s zJ(`;f5eOxjd@`w$Pmy>>7~eOW*mD7AMI0zqTOB>YTmoEYpfot|I$At^`;Q}@!X<}G zAkc&z^0MjepKQkFw}kxXMs(dnKNHnMvA7=c0~PKaPIC=tu_(HmhTzoY9T;I~u`2Q` z3h^%UXn{AbpG6A~DKn;JXBz7kakWB|FyB<}38OovDHpFGD>>BdrNElFpw?wslsjkwgl?J(FdDUT&{Ops zFU=Lx5amoPD>D|cPmtk2HG_rtLPE2kx6v(RY7?z8^VPkBbWnnkdlC`W>WKNx#TFz@z2CL($7edlyfX>SDUH5JdGD4~pzNBuOZTrb|Rb zSlF-iZ_$~jqx)AzY-sDLv!Z(-DNzNvFcu9P`P#iH)& zL_e*9u-tax6Dk38OxZslzki7Sny20i)fL?I7NJ3FRC1kVA?#B=TTd?-)P7)oC`$Fb z4~g9L6}(R3nJ5V)utCRFQHgDEyhs>`J+7=qfvpv>>k>mq_B^FAN<7c%I0Zk7g*!Fg zPt&VC647CKt^|0AnM1saCd))aJKCJ?O4qi@fG>RKoqpi xJHh1MGgb^Dga_^ftKzbRuk6nBq~f_)@DH^x^cbajO1J<3002ovPDHLkV1g+<|GfYJ diff --git a/layout.c b/layout.c index ae082eea7e..bef3a6c9c2 100644 --- a/layout.c +++ b/layout.c @@ -67,14 +67,14 @@ void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, } } if (btnNo) { - oledDrawString(1, OLED_HEIGHT - 8, "{"); - oledDrawString(fontCharWidth('{') + 3, OLED_HEIGHT - 8, btnNo); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('{') + fontStringWidth(btnNo) + 2, OLED_HEIGHT - 1); + oledDrawString(1, OLED_HEIGHT - 8, "\x80"); + oledDrawString(fontCharWidth('\x80') + 3, OLED_HEIGHT - 8, btnNo); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\x80') + fontStringWidth(btnNo) + 2, OLED_HEIGHT - 1); } if (btnYes) { - oledDrawString(OLED_WIDTH - fontCharWidth('}') - 1, OLED_HEIGHT - 8, "}"); - oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth('\x81') - 1, OLED_HEIGHT - 8, "\x81"); + oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('\x81') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('\x81') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } oledRefresh(); } From 7fd1e894f5a02170171010e3f42e66a3b418fdb7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 15:37:23 +0100 Subject: [PATCH 0095/1154] refactor font handling --- firmware/layout2.c | 6 +- gen/fonts.c | 374 +++++++++++++++++++++++++++++------------- gen/fonts.h | 8 +- gen/fonts/font.png | Bin 1114 -> 1196 bytes gen/fonts/generate.py | 5 +- layout.c | 12 +- oled.c | 39 ++--- oled.h | 1 + 8 files changed, 297 insertions(+), 148 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 796d1f3bfc..6ea2b0a363 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -252,9 +252,9 @@ void layoutAddress(const char *address) oledDrawString(68, 3 * 9, str[3]); static const char *btnYes = "Continue"; - oledDrawString(OLED_WIDTH - fontCharWidth('}') - 1, OLED_HEIGHT - 8, "}"); - oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('}') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth('\xff') - 1, OLED_HEIGHT - 8, "\xff"); + oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledRefresh(); } diff --git a/gen/fonts.c b/gen/fonts.c index d562c1dfc9..af0504486c 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -1,122 +1,268 @@ #include "fonts.h" -const uint8_t *font_data[FONT_END - FONT_START + 1] = { - (uint8_t *)"\x01\x00", - (uint8_t *)"\x02\xfa\xfa", - (uint8_t *)"\x03\xc0\x00\xc0", - (uint8_t *)"\x05\x6c\xfe\x6c\xfe\x6c", - (uint8_t *)"\x05\x32\xff\x5a\xff\x4c", - (uint8_t *)"\x06\xc0\xc6\x1c\x70\xc6\x06", - (uint8_t *)"\x06\x5c\xfe\xb2\xfe\x4c\x1e", - (uint8_t *)"\x01\xc0", - (uint8_t *)"\x03\x38\x7c\x82", - (uint8_t *)"\x03\x82\x7c\x38", - (uint8_t *)"\x05\x6c\x38\xfe\x38\x6c", - (uint8_t *)"\x05\x10\x10\x7c\x10\x10", - (uint8_t *)"\x02\x03\x06", - (uint8_t *)"\x04\x10\x10\x10\x10", - (uint8_t *)"\x02\x06\x06", - (uint8_t *)"\x03\x0e\x38\xe0", - (uint8_t *)"\x05\x7c\xfe\x82\xfe\x7c", - (uint8_t *)"\x03\x40\xfe\xfe", - (uint8_t *)"\x05\x8e\x9e\x92\xf2\x62", - (uint8_t *)"\x05\x82\x92\x92\xfe\x6c", - (uint8_t *)"\x05\x18\x28\x48\xfe\xfe", - (uint8_t *)"\x05\xe2\xa2\xa2\xbe\x1c", - (uint8_t *)"\x05\x7c\xfe\xa2\xbe\x1c", - (uint8_t *)"\x05\x80\x8e\xbe\xf0\xc0", - (uint8_t *)"\x05\x6c\xfe\x92\xfe\x6c", - (uint8_t *)"\x05\x70\xfa\x8a\xfe\x7c", - (uint8_t *)"\x02\x36\x36", - (uint8_t *)"\x02\x33\x36", - (uint8_t *)"\x04\x10\x38\x6c\xc6", - (uint8_t *)"\x04\x28\x28\x28\x28", - (uint8_t *)"\x04\xc6\x6c\x38\x10", - (uint8_t *)"\x05\x80\x9a\xba\xe0\x40", - (uint8_t *)"\x06\x7c\xfe\xaa\xba\xfa\x78", - (uint8_t *)"\x05\x7e\xfe\x88\xfe\x7e", - (uint8_t *)"\x05\xfe\xfe\xa2\xfe\x5c", - (uint8_t *)"\x05\x7c\xfe\x82\x82\x82", - (uint8_t *)"\x05\xfe\xfe\x82\xfe\x7c", - (uint8_t *)"\x05\xfe\xfe\xa2\xa2\x82", - (uint8_t *)"\x05\xfe\xfe\xa0\xa0\x80", - (uint8_t *)"\x05\x7c\xfe\x82\x9e\x1e", - (uint8_t *)"\x05\xfe\xfe\x20\xfe\xfe", - (uint8_t *)"\x02\xfe\xfe", - (uint8_t *)"\x04\x02\x02\xfe\xfc", - (uint8_t *)"\x06\xfe\xfe\x38\x6c\xc6\x82", - (uint8_t *)"\x04\xfe\xfe\x02\x02", - (uint8_t *)"\x07\xfe\x7e\x30\x18\x30\x7e\xfe", - (uint8_t *)"\x06\xfe\x7e\x30\x18\xfc\xfe", - (uint8_t *)"\x06\x7c\xfe\x82\x82\xfe\x7c", - (uint8_t *)"\x05\xfe\xfe\x88\xf8\x70", - (uint8_t *)"\x06\x7c\xfe\x82\x86\xff\x7d", - (uint8_t *)"\x05\xfe\xfe\x88\xfe\x72", - (uint8_t *)"\x04\x62\xf2\x9e\x8c", - (uint8_t *)"\x06\x80\x80\xfe\xfe\x80\x80", - (uint8_t *)"\x05\xfc\xfe\x02\xfe\xfc", - (uint8_t *)"\x06\xe0\xf8\x1e\x1e\xf8\xe0", - (uint8_t *)"\x07\xf0\xfe\x1e\x3c\x1e\xfe\xf0", - (uint8_t *)"\x06\xc6\xee\x38\x38\xee\xc6", - (uint8_t *)"\x06\xc0\xe0\x3e\x3e\xe0\xc0", - (uint8_t *)"\x05\x8e\x9e\xba\xf2\xe2", - (uint8_t *)"\x03\xfe\xfe\x82", - (uint8_t *)"\x03\xe0\x38\x0e", - (uint8_t *)"\x03\x82\xfe\xfe", - (uint8_t *)"\x03\x60\xc0\x60", - (uint8_t *)"\x06\x02\x02\x02\x02\x02\x02", - (uint8_t *)"\x02\x80\x40", - (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", - (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", - (uint8_t *)"\x04\x1c\x3e\x22\x22", - (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", - (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", - (uint8_t *)"\x03\x7e\xfe\xa0", - (uint8_t *)"\x05\x18\x3d\x25\x3f\x3e", - (uint8_t *)"\x05\xfe\xfe\x20\x3e\x1e", - (uint8_t *)"\x02\xbe\xbe", - (uint8_t *)"\x03\x01\xbf\xbe", - (uint8_t *)"\x05\xfe\xfe\x1c\x36\x22", - (uint8_t *)"\x02\xfe\xfe", - (uint8_t *)"\x08\x3e\x3e\x20\x3e\x3e\x20\x3e\x1e", - (uint8_t *)"\x05\x3e\x3e\x20\x3e\x1e", - (uint8_t *)"\x05\x1c\x3e\x22\x3e\x1c", - (uint8_t *)"\x05\x3f\x3f\x24\x3c\x18", - (uint8_t *)"\x05\x18\x3c\x24\x3f\x3f", - (uint8_t *)"\x04\x3e\x3e\x10\x30", - (uint8_t *)"\x04\x1a\x3a\x2e\x2c", - (uint8_t *)"\x03\xfc\xfe\x22", - (uint8_t *)"\x05\x3c\x3e\x02\x3e\x3e", - (uint8_t *)"\x05\x30\x3c\x0e\x3c\x30", - (uint8_t *)"\x07\x38\x3e\x06\x1c\x06\x3e\x38", - (uint8_t *)"\x05\x36\x3e\x08\x3e\x36", - (uint8_t *)"\x05\x38\x3d\x05\x3f\x3e", - (uint8_t *)"\x05\x26\x2e\x3a\x32\x22", - (uint8_t *)"\x04\x10\x7c\xee\x82", - (uint8_t *)"\x02\xff\xff", - (uint8_t *)"\x04\x82\xee\x7c\x10", - (uint8_t *)"\x04\x08\x10\x08\x10", - (uint8_t *)"\x02\x00\x00", - (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", - (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", - (uint8_t *)"\x06\x10\x38\x7c\x10\x10\x10", - (uint8_t *)"\x06\x10\x10\x10\x7c\x38\x10", - (uint8_t *)"\x05\x7e\xff\x52\xff\x2c", +const uint8_t *font_data[256] = { + /* 0x00 _ */ (uint8_t *)"\x01\x00", + /* 0x01 _ */ (uint8_t *)"\x01\x00", + /* 0x02 _ */ (uint8_t *)"\x01\x00", + /* 0x03 _ */ (uint8_t *)"\x01\x00", + /* 0x04 _ */ (uint8_t *)"\x01\x00", + /* 0x05 _ */ (uint8_t *)"\x01\x00", + /* 0x06 _ */ (uint8_t *)"\x01\x00", + /* 0x07 _ */ (uint8_t *)"\x01\x00", + /* 0x08 _ */ (uint8_t *)"\x01\x00", + /* 0x09 _ */ (uint8_t *)"\x01\x00", + /* 0x0a _ */ (uint8_t *)"\x01\x00", + /* 0x0b _ */ (uint8_t *)"\x01\x00", + /* 0x0c _ */ (uint8_t *)"\x01\x00", + /* 0x0d _ */ (uint8_t *)"\x01\x00", + /* 0x0e _ */ (uint8_t *)"\x01\x00", + /* 0x0f _ */ (uint8_t *)"\x01\x00", + /* 0x10 _ */ (uint8_t *)"\x01\x00", + /* 0x11 _ */ (uint8_t *)"\x01\x00", + /* 0x12 _ */ (uint8_t *)"\x01\x00", + /* 0x13 _ */ (uint8_t *)"\x01\x00", + /* 0x14 _ */ (uint8_t *)"\x01\x00", + /* 0x15 _ */ (uint8_t *)"\x01\x00", + /* 0x16 _ */ (uint8_t *)"\x01\x00", + /* 0x17 _ */ (uint8_t *)"\x01\x00", + /* 0x18 _ */ (uint8_t *)"\x01\x00", + /* 0x19 _ */ (uint8_t *)"\x01\x00", + /* 0x1a _ */ (uint8_t *)"\x01\x00", + /* 0x1b _ */ (uint8_t *)"\x01\x00", + /* 0x1c _ */ (uint8_t *)"\x01\x00", + /* 0x1d _ */ (uint8_t *)"\x01\x00", + /* 0x1e _ */ (uint8_t *)"\x01\x00", + /* 0x1f _ */ (uint8_t *)"\x01\x00", + /* 0x20 */ (uint8_t *)"\x01\x00", + /* 0x21 ! */ (uint8_t *)"\x02\xfa\xfa", + /* 0x22 " */ (uint8_t *)"\x03\xc0\x00\xc0", + /* 0x23 # */ (uint8_t *)"\x05\x6c\xfe\x6c\xfe\x6c", + /* 0x24 $ */ (uint8_t *)"\x05\x32\xff\x5a\xff\x4c", + /* 0x25 % */ (uint8_t *)"\x06\xc0\xc6\x1c\x70\xc6\x06", + /* 0x26 & */ (uint8_t *)"\x06\x5c\xfe\xb2\xfe\x4c\x1e", + /* 0x27 ' */ (uint8_t *)"\x01\xc0", + /* 0x28 ( */ (uint8_t *)"\x03\x38\x7c\x82", + /* 0x29 ) */ (uint8_t *)"\x03\x82\x7c\x38", + /* 0x2a * */ (uint8_t *)"\x05\x6c\x38\xfe\x38\x6c", + /* 0x2b + */ (uint8_t *)"\x05\x10\x10\x7c\x10\x10", + /* 0x2c , */ (uint8_t *)"\x02\x03\x06", + /* 0x2d - */ (uint8_t *)"\x04\x10\x10\x10\x10", + /* 0x2e . */ (uint8_t *)"\x02\x06\x06", + /* 0x2f / */ (uint8_t *)"\x03\x0e\x38\xe0", + /* 0x30 0 */ (uint8_t *)"\x05\x7c\xfe\x82\xfe\x7c", + /* 0x31 1 */ (uint8_t *)"\x03\x40\xfe\xfe", + /* 0x32 2 */ (uint8_t *)"\x05\x8e\x9e\x92\xf2\x62", + /* 0x33 3 */ (uint8_t *)"\x05\x82\x92\x92\xfe\x6c", + /* 0x34 4 */ (uint8_t *)"\x05\x18\x28\x48\xfe\xfe", + /* 0x35 5 */ (uint8_t *)"\x05\xe2\xa2\xa2\xbe\x1c", + /* 0x36 6 */ (uint8_t *)"\x05\x7c\xfe\xa2\xbe\x1c", + /* 0x37 7 */ (uint8_t *)"\x05\x80\x8e\xbe\xf0\xc0", + /* 0x38 8 */ (uint8_t *)"\x05\x6c\xfe\x92\xfe\x6c", + /* 0x39 9 */ (uint8_t *)"\x05\x70\xfa\x8a\xfe\x7c", + /* 0x3a : */ (uint8_t *)"\x02\x36\x36", + /* 0x3b ; */ (uint8_t *)"\x02\x33\x36", + /* 0x3c < */ (uint8_t *)"\x04\x10\x38\x6c\xc6", + /* 0x3d = */ (uint8_t *)"\x04\x28\x28\x28\x28", + /* 0x3e > */ (uint8_t *)"\x04\xc6\x6c\x38\x10", + /* 0x3f ? */ (uint8_t *)"\x05\x80\x9a\xba\xe0\x40", + /* 0x40 @ */ (uint8_t *)"\x06\x7c\xfe\xaa\xba\xfa\x78", + /* 0x41 A */ (uint8_t *)"\x05\x7e\xfe\x88\xfe\x7e", + /* 0x42 B */ (uint8_t *)"\x05\xfe\xfe\xa2\xfe\x5c", + /* 0x43 C */ (uint8_t *)"\x05\x7c\xfe\x82\x82\x82", + /* 0x44 D */ (uint8_t *)"\x05\xfe\xfe\x82\xfe\x7c", + /* 0x45 E */ (uint8_t *)"\x05\xfe\xfe\xa2\xa2\x82", + /* 0x46 F */ (uint8_t *)"\x05\xfe\xfe\xa0\xa0\x80", + /* 0x47 G */ (uint8_t *)"\x05\x7c\xfe\x82\x9e\x1e", + /* 0x48 H */ (uint8_t *)"\x05\xfe\xfe\x20\xfe\xfe", + /* 0x49 I */ (uint8_t *)"\x02\xfe\xfe", + /* 0x4a J */ (uint8_t *)"\x04\x02\x02\xfe\xfc", + /* 0x4b K */ (uint8_t *)"\x06\xfe\xfe\x38\x6c\xc6\x82", + /* 0x4c L */ (uint8_t *)"\x04\xfe\xfe\x02\x02", + /* 0x4d M */ (uint8_t *)"\x07\xfe\x7e\x30\x18\x30\x7e\xfe", + /* 0x4e N */ (uint8_t *)"\x06\xfe\x7e\x30\x18\xfc\xfe", + /* 0x4f O */ (uint8_t *)"\x06\x7c\xfe\x82\x82\xfe\x7c", + /* 0x50 P */ (uint8_t *)"\x05\xfe\xfe\x88\xf8\x70", + /* 0x51 Q */ (uint8_t *)"\x06\x7c\xfe\x82\x86\xff\x7d", + /* 0x52 R */ (uint8_t *)"\x05\xfe\xfe\x88\xfe\x72", + /* 0x53 S */ (uint8_t *)"\x04\x62\xf2\x9e\x8c", + /* 0x54 T */ (uint8_t *)"\x06\x80\x80\xfe\xfe\x80\x80", + /* 0x55 U */ (uint8_t *)"\x05\xfc\xfe\x02\xfe\xfc", + /* 0x56 V */ (uint8_t *)"\x06\xe0\xf8\x1e\x1e\xf8\xe0", + /* 0x57 W */ (uint8_t *)"\x07\xf0\xfe\x1e\x3c\x1e\xfe\xf0", + /* 0x58 X */ (uint8_t *)"\x06\xc6\xee\x38\x38\xee\xc6", + /* 0x59 Y */ (uint8_t *)"\x06\xc0\xe0\x3e\x3e\xe0\xc0", + /* 0x5a Z */ (uint8_t *)"\x05\x8e\x9e\xba\xf2\xe2", + /* 0x5b [ */ (uint8_t *)"\x03\xfe\xfe\x82", + /* 0x5c \ */ (uint8_t *)"\x03\xe0\x38\x0e", + /* 0x5d ] */ (uint8_t *)"\x03\x82\xfe\xfe", + /* 0x5e ^ */ (uint8_t *)"\x03\x60\xc0\x60", + /* 0x5f _ */ (uint8_t *)"\x06\x02\x02\x02\x02\x02\x02", + /* 0x60 ` */ (uint8_t *)"\x02\x80\x40", + /* 0x61 a */ (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", + /* 0x62 b */ (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", + /* 0x63 c */ (uint8_t *)"\x04\x1c\x3e\x22\x22", + /* 0x64 d */ (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", + /* 0x65 e */ (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", + /* 0x66 f */ (uint8_t *)"\x03\x7e\xfe\xa0", + /* 0x67 g */ (uint8_t *)"\x05\x18\x3d\x25\x3f\x3e", + /* 0x68 h */ (uint8_t *)"\x05\xfe\xfe\x20\x3e\x1e", + /* 0x69 i */ (uint8_t *)"\x02\xbe\xbe", + /* 0x6a j */ (uint8_t *)"\x03\x01\xbf\xbe", + /* 0x6b k */ (uint8_t *)"\x05\xfe\xfe\x1c\x36\x22", + /* 0x6c l */ (uint8_t *)"\x02\xfe\xfe", + /* 0x6d m */ (uint8_t *)"\x08\x3e\x3e\x20\x3e\x3e\x20\x3e\x1e", + /* 0x6e n */ (uint8_t *)"\x05\x3e\x3e\x20\x3e\x1e", + /* 0x6f o */ (uint8_t *)"\x05\x1c\x3e\x22\x3e\x1c", + /* 0x70 p */ (uint8_t *)"\x05\x3f\x3f\x24\x3c\x18", + /* 0x71 q */ (uint8_t *)"\x05\x18\x3c\x24\x3f\x3f", + /* 0x72 r */ (uint8_t *)"\x04\x3e\x3e\x10\x30", + /* 0x73 s */ (uint8_t *)"\x04\x1a\x3a\x2e\x2c", + /* 0x74 t */ (uint8_t *)"\x03\xfc\xfe\x22", + /* 0x75 u */ (uint8_t *)"\x05\x3c\x3e\x02\x3e\x3e", + /* 0x76 v */ (uint8_t *)"\x05\x30\x3c\x0e\x3c\x30", + /* 0x77 w */ (uint8_t *)"\x07\x38\x3e\x06\x1c\x06\x3e\x38", + /* 0x78 x */ (uint8_t *)"\x05\x36\x3e\x08\x3e\x36", + /* 0x79 y */ (uint8_t *)"\x05\x38\x3d\x05\x3f\x3e", + /* 0x7a z */ (uint8_t *)"\x05\x26\x2e\x3a\x32\x22", + /* 0x7b { */ (uint8_t *)"\x04\x10\x7c\xee\x82", + /* 0x7c | */ (uint8_t *)"\x02\xff\xff", + /* 0x7d } */ (uint8_t *)"\x04\x82\xee\x7c\x10", + /* 0x7e ~ */ (uint8_t *)"\x04\x08\x10\x08\x10", + /* 0x7f _ */ (uint8_t *)"\x01\x00", + /* 0x80 _ */ (uint8_t *)"\x01\x00", + /* 0x81 _ */ (uint8_t *)"\x01\x00", + /* 0x82 _ */ (uint8_t *)"\x01\x00", + /* 0x83 _ */ (uint8_t *)"\x01\x00", + /* 0x84 _ */ (uint8_t *)"\x01\x00", + /* 0x85 _ */ (uint8_t *)"\x01\x00", + /* 0x86 _ */ (uint8_t *)"\x01\x00", + /* 0x87 _ */ (uint8_t *)"\x01\x00", + /* 0x88 _ */ (uint8_t *)"\x01\x00", + /* 0x89 _ */ (uint8_t *)"\x01\x00", + /* 0x8a _ */ (uint8_t *)"\x01\x00", + /* 0x8b _ */ (uint8_t *)"\x01\x00", + /* 0x8c _ */ (uint8_t *)"\x01\x00", + /* 0x8d _ */ (uint8_t *)"\x01\x00", + /* 0x8e _ */ (uint8_t *)"\x01\x00", + /* 0x8f _ */ (uint8_t *)"\x01\x00", + /* 0x90 _ */ (uint8_t *)"\x01\x00", + /* 0x91 _ */ (uint8_t *)"\x01\x00", + /* 0x92 _ */ (uint8_t *)"\x01\x00", + /* 0x93 _ */ (uint8_t *)"\x01\x00", + /* 0x94 _ */ (uint8_t *)"\x01\x00", + /* 0x95 _ */ (uint8_t *)"\x01\x00", + /* 0x96 _ */ (uint8_t *)"\x01\x00", + /* 0x97 _ */ (uint8_t *)"\x01\x00", + /* 0x98 _ */ (uint8_t *)"\x01\x00", + /* 0x99 _ */ (uint8_t *)"\x01\x00", + /* 0x9a _ */ (uint8_t *)"\x01\x00", + /* 0x9b _ */ (uint8_t *)"\x01\x00", + /* 0x9c _ */ (uint8_t *)"\x01\x00", + /* 0x9d _ */ (uint8_t *)"\x01\x00", + /* 0x9e _ */ (uint8_t *)"\x01\x00", + /* 0x9f _ */ (uint8_t *)"\x01\x00", + /* 0xa0 _ */ (uint8_t *)"\x01\x00", + /* 0xa1 _ */ (uint8_t *)"\x01\x00", + /* 0xa2 _ */ (uint8_t *)"\x01\x00", + /* 0xa3 _ */ (uint8_t *)"\x01\x00", + /* 0xa4 _ */ (uint8_t *)"\x01\x00", + /* 0xa5 _ */ (uint8_t *)"\x01\x00", + /* 0xa6 _ */ (uint8_t *)"\x01\x00", + /* 0xa7 _ */ (uint8_t *)"\x01\x00", + /* 0xa8 _ */ (uint8_t *)"\x01\x00", + /* 0xa9 _ */ (uint8_t *)"\x01\x00", + /* 0xaa _ */ (uint8_t *)"\x01\x00", + /* 0xab _ */ (uint8_t *)"\x01\x00", + /* 0xac _ */ (uint8_t *)"\x01\x00", + /* 0xad _ */ (uint8_t *)"\x01\x00", + /* 0xae _ */ (uint8_t *)"\x01\x00", + /* 0xaf _ */ (uint8_t *)"\x01\x00", + /* 0xb0 _ */ (uint8_t *)"\x01\x00", + /* 0xb1 _ */ (uint8_t *)"\x01\x00", + /* 0xb2 _ */ (uint8_t *)"\x01\x00", + /* 0xb3 _ */ (uint8_t *)"\x01\x00", + /* 0xb4 _ */ (uint8_t *)"\x01\x00", + /* 0xb5 _ */ (uint8_t *)"\x01\x00", + /* 0xb6 _ */ (uint8_t *)"\x01\x00", + /* 0xb7 _ */ (uint8_t *)"\x01\x00", + /* 0xb8 _ */ (uint8_t *)"\x01\x00", + /* 0xb9 _ */ (uint8_t *)"\x01\x00", + /* 0xba _ */ (uint8_t *)"\x01\x00", + /* 0xbb _ */ (uint8_t *)"\x01\x00", + /* 0xbc _ */ (uint8_t *)"\x01\x00", + /* 0xbd _ */ (uint8_t *)"\x01\x00", + /* 0xbe _ */ (uint8_t *)"\x01\x00", + /* 0xbf _ */ (uint8_t *)"\x01\x00", + /* 0xc0 _ */ (uint8_t *)"\x01\x00", + /* 0xc1 _ */ (uint8_t *)"\x01\x00", + /* 0xc2 _ */ (uint8_t *)"\x01\x00", + /* 0xc3 _ */ (uint8_t *)"\x01\x00", + /* 0xc4 _ */ (uint8_t *)"\x01\x00", + /* 0xc5 _ */ (uint8_t *)"\x01\x00", + /* 0xc6 _ */ (uint8_t *)"\x01\x00", + /* 0xc7 _ */ (uint8_t *)"\x01\x00", + /* 0xc8 _ */ (uint8_t *)"\x01\x00", + /* 0xc9 _ */ (uint8_t *)"\x01\x00", + /* 0xca _ */ (uint8_t *)"\x01\x00", + /* 0xcb _ */ (uint8_t *)"\x01\x00", + /* 0xcc _ */ (uint8_t *)"\x01\x00", + /* 0xcd _ */ (uint8_t *)"\x01\x00", + /* 0xce _ */ (uint8_t *)"\x01\x00", + /* 0xcf _ */ (uint8_t *)"\x01\x00", + /* 0xd0 _ */ (uint8_t *)"\x01\x00", + /* 0xd1 _ */ (uint8_t *)"\x01\x00", + /* 0xd2 _ */ (uint8_t *)"\x01\x00", + /* 0xd3 _ */ (uint8_t *)"\x01\x00", + /* 0xd4 _ */ (uint8_t *)"\x01\x00", + /* 0xd5 _ */ (uint8_t *)"\x01\x00", + /* 0xd6 _ */ (uint8_t *)"\x01\x00", + /* 0xd7 _ */ (uint8_t *)"\x01\x00", + /* 0xd8 _ */ (uint8_t *)"\x01\x00", + /* 0xd9 _ */ (uint8_t *)"\x01\x00", + /* 0xda _ */ (uint8_t *)"\x01\x00", + /* 0xdb _ */ (uint8_t *)"\x01\x00", + /* 0xdc _ */ (uint8_t *)"\x01\x00", + /* 0xdd _ */ (uint8_t *)"\x01\x00", + /* 0xde _ */ (uint8_t *)"\x01\x00", + /* 0xdf _ */ (uint8_t *)"\x01\x00", + /* 0xe0 _ */ (uint8_t *)"\x01\x00", + /* 0xe1 _ */ (uint8_t *)"\x01\x00", + /* 0xe2 _ */ (uint8_t *)"\x01\x00", + /* 0xe3 _ */ (uint8_t *)"\x01\x00", + /* 0xe4 _ */ (uint8_t *)"\x01\x00", + /* 0xe5 _ */ (uint8_t *)"\x01\x00", + /* 0xe6 _ */ (uint8_t *)"\x01\x00", + /* 0xe7 _ */ (uint8_t *)"\x01\x00", + /* 0xe8 _ */ (uint8_t *)"\x01\x00", + /* 0xe9 _ */ (uint8_t *)"\x01\x00", + /* 0xea _ */ (uint8_t *)"\x01\x00", + /* 0xeb _ */ (uint8_t *)"\x01\x00", + /* 0xec _ */ (uint8_t *)"\x01\x00", + /* 0xed _ */ (uint8_t *)"\x01\x00", + /* 0xee _ */ (uint8_t *)"\x01\x00", + /* 0xef _ */ (uint8_t *)"\x01\x00", + /* 0xf0 _ */ (uint8_t *)"\x01\x00", + /* 0xf1 _ */ (uint8_t *)"\x01\x00", + /* 0xf2 _ */ (uint8_t *)"\x01\x00", + /* 0xf3 _ */ (uint8_t *)"\x01\x00", + /* 0xf4 _ */ (uint8_t *)"\x01\x00", + /* 0xf5 _ */ (uint8_t *)"\x01\x00", + /* 0xf6 _ */ (uint8_t *)"\x01\x00", + /* 0xf7 _ */ (uint8_t *)"\x01\x00", + /* 0xf8 _ */ (uint8_t *)"\x01\x00", + /* 0xf9 _ */ (uint8_t *)"\x01\x00", + /* 0xfa _ */ (uint8_t *)"\x01\x00", + /* 0xfb _ */ (uint8_t *)"\x01\x00", + /* 0xfc _ */ (uint8_t *)"\x01\x00", + /* 0xfd _ */ (uint8_t *)"\x01\x00", + /* 0xfe _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", + /* 0xff _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", }; int fontCharWidth(char c) { - if ((c < FONT_START) || (c > FONT_END)) { - c = '?'; - } - return font_data[(int)(c - FONT_START)][0]; + return font_data[(int)(c)][0]; } -int fontStringWidth(const char *s) { - if (!s) return 0; - int l = 0; - char *c; - for (c = (char *)s; *c; c++) { - l += fontCharWidth(*c) + 1; - } - return l; +const uint8_t *fontCharData(char c) { + return font_data[(int)(c)] + 1; } diff --git a/gen/fonts.h b/gen/fonts.h index b4465ea662..ecb5195285 100644 --- a/gen/fonts.h +++ b/gen/fonts.h @@ -3,13 +3,11 @@ #include -#define FONT_START 32 -#define FONT_END 132 #define FONT_HEIGHT 8 -int fontCharWidth(char c); -int fontStringWidth(const char *s); +extern const uint8_t *font_data[256]; -extern const uint8_t *font_data[FONT_END - FONT_START + 1]; +int fontCharWidth(char c); +const uint8_t *fontCharData(char c); #endif diff --git a/gen/fonts/font.png b/gen/fonts/font.png index 6aa04f5d2be9d38ad2eda1be1b65035ea510879b..9537b46f12633f8ce0ff830b8a014b8aa4573762 100644 GIT binary patch literal 1196 zcmV;d1XKHoP)SKH9FgH{kj{~jT3 zg`>1ITPwne9m|ukiqnd`Lnjh3Ux!F?>o@FSg*1`WRaFe0tyUcBKT3s_76I{;s%h(@ zkp!(X=^(q|c0i~R1YDgoHO9o+`fA9Ip|$XOW@va0?eT~|+A?{IL$s*Mfv%=Y9*_wP3%7k>}-t=uw7(N4w+6&2CgE^2TjU5 z%57ijsR^2h3~+*seSVSOF{V^4s7{Srnb{t=P;||q_Mg%DHvLH=Z|nr=Yo-o&DF?fd zg66~3EQ;olJx+5l)p|ApAnX}vh173c<2!^zTLf^GRaQxcJtq9X)v$G>uV-Uno;;h9 z{7c3%p0~~fc32DViZ8V2YRyW6d*yB_h%YwzSOkM+lh-kWlFfY*{Lz>glP+!=#!S;t zG?pQb*uF2NF%6fibF_!qg4+;B*uFFKhR>tL#buN>Eh#XmF@tecsCWlB? z3-`RqM7pSm(FL#Qmfp8)za}(lNX#fhc}HO3=IS!rl4%gmb3U4-o-nBMG4xFVWh;A^ z$&sTCU2k*Wu7qkk)J7vPxQL|$oR?r z`QXf*uS{&DP%`rv>5S0RQgSh48iDgsV{$9Sne2K77udN(HMvbeE-79c#ILf-V+w{k ze2f0`B(d>EKSF?)=q*6%g>DMn>Ws^CKRc-7c5k*tlrA&BRXo8UpClYZf1j%eSv*u2O^4q{Ij?&2f>@z}&RQr;h1^i0#}o>2`u2uSBZS zetwkEC^CJKzZ%_CbiIuW2v((iUwh8hdfcnf-!p&m&~bGv-6rS-arEyM@= zp5_=uIPq&C8Jjr0$R~84N5YuMEgm?+D$-<9H&t2tb{5J93OFj#KvZqD^$c?axXwT{xa>Mv+Fw`qCg!(5{)-JFtoR)0`Qea0N|9-K?Dz-O^d0eXsagb!PO1?& z2;Lbb3`kZLtI%=3%cxqoj`L?R#`lyNb+I#Lc9XbsNkf<~D#|;{?O5ui4O(zgaf6_3 z{0V>IOsQE=+Zx!ZWGWDfp*ghq6`k)7g(L}xlSKNKQOAVoVi#7U`EWJM5{t+lr@5GF zs~80k&U1MQ2jaX3I|N~D1aK#!{UU!Qze!FbfElN@z5&YTk98*!4oVsnA3JeOdl6l>J>{x>fYF(Cl zxs4{B(7AH}qfsjxJ#}{EWdOxArV{on%JR6fP#eh93?BLy(x3&s&D;XP#IYS0g;MlB zIRnA@ZBperrk$(8kvO!hK!m?o<;dLea(*3)NDK2H-${2a<$yXu1R7k z8TbtXX3UYj*FtGE^ZN?=#N?E`EW=c>!@DZ%Pb)4g2)LjNl>lO!ebM>-P4x0S&0jdl z4O7B>N2v$AO%V1upFO)T7}S0^e<-%~vJaWu^cDO}#`D+ZJ<42ebf+-F>1syazDV$h zRk-XtM80=HUfVpp)G)06ZRQTynNgvSuy9w%D}MUPlH>uffS{xWP$D-F9)ii_vnOEj z!|7B$9#cYnr-)?^=UFJd?#BtZUt+n^HDw<&o#EvyQaN8nU_XF~SsiC`=ouieYsYs| z?j|3!bcKwbUrCOV07*qoM6N<$f}wyKYXATM diff --git a/gen/fonts/generate.py b/gen/fonts/generate.py index b7a1dd7cf6..c50765d9d1 100755 --- a/gen/fonts/generate.py +++ b/gen/fonts/generate.py @@ -20,12 +20,15 @@ class Img(object): img = Img('font.png') cur = '' +idx = 0 for i in range(img.w): if img.pixel(i, 0) == None: cur = '\\x%02x' % (len(cur) / 4) + cur - print '\t(uint8_t *)"%s",' % cur + ch = chr(idx) if idx >= 32 and idx <= 126 else '_' + print '\t/* 0x%02x %c */ (uint8_t *)"%s",' % (idx, ch , cur) cur = '' + idx += 1 continue val = img.pixel(i, 0) + img.pixel(i, 1) + img.pixel(i, 2) + img.pixel(i, 3) + img.pixel(i, 4) + img.pixel(i, 5) + img.pixel(i, 6) + img.pixel(i, 7) cur += '\\x%02x' % int(val, 2) diff --git a/layout.c b/layout.c index bef3a6c9c2..2d7f2771a8 100644 --- a/layout.c +++ b/layout.c @@ -67,14 +67,14 @@ void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, } } if (btnNo) { - oledDrawString(1, OLED_HEIGHT - 8, "\x80"); - oledDrawString(fontCharWidth('\x80') + 3, OLED_HEIGHT - 8, btnNo); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\x80') + fontStringWidth(btnNo) + 2, OLED_HEIGHT - 1); + oledDrawString(1, OLED_HEIGHT - 8, "\xfe"); + oledDrawString(fontCharWidth('\xfe') + 3, OLED_HEIGHT - 8, btnNo); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\xfe') + oledStringWidth(btnNo) + 2, OLED_HEIGHT - 1); } if (btnYes) { - oledDrawString(OLED_WIDTH - fontCharWidth('\x81') - 1, OLED_HEIGHT - 8, "\x81"); - oledDrawString(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('\x81') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - fontStringWidth(btnYes) - fontCharWidth('\x81') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth('\xff') - 1, OLED_HEIGHT - 8, "\xff"); + oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } oledRefresh(); } diff --git a/oled.c b/oled.c index 2d90105ed0..00405c0358 100644 --- a/oled.c +++ b/oled.c @@ -189,51 +189,52 @@ void oledClearPixel(int x, int y) void oledDrawChar(int x, int y, char c) { - uint8_t width, *column; + int char_width; + const uint8_t *char_data; if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - if (c < FONT_START) { - c = ' '; - } - - if (c > FONT_END) { - c = '_'; - } - - width = font_data[(int)(c - FONT_START)][0]; - column = (uint8_t *)(font_data[(int)(c - FONT_START)] + 1); + char_width = fontCharWidth(c); + char_data = fontCharData(c); int xoffset, yoffset; - for (xoffset = 0; xoffset < width; xoffset++) { + for (xoffset = 0; xoffset < char_width; xoffset++) { for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { - if (column[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { + if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { oledDrawPixel(x + xoffset, y + yoffset); } } } } +int oledStringWidth(const char *text) { + if (!text) return 0; + int l = 0; + for (; *text; text++) { + l += fontCharWidth(*text) + 1; + } + return l; +} + void oledDrawString(int x, int y, const char* text) { if (!text) return; - const char *c; int l = 0; - for (c = text; *c; c++) { - oledDrawChar(x + l, y, *c); - l += fontCharWidth(*c) + 1; + for (; *text; text++) { + oledDrawChar(x + l, y, *text); + l += fontCharWidth(*text) + 1; } } void oledDrawStringCenter(int y, const char* text) { - int x = ( OLED_WIDTH - fontStringWidth(text) ) / 2; + int x = ( OLED_WIDTH - oledStringWidth(text) ) / 2; oledDrawString(x, y, text); } void oledDrawStringRight(int x, int y, const char* text) { - x -= fontStringWidth(text); + x -= oledStringWidth(text); oledDrawString(x, y, text); } diff --git a/oled.h b/oled.h index 0823b7a1a3..c3b8db2c69 100644 --- a/oled.h +++ b/oled.h @@ -39,6 +39,7 @@ const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); void oledClearPixel(int x, int y); void oledDrawChar(int x, int y, char c); +int oledStringWidth(const char *text); void oledDrawString(int x, int y, const char* text); void oledDrawStringCenter(int y, const char* text); void oledDrawStringRight(int x, int y, const char* text); From 7d3196a057c813eb2725418ae362a8798754010a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 17:42:23 +0100 Subject: [PATCH 0096/1154] correctly skip utf-8 characters --- firmware/layout2.c | 6 +++--- gen/fonts.c | 8 ++++---- gen/fonts/font.png | Bin 1196 -> 1796 bytes gen/fonts/generate.py | 22 +++++++++++----------- layout.c | 12 ++++++------ oled.c | 24 +++++++++++++++++++++--- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 6ea2b0a363..739c233d5c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -252,9 +252,9 @@ void layoutAddress(const char *address) oledDrawString(68, 3 * 9, str[3]); static const char *btnYes = "Continue"; - oledDrawString(OLED_WIDTH - fontCharWidth('\xff') - 1, OLED_HEIGHT - 8, "\xff"); - oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); + oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledRefresh(); } diff --git a/gen/fonts.c b/gen/fonts.c index af0504486c..a82be16142 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -7,7 +7,7 @@ const uint8_t *font_data[256] = { /* 0x03 _ */ (uint8_t *)"\x01\x00", /* 0x04 _ */ (uint8_t *)"\x01\x00", /* 0x05 _ */ (uint8_t *)"\x01\x00", - /* 0x06 _ */ (uint8_t *)"\x01\x00", + /* 0x06 _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", /* 0x07 _ */ (uint8_t *)"\x01\x00", /* 0x08 _ */ (uint8_t *)"\x01\x00", /* 0x09 _ */ (uint8_t *)"\x01\x00", @@ -22,7 +22,7 @@ const uint8_t *font_data[256] = { /* 0x12 _ */ (uint8_t *)"\x01\x00", /* 0x13 _ */ (uint8_t *)"\x01\x00", /* 0x14 _ */ (uint8_t *)"\x01\x00", - /* 0x15 _ */ (uint8_t *)"\x01\x00", + /* 0x15 _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", /* 0x16 _ */ (uint8_t *)"\x01\x00", /* 0x17 _ */ (uint8_t *)"\x01\x00", /* 0x18 _ */ (uint8_t *)"\x01\x00", @@ -255,8 +255,8 @@ const uint8_t *font_data[256] = { /* 0xfb _ */ (uint8_t *)"\x01\x00", /* 0xfc _ */ (uint8_t *)"\x01\x00", /* 0xfd _ */ (uint8_t *)"\x01\x00", - /* 0xfe _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", - /* 0xff _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", + /* 0xfe _ */ (uint8_t *)"\x01\x00", + /* 0xff _ */ (uint8_t *)"\x01\x00", }; int fontCharWidth(char c) { diff --git a/gen/fonts/font.png b/gen/fonts/font.png index 9537b46f12633f8ce0ff830b8a014b8aa4573762..b78c0931689d508291c31dc5e0d75cd6b4321c6d 100644 GIT binary patch literal 1796 zcmV+f2mAPmP)005u}0ssI21g-FT000KdNklyD&F77)a!5>m#cUljI+WEI=I5s`VQec|! zVDMmqwFCdo8bb^z{QY_V`v#+Wob{$2oTs^@yc2HGp8)E^D6rEXyG0r6|7-I$ z+fk{lKZr3GJ1ksVY?Ic1idH$QY8%6~wL2Q{l zTXa4kaaY0}ySM059Hn?ipVfSHS4$aAbl*0?eLv}6clo$I>-x|y+EyJ zwHxabI-Dt%QzQ||l@>bm&5F*KQwFWa9qR8424#nO&58MHE~)0C?9<(vQf2pweEllA zyKS+RUXj&sLs&0t!K>5YgH6&9&?9? z<_U(>jO` z6f1H$V&6uK6>;~h%ww_KTKILz;Ic_|ip3Ir`DosAUwYTPwrFi8Z@*1>EiqbcGA+sK zrsd*KNymu>PUXlM@m@b0mIB4jXRwE!aiudJVL`8eUzMpiS6;^?FN6C1mvKrB%vtMZ z**wpRy>K+>vi(d?bq5j4XF%PLG+m$Uky!giHSUq2->g^$;FsU^JntKnUg<=%Dz_S? zXVP+Q-po;;fp_+s8@4Lx%eVVQueiE-NjA8S9P`NWZa{@94*HlX~8qjLTzXs`CDtUDzBQY znvqBMX{u38W#=SS$T}*|xkdk(N0cm-EHIanWi9p$orl2m7OfAi)p}Mn=#DWrYqFYW zExUWJ^W%Db@-BRT)<*3NzS@Cq>~C;4yqYuBO#UpQPc7i|B%NYiifT?hX3OCe-N4w! zG8M(sJxAr2#j>dVRh5U9ML1H;d9>%z3XDfG+9daz;Wg*EXnpl9t}D0V$Kh5lPL^@& z@syeB`=}V}(n_%BZ29Juz@eU5=s_I7I-pV7j43Ez;Y&i< zWmic;?g@2%2yI*enwIpx-(Bt_xG7egPW&~A|Ng!_A42<;u6IIJrR8gN z9ZRx%y*C$@<(|70f6KY@?vF}dymWT2nT~w9^_;Ie-7HP=s$e=Tw7l>?HBCavLdgQp zCRjT#)`wg1V76!g!2p5*1Oo^L5DZp8$-;xdvk6A`nc9j6vqb|41`rG&7(g(9V6Xy8 z79I?qO)$F8)K)y0EgC>DfM5W@0D=JogB4J+@L=$4g3*1Zw&KBT(Ex%01Oo^L5DXv~ ztbme*2ZLu5jP5hF6%S^M1`rG&7(g(9U;x2j1(Ym27(AO`bf2lMcraTufM5W@0D=Jo z0|*8ypk(2};MoMD`%G=cgV~}11Oo^L5DXv~KrmPVB?}J*&n6h%XKE`R%oYtG7(g(9 mU;x1Yg24(XS$HsbGX4WcKWDo2BnHC(0000SKH9FgH{kj{~jT3 zg`>1ITPwne9m|ukiqnd`Lnjh3Ux!F?>o@FSg*1`WRaFe0tyUcBKT3s_76I{;s%h(@ zkp!(X=^(q|c0i~R1YDgoHO9o+`fA9Ip|$XOW@va0?eT~|+A?{IL$s*Mfv%=Y9*_wP3%7k>}-t=uw7(N4w+6&2CgE^2TjU5 z%57ijsR^2h3~+*seSVSOF{V^4s7{Srnb{t=P;||q_Mg%DHvLH=Z|nr=Yo-o&DF?fd zg66~3EQ;olJx+5l)p|ApAnX}vh173c<2!^zTLf^GRaQxcJtq9X)v$G>uV-Uno;;h9 z{7c3%p0~~fc32DViZ8V2YRyW6d*yB_h%YwzSOkM+lh-kWlFfY*{Lz>glP+!=#!S;t zG?pQb*uF2NF%6fibF_!qg4+;B*uFFKhR>tL#buN>Eh#XmF@tecsCWlB? z3-`RqM7pSm(FL#Qmfp8)za}(lNX#fhc}HO3=IS!rl4%gmb3U4-o-nBMG4xFVWh;A^ z$&sTCU2k*Wu7qkk)J7vPxQL|$oR?r z`QXf*uS{&DP%`rv>5S0RQgSh48iDgsV{$9Sne2K77udN(HMvbeE-79c#ILf-V+w{k ze2f0`B(d>EKSF?)=q*6%g>DMn>Ws^CKRc-7c5k*tlrA&BRXo8UpClYZf1j%eSv*u2O^4q{Ij?&2f>@z}&RQr;h1^i0#}o>2`u2uSBZS zetwkEC^CJKzZ%_CbiIuW2= 32 and idx <= 126 else '_' - print '\t/* 0x%02x %c */ (uint8_t *)"%s",' % (idx, ch , cur) - cur = '' - idx += 1 - continue - val = img.pixel(i, 0) + img.pixel(i, 1) + img.pixel(i, 2) + img.pixel(i, 3) + img.pixel(i, 4) + img.pixel(i, 5) + img.pixel(i, 6) + img.pixel(i, 7) - cur += '\\x%02x' % int(val, 2) +for i in range(256): + x = (i % 16) * 10 + y = (i / 16) * 10 + cur = '' + while img.pixel(x, y) != None: + val = ''.join(img.pixel(x, y + j) for j in range(8)) + x += 1 + cur += '\\x%02x' % int(val, 2) + cur = '\\x%02x' % (len(cur) / 4) + cur + ch = chr(i) if i >= 32 and i <= 126 else '_' + print '\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur) diff --git a/layout.c b/layout.c index 2d7f2771a8..7848b49e46 100644 --- a/layout.c +++ b/layout.c @@ -67,14 +67,14 @@ void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, } } if (btnNo) { - oledDrawString(1, OLED_HEIGHT - 8, "\xfe"); - oledDrawString(fontCharWidth('\xfe') + 3, OLED_HEIGHT - 8, btnNo); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\xfe') + oledStringWidth(btnNo) + 2, OLED_HEIGHT - 1); + oledDrawString(1, OLED_HEIGHT - 8, "\x15"); + oledDrawString(fontCharWidth('\x15') + 3, OLED_HEIGHT - 8, btnNo); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\x15') + oledStringWidth(btnNo) + 2, OLED_HEIGHT - 1); } if (btnYes) { - oledDrawString(OLED_WIDTH - fontCharWidth('\xff') - 1, OLED_HEIGHT - 8, "\xff"); - oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\xff') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); + oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } oledRefresh(); } diff --git a/oled.c b/oled.c index 00405c0358..6b3ef56743 100644 --- a/oled.c +++ b/oled.c @@ -207,11 +207,25 @@ void oledDrawChar(int x, int y, char c) } } +char oledConvertChar(const char c) { + uint8_t a = c; + if (a < 0x80) return c; + // UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description + // bytes 11xxxxxx are first byte of UTF-8 characters + // bytes 10xxxxxx are successive UTF-8 characters + if (a >= 0xC0) return '_'; + return 0; +} + int oledStringWidth(const char *text) { if (!text) return 0; int l = 0; + char c; for (; *text; text++) { - l += fontCharWidth(*text) + 1; + c = oledConvertChar(*text); + if (c) { + l += fontCharWidth(c) + 1; + } } return l; } @@ -220,9 +234,13 @@ void oledDrawString(int x, int y, const char* text) { if (!text) return; int l = 0; + char c; for (; *text; text++) { - oledDrawChar(x + l, y, *text); - l += fontCharWidth(*text) + 1; + c = oledConvertChar(*text); + if (c) { + oledDrawChar(x + l, y, c); + l += fontCharWidth(c) + 1; + } } } From 062a09e646ca82def452eb783a4251d5baf88c2f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 18:12:27 +0100 Subject: [PATCH 0097/1154] make lowercase char 'c' nicer --- gen/fonts.c | 2 +- gen/fonts/font.png | Bin 1796 -> 1800 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/fonts.c b/gen/fonts.c index a82be16142..f32b4a04d4 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -100,7 +100,7 @@ const uint8_t *font_data[256] = { /* 0x60 ` */ (uint8_t *)"\x02\x80\x40", /* 0x61 a */ (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", /* 0x62 b */ (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", - /* 0x63 c */ (uint8_t *)"\x04\x1c\x3e\x22\x22", + /* 0x63 c */ (uint8_t *)"\x05\x1c\x3e\x22\x22\x14", /* 0x64 d */ (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", /* 0x65 e */ (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", /* 0x66 f */ (uint8_t *)"\x03\x7e\xfe\xa0", diff --git a/gen/fonts/font.png b/gen/fonts/font.png index b78c0931689d508291c31dc5e0d75cd6b4321c6d..adb686f6ed7331a8b1d205a49bfaaa1f985beb8f 100644 GIT binary patch literal 1800 zcmd5-`BxH%8g)V2q&J<++^4j35-}$QM~y)ZLrq*TKqSo^9UU3ek_pYo!lkn3Ys7_; z6gOOAbH^ohaH<(1*AyKLm&y^%+)8mF8JoZ2edpZ!o%5Y@?=Sb9``r!jLjw02@72)I z0D5~N&^x>23wCSmFo3soO+!Ps&l}->K1ufB(Nukfjb8e*LS<^y!hHvd?xDg5CFKhv zO*`XmJqYkJ@pYa#fkM5TEt4Kc`)qvdVytc)mL|8s(LT;Idrs5CN2y0dC)jy|6Y!Fy zx&x{|?54KdXz+^eg&!;pV_9&|-|K!lDmf@e0Mbkja<$hfQb+a)|J2lRb>~f-up!Km zCUIosDQ^XRiq>A8$_Ed>l1|bCznD%xdZ|)5(u58Urtk#d_%<*&O?1T$A-152czX&o zA64ebbl|C4K@IM9#_y<7#GL=AY>^Rele=>ZshJ>eN8>TRcbCumJZOc*m zJ4NxSv*MrRJg2oN_GlObeXAv&@u2M7?WaL^6UhDpXSCRx2-d(83Ra?{n;FjvpYVVF zN9Zgi^1|Y#=T>zV*QayeYEw7MIf=AjQ| z)|M+y9Rbo*KFt@@VzA}G2JJsS6s*RJl)%>kNKz%^{Z$-;RXD@wx2t0#?$4iW@Ta3UkT2~))t*+lccRvdBOJRj_DfE4U+HyOF(b#`U zyiRapAz=+m?fF)->F;uBLi3l_WIzzN#LI#X0+SWD4>_@Jf5-b=EL+su|6>2@gM*)k z&Cqi9*;n#5G&=>+d84Vl{pY%T^PHX!cSha7It8&NbyKyqAYVbBK&s46(QjGJJT5M( z#Sf2#nJl-a@MNA$>eV|jIX%A?)=AY&KlIhOpGjXix^c1yLZe+i20jK!S#%6O>1AOK zHe)Ro6Ox@3gRv?thj6^>%JM9mNsYldP-0Z;VGu9>B15m2bG|CXc1nVjxNZ%$FEn9@ zPRU!O7sS8Hn_OPex%`mc<-AYd4IHU9)uB9@QD(B;23mEI3THmq%EDH0V2N`ofAY^n z^2+sosya%q=9Up8?(gAi*p7Y3G(Tn^8RvTE0epWe!!eX)niEV7GZRKCoInP<-mJ7Q z%#hM#prUl_A#6F>KZFlv>evkZ8zql&{rz7TIDryfSDPy1HveeJ)Dk{TY#3?c%($GG!tcuR-mPkyWl6)#Hh=MEjoX zd6rx=VSTncP2bKENP8>Ikj-t|6E1-C_LyDP!H}h5k6`7~gk)~dVOm^s?+76Jt&PHU zDp~7ZCj%;{_gF?OTbr%UZJy6MS#~UnaPDurxWWhwj>9w+HjYpvVoNYW#U08la7`tm zux~L97>6vy_o0x-oOwNT1~<&J7yP{MbXjC+`Pha?Tb<+0IAW{|-O-Nd9dt5<(=zT-wDQ~6T z2mm{kKkmq^^!^6_4SupW3CQ%Km=nzHPy|CE~HZdM-uyhveC0hDK1Q%_mB>+vkm%F)J;UH5U6rEXyG0r6|7-I$+fk{lKZr3GJ1ksVY?Ic1idH$QY8%6~wL2Q< z!4@5=sZte9`G2eaj_6uc`J|MLgVA?1$rkO2Z*!9NJ*1SxTm78cn)T3%vA4OWZYstz z(1R^Wj-Dx_ms~d8Ig7F%>aAaPg19lN*aQyisuN1xSvbXQ9mPITWk z!F@mJUw8SqJ?r|=FWOg?=c&|pp}tm(XK{Ajy+!AqEq_9urtfylwTPs2m9<5C>3bNB z6grwmS3><{MEa%|%35rb-n03h(hBB&WrupriTP?Sspg{W)7_ds&0t!K>5YgH6&9&?9?<_U(>jO`6f1H$V&6uK6>;~h%ww_KTKILz;Ic_| zihsotefenKb6Zax5Pf5p#22SP38S!2}8g4=Ok6gIx5e(MgN&c zlq{4iFqe{LE%pqZhrsj}tq-o%dVf|m=#DWrYqFYWExUWJ^W%Db@-BRT)<*3NzS@Cq z>~C;4yqYuBO#UpQPc7i|B%NYiifT?hX3OCe-N4w!G8M(sJxAr2#j>dVRh5U9ML1H; zd9>%z3XDfG+9daz;Wg*EXnpl9t}D0V$Kh5lPL^@&@syeB`=}V}(n_%BY=8OYmB68% zot0ugeE)d;^3q4zV}6L;LggzQLhRH^mQbVep7rkv zYf)G7_gtHeTR(#>D#_8b&wp}Gcl3wWM&#wSkvla5%a^eFPZyqb+r^QMnCR{ab$$qK zTmhPv^uOO-?jyJZYjqtIxV!k@IN(8LdinO0?#H`J22LVTYvFjwrBvs0D=Jo z0|*8X3|2tN!h^xH2}bvs+KLCWMFR*15DXv~Krnz{umVaJ9t@sMFuKpwRy>$38bC0B zU;x1Yf&m1B6;QJ9VDM~$(S4@2;=ydu0D=Jo0|*8X3?LY+fRcp=gJ% Date: Fri, 13 Feb 2015 18:21:20 +0100 Subject: [PATCH 0098/1154] check gpg key in Dockerfile --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 17a3c088b1..e77b0acd2d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,9 @@ FROM ubuntu:14.04 # add and update package repositories -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB && echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update +RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB +RUN gpg --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --fingerprint FE324A81C208C89497EFC6246D1D8367A3421AFB +RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update # install build tools and dependencies From 60bb2fe2b1605d56672ed2b0e96b5caea4cc9bb9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 20:49:53 +0100 Subject: [PATCH 0099/1154] use Knuth shuffles --- firmware/pinmatrix.c | 12 ++---------- firmware/recovery.c | 13 +++---------- rng.c | 19 +++++++++++++++++++ rng.h | 2 ++ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 8212972443..73ae3b4052 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -49,20 +49,12 @@ void pinmatrix_draw(const char *text) void pinmatrix_start(const char *text) { - int i, j, k; - char t; - + int i; for (i = 0; i < 9; i++) { pinmatrix_perm[i] = '1' + i; } pinmatrix_perm[9] = 0; - for (i = 0; i < 10000; i++) { - j = random32() % 9; - k = random32() % 9; - t = pinmatrix_perm[j]; - pinmatrix_perm[j] = pinmatrix_perm[k]; - pinmatrix_perm[k] = t; - } + random_permute(pinmatrix_perm, 9); pinmatrix_draw(text); } diff --git a/firmware/recovery.c b/firmware/recovery.c index 1aa6d36e89..c53a42b845 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -40,7 +40,7 @@ void next_word(void) { word_pos = word_order[word_index]; if (word_pos == 0) { const char **wl = mnemonic_wordlist(); - strlcpy(fake_word, wl[random32() & 0x7FF], sizeof(fake_word)); + strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); } else { fake_word[0] = 0; @@ -89,21 +89,14 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_setLanguage(language); storage_setLabel(label); - uint32_t i, j, k; - char t; + uint32_t i; for (i = 0; i < word_count; i++) { word_order[i] = i + 1; } for (i = word_count; i < 24; i++) { word_order[i] = 0; } - for (i = 0; i < 10000; i++) { - j = random32() % 24; - k = random32() % 24; - t = word_order[j]; - word_order[j] = word_order[k]; - word_order[k] = t; - } + random_permute(word_order, 24); awaiting_word = true; word_index = 0; next_word(); diff --git a/rng.c b/rng.c index 0f7437a741..39aea97710 100644 --- a/rng.c +++ b/rng.c @@ -35,6 +35,13 @@ uint32_t random32(void) return new; } +uint32_t random_uniform(uint32_t n) +{ + uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); + while ((x = random32()) >= max); + return x / (max / n); +} + void random_buffer(uint8_t *buf, size_t len) { size_t i; @@ -46,3 +53,15 @@ void random_buffer(uint8_t *buf, size_t len) buf[i] = (r >> ((i % 4) * 8)) & 0xFF; } } + +void random_permute(char *str, size_t len) +{ + int i, j; + char t; + for (i = len - 1; i >= 1; i--) { + j = random_uniform(i + 1); + t = str[j]; + str[j] = str[i]; + str[i] = t; + } +} diff --git a/rng.h b/rng.h index 9fbe2bea29..3e25c0eedd 100644 --- a/rng.h +++ b/rng.h @@ -24,6 +24,8 @@ #include uint32_t random32(void); +uint32_t random_uniform(uint32_t n); void random_buffer(uint8_t *buf, size_t len); +void random_permute(char *buf, size_t len); #endif From 873c0ec11acad53e9133fc25c418b6be038fc700 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 13 Feb 2015 20:59:47 +0100 Subject: [PATCH 0100/1154] one more edit of 'c' letter in font --- gen/fonts.c | 2 +- gen/fonts/font.png | Bin 1800 -> 1795 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/fonts.c b/gen/fonts.c index f32b4a04d4..5d2787e2b3 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -100,7 +100,7 @@ const uint8_t *font_data[256] = { /* 0x60 ` */ (uint8_t *)"\x02\x80\x40", /* 0x61 a */ (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", /* 0x62 b */ (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", - /* 0x63 c */ (uint8_t *)"\x05\x1c\x3e\x22\x22\x14", + /* 0x63 c */ (uint8_t *)"\x05\x1c\x3e\x22\x36\x14", /* 0x64 d */ (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", /* 0x65 e */ (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", /* 0x66 f */ (uint8_t *)"\x03\x7e\xfe\xa0", diff --git a/gen/fonts/font.png b/gen/fonts/font.png index adb686f6ed7331a8b1d205a49bfaaa1f985beb8f..a3d26a98eb7fa4eb7a3937783f9dad53dca2e414 100644 GIT binary patch delta 1748 zcmV;_1}pi94ucMmBmv5iB_n?k2Wb*W8%#OpDNRk}>7v#pQcC&rznAUvFRb%)f25Rh z&J%bf!La*4f>TNGLX<2#7~Gm*>A-19sa^2%ConZH$i)SDpY{E_RT=C5w&gYJUa8PO zi9T0vSZQ0mCNKX~t+H3mYYc5$PjsLMTXd+dN>w$LulgOkYf9 zlC-@;&RM+GFR5)=cg=qo`!(0pO+|kW^k7Spqesf~saW30taN>^E1v=`rEbfnPHJ-RZrPe$Z#dZDbda0gl+iL6Qe%1ST+loG~G@W(N zZO^OvoI=al;vl3gM8Cs(+bUUD?mJooU616FB#ZSsnw#HU>{eCm)Nr%8Gb-?a|!f22RUOIql#Wc;n0&!e7M^t+WN>4fByg0~*b zCv*f;te{9Dk}EBA=!X?IpNDi>_j_u;GdL(a)N@XZS9eNvC#6q!>q?dG8TtCv?(VY1 zR(eJ@w#Y*N6>=g9Y8P$pvqMCS zY=%_CTK{i4N!huvwL#DTttxKaW*jJ4C|TesN>*jzF>6Lz722y+X*DXMRhfj2R#cN> zMJY#YuhC*f+N_o3UaYiMeqAy+uTq_Av4k%lE${40@49WP)^76l+mzR`M{5nHC0Siv zImc7d<3xXhpmG%4@t!{#mI6iR8XTeLxYC)3u%KtaugX+{GtV)|^FjChmocOUX4Jfy zSL<2zE*uRyEuQJ2b`UXtI^-d<39rIXOA!fKQr zNlV-EvOt9zN)}2Mxb=>29nG~GwY*?QT9j~wPwwY zp){&qTx8Xy}nyc9%&)c&q{4*x%0QyWHnwj zTQ#GI?$cGHy2{QVRmj?_$hpP%nMaf?lq~QpCCgguIXMr3X{$cC)@rM2&;xz$)?{_h zTDtGt<|p*}9c+oM+3V4pvomt(t(nbydN4^24G_IJsYS&o|C5-{cw__pYP+j1^&Su!|m2 z66>y0@qHWYC;I4R=j9w9tZq$K*D8M3H#vUz{_*_jrN=pS;^)Qds**}(Ci(Ffb?1Nf z`9ZZO9aZf$G)+RuLdgPm#%ow0-Fa+zK)5qnSJxc8aCFWdwi0*ShmxAsga@CvfA)PJ z^`NcU%dV14jjwPBu~WY~6>3y@XZ^dvTGf@}ch(x&Mb}`T-lWq$%Q@YnKeRSHArX}% zLCwJOB`p8x!cmVsP~~uEe#f<)jx2vb(~|!8yURX;eR9M#)rPXq+vkdW2<`muGrJXk%eiv*Mwb8EePx{2=q000023wCSmFo3soO+!Ps&l}->K1ufB(Nukfjb8e*LS<^y!hHvd?xDg5CFKhv zO*`XmJqYkJ@pYa#fkM5TEt4Kc`)qvdVytc)mL|8s(LT;Idrs5CN2y0dC)jy|6Y!Fy zx&x{|?54KdXz+^eg&!;pV_9&|-|K!lDmf@e0Mbkja<$hfQb+a)|J2lRb>~f-up!Km zCUIosDQ^XRiq>A8$_Ed>l1|bCznD%xdZ|)5(u58Urtk#d_%<*&O?1T$A-152czX&o zA64ebbl|C4K@IM9#_y<7#GL=AY>^Rele=>ZshJ>eN8>TRcbCumJZOc*m zJ4NxSv*MrRJg2oN_GlObeXAv&@u2M7?WaL^6UhDpXSCRx2-d(83Ra?{n;FjvpYVVF zN9Zgi^1|Y#=T>zV*QayeYEw7MIf=AjQ| z)|M+y9Rbo*KFt@@VzA}G2JJsS6s*RJl)%>kNKz%^{Z$-;RXD@wx2t0#?$4iW@Ta3UkT2~))t*+lccRvdBOJRj_DfE4U+HyOF(b#`U zyiRapAz=+m?fF)->F;uBLi3l_WIzzN#LI#X0+SWD4>_@Jf5-b=EL+su|6>2@gM*)k z&Cqi9*;n#5G&=>+d84Vl{pY%T^PHX!cSha7It8&NbyKyqAYVbBK&s46(QjGJJT5M( z#Sf2#nJl-a@MNA$>eV|jIX%A?)=AY&KlIhOpGjXix^c1yLZe+i20jK!S#%6O>1AOK zHe)Ro6Ox@3gRv?thj6^>%JM9mNsYldP-0Z;VGu9>B15m2bG|CXc1nVjxNZ%$FEn9@ zPRU!O7sS8Hn_OPex%`mc<-AYd4IHU9)uB9@QD(B;23mEI3THmq%EDH0V2N`ofAY^n z^2+sosya%q=9Up8?(gAi*p7Y3G(Tn^8RvTE0epWe!!eX)niEV7GZRKCoInP<-mJ7Q z%#hM#prUl_A#6F>KZFlv>evkZ8zql&{rz7TIDryfSDPy1HveeJ)Dk{TY#3?c%($GG!tcuR-mPkyWl6)#Hh=MEjoX zd6rx=VSTncP2bKENP8>Ikj-t|6E1-C_LyDP!H}h5k6`7~gk)~dVOm^s?+76Jt&PHU zDp~7ZCj%;{_gF?OTbr%UZJy6MS#~UnaPDurxWWhwj>9w+HjYpvVoNYW#U08la7`tm zux~L97>6vy_o0x-oOwNT1~<&J7yP{MbXjC+`Pha?Tb<+0IAW{|-O-Nd9dt5<(=zT-wDQ~6T z2mm{kKkmq^^!^6_4SupW3CQ%Km=nzHPy|CE~HZdM-uyhveC0hDK1Q%_mB>+vkm%F)J;UH5U Date: Sat, 14 Feb 2015 11:50:12 +0100 Subject: [PATCH 0101/1154] Disable assertion checking The trezor-crypto has some assertions, which are enabled unless compiled with -DNDEBUG. This does not make much sense for the Trezor as could not write the assertion errors to stderr anyway. This simple patch removes the dependency to assert, printf, etc. It saves about 11kb flash and 2.2kb ram. --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 965c5388be..10c9d23274 100644 --- a/Makefile.include +++ b/Makefile.include @@ -9,7 +9,7 @@ OBJDUMP = $(PREFIX)objdump FLASH = st-flash OPENOCD = openocd -OPTFLAGS = -Os -g +OPTFLAGS = -Os -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ -W \ From 07c8c4963a616b06774eb6b80e39d7f863bd62ef Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 14 Feb 2015 12:40:32 +0100 Subject: [PATCH 0102/1154] use const char * const * for wordlist --- firmware/recovery.c | 4 ++-- trezor-crypto | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index c53a42b845..48213e0d6e 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -39,7 +39,7 @@ static char words[24][12]; void next_word(void) { word_pos = word_order[word_index]; if (word_pos == 0) { - const char **wl = mnemonic_wordlist(); + const char * const *wl = mnemonic_wordlist(); strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); } else { @@ -119,7 +119,7 @@ void recovery_word(const char *word) } } else { // real word if (enforce_wordlist) { // check if word is valid - const char **wl = mnemonic_wordlist(); + const char * const *wl = mnemonic_wordlist(); bool found = false; while (*wl) { if (strcmp(word, *wl) == 0) { diff --git a/trezor-crypto b/trezor-crypto index f4fe7c9aa5..d814f58a3b 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit f4fe7c9aa5e85ec3898ce07a5af5fc99bb8f5de4 +Subproject commit d814f58a3b027b154ae77bdf236a0cd08a421107 From 94531f264e9f386bef0d6eaa7c925e429f47fb51 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 15 Feb 2015 20:47:53 +0100 Subject: [PATCH 0103/1154] speed up public ckd (used in multisig) --- firmware/Makefile | 1 + firmware/crypto.c | 2 +- gen/fonts.c | 2 +- gen/fonts.h | 2 +- layout.c | 16 ++++++++++++++-- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 74a642814e..193738731a 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -50,6 +50,7 @@ include ../Makefile.include CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DQR_MAX_VERSION=0 +CFLAGS += -DUSE_PUBKEY_VALIDATE=0 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' diff --git a/firmware/crypto.c b/firmware/crypto.c index 7cd4fd9f98..24c2998fa1 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -301,11 +301,11 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { + static const HDNodePathType *ptr[15], *swap; const uint32_t n = multisig->pubkeys_count; if (n > 15) { return 0; } - const HDNodePathType *ptr[n], *swap; uint32_t i, j; // check sanity for (i = 0; i < n; i++) { diff --git a/gen/fonts.c b/gen/fonts.c index 5d2787e2b3..a9f23df755 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -1,6 +1,6 @@ #include "fonts.h" -const uint8_t *font_data[256] = { +const uint8_t * const font_data[256] = { /* 0x00 _ */ (uint8_t *)"\x01\x00", /* 0x01 _ */ (uint8_t *)"\x01\x00", /* 0x02 _ */ (uint8_t *)"\x01\x00", diff --git a/gen/fonts.h b/gen/fonts.h index ecb5195285..43ca21a6fb 100644 --- a/gen/fonts.h +++ b/gen/fonts.h @@ -5,7 +5,7 @@ #define FONT_HEIGHT 8 -extern const uint8_t *font_data[256]; +extern const uint8_t * const font_data[256]; int fontCharWidth(char c); const uint8_t *fontCharData(char c); diff --git a/layout.c b/layout.c index 7848b49e46..cdcc034901 100644 --- a/layout.c +++ b/layout.c @@ -82,8 +82,20 @@ void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, void layoutProgressUpdate(bool refresh) { static uint8_t step = 0; - const BITMAP *bmp_gears[4] = { &bmp_gears0, &bmp_gears1, &bmp_gears2, &bmp_gears3 }; - oledDrawBitmap(40, 0, bmp_gears[step]); + switch (step) { + case 0: + oledDrawBitmap(40, 0, &bmp_gears0); + break; + case 1: + oledDrawBitmap(40, 0, &bmp_gears1); + break; + case 2: + oledDrawBitmap(40, 0, &bmp_gears2); + break; + case 3: + oledDrawBitmap(40, 0, &bmp_gears3); + break; + } step = (step + 1) % 4; if (refresh) { oledRefresh(); From f2f50aa1886429aaeab5aa88e8c6e106ac5224b1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Feb 2015 13:48:24 +0100 Subject: [PATCH 0104/1154] bump version to 1.3.1 --- firmware-docker-build.sh | 2 +- firmware/storage.c | 5 ++++- firmware/trezor.h | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 375bc7c90d..cb4f524f71 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,6 +1,6 @@ #!/bin/bash IMAGETAG=trezor-mcu-build -FIRMWARETAG=v1.3.0 +FIRMWARETAG=v1.3.1 docker build -t $IMAGETAG . docker run -t -v $(pwd):/output $IMAGETAG /bin/sh -c "\ diff --git a/firmware/storage.c b/firmware/storage.c index bc9aaea8fe..d540e7f184 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -63,7 +63,7 @@ static char sessionPassphrase[51]; 0x0010 | ? | Storage structure */ -#define STORAGE_VERSION 2 +#define STORAGE_VERSION 3 void storage_from_flash(uint32_t version) { @@ -74,6 +74,9 @@ void storage_from_flash(uint32_t version) case 2: // copy memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; + case 3: // copy + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + break; } storage.version = STORAGE_VERSION; } diff --git a/firmware/trezor.h b/firmware/trezor.h index 9ef2e81dd7..0a368c6627 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) From 2f5e5203458465474e8f572290e64f4e9db68532 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Feb 2015 18:30:54 +0100 Subject: [PATCH 0105/1154] add description to layoutAddress --- firmware/crypto.c | 3 +++ firmware/fsm.c | 14 +++++++++++++- firmware/layout2.c | 13 ++++++++----- firmware/layout2.h | 2 +- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 24c2998fa1..d0f9f48357 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -308,6 +308,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t } uint32_t i, j; // check sanity + if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; for (i = 0; i < n; i++) { ptr[i] = &(multisig->pubkeys[i]); if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; @@ -326,6 +327,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t // hash sorted nodes SHA256_CTX ctx; sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); for (i = 0; i < n; i++) { sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); @@ -333,6 +335,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); } + sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); sha256_Final(hash, &ctx); layoutProgressUpdate(true); return 1; diff --git a/firmware/fsm.c b/firmware/fsm.c index 1f88c9d84f..6a4e07d711 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -526,7 +526,19 @@ void fsm_msgGetAddress(GetAddress *msg) } if (msg->has_show_display && msg->show_display) { - layoutAddress(resp->address); + char desc[16]; + if (msg->has_multisig) { + strlcpy(desc, "Msig __ of __:", sizeof(desc)); + const uint32_t m = msg->multisig.m; + const uint32_t n = msg->multisig.pubkeys_count; + desc[5] = (m < 10) ? ' ': ('0' + (m / 10)); + desc[6] = '0' + (m % 10); + desc[11] = (n < 10) ? ' ': ('0' + (n / 10)); + desc[12] = '0' + (n % 10); + } else { + strlcpy(desc, "Address:", sizeof(desc)); + } + layoutAddress(resp->address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); layoutHome(); diff --git a/firmware/layout2.c b/firmware/layout2.c index 739c233d5c..73819d0a2a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -220,7 +220,7 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutAddress(const char *address) +void layoutAddress(const char *address, const char *desc) { oledSwipeLeft(); layoutLast = layoutAddress; @@ -246,10 +246,13 @@ void layoutAddress(const char *address) const char **str = split_message((const uint8_t *)address, strlen(address), 9); - oledDrawString(68, 0 * 9, str[0]); - oledDrawString(68, 1 * 9, str[1]); - oledDrawString(68, 2 * 9, str[2]); - oledDrawString(68, 3 * 9, str[3]); + if (desc) { + oledDrawString(68, 0 * 9, desc); + } + oledDrawString(68, 1 * 9 + 4, str[0]); + oledDrawString(68, 2 * 9 + 4, str[1]); + oledDrawString(68, 3 * 9 + 4, str[2]); + oledDrawString(68, 4 * 9 + 4, str[3]); static const char *btnYes = "Continue"; oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); diff --git a/firmware/layout2.h b/firmware/layout2.h index bd9be4cb84..b109863079 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -35,6 +35,6 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); -void layoutAddress(const char *address); +void layoutAddress(const char *address, const char *desc); #endif From ad6fc7b5a76bfa2dc5667282e8831fb29de342f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 20 Feb 2015 19:01:45 +0100 Subject: [PATCH 0106/1154] update protobuf --- firmware/protob/messages.options | 7 ++++ firmware/protob/messages.pb.c | 16 ++++++++- firmware/protob/messages.pb.h | 59 +++++++++++++++++++++++++++++--- firmware/protob/types.options | 6 ++++ firmware/protob/types.pb.c | 13 ++++++- firmware/protob/types.pb.h | 26 ++++++++++++++ trezor-common | 2 +- 7 files changed, 121 insertions(+), 8 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 64a5431f29..cc66922d13 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -86,6 +86,13 @@ EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 +SignIdentity.challenge_hidden max_size:64 +SignIdentity.challenge_visual max_size:64 + +SignedIdentity.address max_size:36 +SignedIdentity.public_key max_size:33 +SignedIdentity.signature max_size:65 + # not used in firmware SimpleSignTx.inputs max_count:0 SimpleSignTx.outputs max_count:0 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 874ebd04f1..3e4e41bf27 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -298,6 +298,20 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; +const pb_field_t SignIdentity_fields[4] = { + PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_visual, challenge_hidden, 0), + PB_LAST_FIELD +}; + +const pb_field_t SignedIdentity_fields[4] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, SignedIdentity, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignedIdentity, public_key, address, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, SignedIdentity, signature, public_key, 0), + PB_LAST_FIELD +}; + const pb_field_t FirmwareErase_fields[1] = { PB_LAST_FIELD }; @@ -351,7 +365,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index cec27de26e..50b2fd867e 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -35,7 +35,6 @@ typedef enum _MessageType { MessageType_MessageType_TxRequest = 21, MessageType_MessageType_TxAck = 22, MessageType_MessageType_CipherKeyValue = 23, - MessageType_MessageType_CipheredKeyValue = 48, MessageType_MessageType_ClearSession = 24, MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, @@ -47,10 +46,6 @@ typedef enum _MessageType { MessageType_MessageType_SignMessage = 38, MessageType_MessageType_VerifyMessage = 39, MessageType_MessageType_MessageSignature = 40, - MessageType_MessageType_EncryptMessage = 49, - MessageType_MessageType_EncryptedMessage = 50, - MessageType_MessageType_DecryptMessage = 51, - MessageType_MessageType_DecryptedMessage = 52, MessageType_MessageType_PassphraseRequest = 41, MessageType_MessageType_PassphraseAck = 42, MessageType_MessageType_EstimateTxSize = 43, @@ -58,6 +53,13 @@ typedef enum _MessageType { MessageType_MessageType_RecoveryDevice = 45, MessageType_MessageType_WordRequest = 46, MessageType_MessageType_WordAck = 47, + MessageType_MessageType_CipheredKeyValue = 48, + MessageType_MessageType_EncryptMessage = 49, + MessageType_MessageType_EncryptedMessage = 50, + MessageType_MessageType_DecryptMessage = 51, + MessageType_MessageType_DecryptedMessage = 52, + MessageType_MessageType_SignIdentity = 53, + MessageType_MessageType_SignedIdentity = 54, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, @@ -497,6 +499,20 @@ typedef struct _ResetDevice { char label[33]; } ResetDevice; +typedef struct { + size_t size; + uint8_t bytes[64]; +} SignIdentity_challenge_hidden_t; + +typedef struct _SignIdentity { + bool has_identity; + IdentityType identity; + bool has_challenge_hidden; + SignIdentity_challenge_hidden_t challenge_hidden; + bool has_challenge_visual; + char challenge_visual[64]; +} SignIdentity; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -517,6 +533,25 @@ typedef struct _SignTx { char coin_name[17]; } SignTx; +typedef struct { + size_t size; + uint8_t bytes[33]; +} SignedIdentity_public_key_t; + +typedef struct { + size_t size; + uint8_t bytes[65]; +} SignedIdentity_signature_t; + +typedef struct _SignedIdentity { + bool has_address; + char address[36]; + bool has_public_key; + SignedIdentity_public_key_t public_key; + bool has_signature; + SignedIdentity_signature_t signature; +} SignedIdentity; + typedef struct _SimpleSignTx { size_t inputs_count; TxInputType inputs[0]; @@ -632,6 +667,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin"} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} +#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} +#define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_default {0} #define FirmwareUpload_init_default {{0, {0}}} #define DebugLinkDecision_init_default {0} @@ -683,6 +720,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} +#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} +#define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_zero {0} #define FirmwareUpload_init_zero {{0, {0}}} #define DebugLinkDecision_init_zero {0} @@ -794,12 +833,18 @@ extern const char SimpleSignTx_coin_name_default[17]; #define ResetDevice_pin_protection_tag 4 #define ResetDevice_language_tag 5 #define ResetDevice_label_tag 6 +#define SignIdentity_identity_tag 1 +#define SignIdentity_challenge_hidden_tag 2 +#define SignIdentity_challenge_visual_tag 3 #define SignMessage_address_n_tag 1 #define SignMessage_message_tag 2 #define SignMessage_coin_name_tag 3 #define SignTx_outputs_count_tag 1 #define SignTx_inputs_count_tag 2 #define SignTx_coin_name_tag 3 +#define SignedIdentity_address_tag 1 +#define SignedIdentity_public_key_tag 2 +#define SignedIdentity_signature_tag 3 #define SimpleSignTx_inputs_tag 1 #define SimpleSignTx_outputs_tag 2 #define SimpleSignTx_transactions_tag 3 @@ -860,6 +905,8 @@ extern const pb_field_t SignTx_fields[4]; extern const pb_field_t SimpleSignTx_fields[5]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; +extern const pb_field_t SignIdentity_fields[4]; +extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t FirmwareErase_fields[1]; extern const pb_field_t FirmwareUpload_fields[2]; extern const pb_field_t DebugLinkDecision_fields[2]; @@ -913,6 +960,8 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) +#define SignIdentity_size (138 + IdentityType_size) +#define SignedIdentity_size 140 #define FirmwareErase_size 0 #define FirmwareUpload_size 2 #define DebugLinkDecision_size 2 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index c1a4c536ca..9fa6c9d860 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -28,3 +28,9 @@ TxRequestSerializedType.serialized_tx max_size:2048 MultisigRedeemScriptType.pubkeys max_count:15 MultisigRedeemScriptType.signatures max_count:15 max_size:73 + +IdentityType.proto max_size:9 +IdentityType.user max_size:64 +IdentityType.host max_size:64 +IdentityType.port max_size:6 +IdentityType.path max_size:256 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 8dca6cfe04..c45448f314 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -7,6 +7,7 @@ const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_p2sh_default = 5u; const uint32_t TxInputType_sequence_default = 4294967295u; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; +const uint32_t IdentityType_index_default = 0u; const pb_field_t HDNodeType_fields[7] = { @@ -92,6 +93,16 @@ const pb_field_t TxRequestSerializedType_fields[4] = { PB_LAST_FIELD }; +const pb_field_t IdentityType_fields[7] = { + PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, IdentityType, proto, proto, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, IdentityType, user, proto, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, IdentityType, host, user, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, IdentityType, port, host, 0), + PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, IdentityType, path, port, 0), + PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, IdentityType, index, path, &IdentityType_index_default), + PB_LAST_FIELD +}; + typedef struct { bool wire_in; } wire_in_struct; @@ -154,7 +165,7 @@ const pb_extension_type_t wire_debug_out = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType) +STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType_IdentityType) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 177df7b9ee..f31812d194 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -102,6 +102,21 @@ typedef struct _HDNodeType { HDNodeType_public_key_t public_key; } HDNodeType; +typedef struct _IdentityType { + bool has_proto; + char proto[9]; + bool has_user; + char user[64]; + bool has_host; + char host[64]; + bool has_port; + char port[6]; + bool has_path; + char path[256]; + bool has_index; + uint32_t index; +} IdentityType; + typedef struct { size_t size; uint8_t bytes[520]; @@ -234,6 +249,7 @@ extern const uint32_t CoinType_address_type_default; extern const uint32_t CoinType_address_type_p2sh_default; extern const uint32_t TxInputType_sequence_default; extern const InputScriptType TxInputType_script_type_default; +extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} @@ -246,6 +262,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} #define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} +#define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0} @@ -256,6 +273,7 @@ extern const InputScriptType TxInputType_script_type_default; #define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} #define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} #define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}} +#define IdentityType_init_zero {false, "", false, "", false, "", false, "", false, "", false, 0} /* Field tags (for use in manual encoding/decoding) */ #define CoinType_coin_name_tag 1 @@ -269,6 +287,12 @@ extern const InputScriptType TxInputType_script_type_default; #define HDNodeType_chain_code_tag 4 #define HDNodeType_private_key_tag 5 #define HDNodeType_public_key_tag 6 +#define IdentityType_proto_tag 1 +#define IdentityType_user_tag 2 +#define IdentityType_host_tag 3 +#define IdentityType_port_tag 4 +#define IdentityType_path_tag 5 +#define IdentityType_index_tag 6 #define TxOutputBinType_amount_tag 1 #define TxOutputBinType_script_pubkey_tag 2 #define TxRequestDetailsType_request_index_tag 1 @@ -317,6 +341,7 @@ extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TxRequestDetailsType_fields[3]; extern const pb_field_t TxRequestSerializedType_fields[4]; +extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 @@ -329,6 +354,7 @@ extern const pb_field_t TxRequestSerializedType_fields[4]; #define TransactionType_size 9993 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 +#define IdentityType_size 416 #ifdef __cplusplus } /* extern "C" */ diff --git a/trezor-common b/trezor-common index 201b66a559..69d476a3ba 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 201b66a559567031f74621615884946c8bf1e837 +Subproject commit 69d476a3ba10c40209dd26789876b265cf03f384 From 286ee0525cc50070ff6212a2882fc44862044eb3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 22 Feb 2015 15:19:13 +0100 Subject: [PATCH 0107/1154] PIN handling - constant time. This diff contains three changes. 1. Make timing isPinCorrect independent of storage.pin, to avoid timing attacks 2. Only update failed PIN counter if the user entered a PIN. Of course, the fail counter is still incremented, before the PIN is checked. 3. Don't cache the PIN, but just the fact that the PIN was entered. The cache should be in sync with storage.pin in any case. --- firmware/protect.c | 6 +++--- firmware/storage.c | 25 ++++++++++++++++++------- firmware/storage.h | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index cf1dbddf77..d3d77a2344 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -156,16 +156,16 @@ bool protectPin(bool use_cached) delay(10000000); } } - storage_increasePinFails(); - bool increase_failed = (fails >= storage_getPinFails()); const char *pin; pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); if (!pin) { fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); return false; } + storage_increasePinFails(); + bool increase_failed = (fails >= storage_getPinFails()); if (storage_isPinCorrect(pin) && !increase_failed) { - session_cachePin(pin); + session_cachePin(); storage_resetPinFails(); return true; } else { diff --git a/firmware/storage.c b/firmware/storage.c index d540e7f184..44494610c4 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -48,7 +48,6 @@ static bool sessionRootNodeCached; static HDNode sessionRootNode; static bool sessionPinCached; -static char sessionPin[17]; static bool sessionPassphraseCached; static char sessionPassphrase[51]; @@ -122,7 +121,7 @@ void session_clear(void) { sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); - sessionPinCached = false; memset(&sessionPin, 0, sizeof(sessionPin)); + sessionPinCached = false; } static uint8_t meta_backup[FLASH_META_LEN]; @@ -306,14 +305,27 @@ const uint8_t *storage_getHomescreen(void) return (storage.has_homescreen && storage.homescreen.size == 1024) ? storage.homescreen.bytes : 0; } +/* Check whether pin matches storage. The pin must be a null-terminated + * string with at most 9 characters. + */ bool storage_isPinCorrect(const char *pin) { - return strcmp(storage.pin, pin) == 0; + /* The execution time of the following code only depends on the + * (public) input. This avoids timing attacks. + */ + char diff = 0; + uint32_t i = 0; + while (pin[i]) { + diff |= storage.pin[i] - pin[i]; + i++; + } + diff |= storage.pin[i]; + return diff == 0; } bool storage_hasPin(void) { - return storage.has_pin && strlen(storage.pin) > 0; + return storage.has_pin && storage.pin[0] != 0; } void storage_setPin(const char *pin) @@ -340,15 +352,14 @@ bool session_isPassphraseCached(void) return sessionPassphraseCached; } -void session_cachePin(const char *pin) +void session_cachePin(void) { - strlcpy(sessionPin, pin, sizeof(sessionPin)); sessionPinCached = true; } bool session_isPinCached(void) { - return sessionPinCached && strcmp(sessionPin, storage.pin) == 0; + return sessionPinCached; } void storage_resetPinFails(void) diff --git a/firmware/storage.h b/firmware/storage.h index 828dea7b2f..2b7b9b4e75 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -52,7 +52,7 @@ bool session_isPassphraseCached(void); bool storage_isPinCorrect(const char *pin); bool storage_hasPin(void); void storage_setPin(const char *pin); -void session_cachePin(const char *pin); +void session_cachePin(void); bool session_isPinCached(void); void storage_resetPinFails(void); void storage_increasePinFails(void); From 5d8135be1a977bc90b04396b9651a372cc019d4b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 25 Feb 2015 16:23:24 +0100 Subject: [PATCH 0108/1154] Faster signing, smoother progressbar. Most time in signing transaction on the Trezor side is spent in layoutProgress. This patch reduces the calls to this functions. We also compute the progress differently, reserving 50 % for downloading input transactions and 50 % for the signing process. This gives a smoother experience if the input transactions are large. --- firmware/signing.c | 52 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 045ed1255a..3224808e07 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -51,10 +51,15 @@ static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; static uint64_t to_spend, spending, change_spend; const uint32_t version = 1; const uint32_t lock_time = 0; -static uint32_t progress, progress_total; +static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; +/* progress_step/meta_step are fixed point numbers, giving the + * progress per input in permille with these many additional bits. + */ +#define PROGRESS_PRECISION 16 + /* Workflow of streamed signing @@ -117,7 +122,6 @@ foreach O (idx1): void send_req_1_input(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; @@ -129,7 +133,6 @@ void send_req_1_input(void) void send_req_2_prev_meta(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_META; resp.has_request_type = true; resp.request_type = RequestType_TXMETA; @@ -142,7 +145,6 @@ void send_req_2_prev_meta(void) void send_req_2_prev_input(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; @@ -157,7 +159,6 @@ void send_req_2_prev_input(void) void send_req_2_prev_output(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -172,7 +173,6 @@ void send_req_2_prev_output(void) void send_req_3_output(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_3_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -184,7 +184,6 @@ void send_req_3_output(void) void send_req_4_input(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_4_INPUT; resp.has_request_type = true; resp.request_type = RequestType_TXINPUT; @@ -196,7 +195,6 @@ void send_req_4_input(void) void send_req_4_output(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_4_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -208,7 +206,6 @@ void send_req_4_output(void) void send_req_5_output(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); signing_stage = STAGE_REQUEST_5_OUTPUT; resp.has_request_type = true; resp.request_type = RequestType_TXOUTPUT; @@ -220,7 +217,6 @@ void send_req_5_output(void) void send_req_finished(void) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); resp.has_request_type = true; resp.request_type = RequestType_TXFINISHED; msg_write(MessageType_MessageType_TxRequest, &resp); @@ -241,8 +237,10 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp memset(&resp, 0, sizeof(TxRequest)); signing = true; - progress = 1; - progress_total = inputs_count * (1 + inputs_count + outputs_count) + outputs_count + 1; + progress = 0; + // we step by 500/inputs_count per input in phase1 and phase2 + // this means 50 % per phase. + progress_step = (500 << PROGRESS_PRECISION) / inputs_count; multisig_fp_set = false; multisig_fp_mismatch = false; @@ -263,14 +261,17 @@ void signing_txack(TransactionType *tx) return; } - layoutProgress("Signing transaction", 1000 * progress / progress_total); + static int update_ctr = 0; + if (update_ctr++ == 50) { + layoutProgress("Signing transaction", progress); + update_ctr = 0; + } int co; memset(&resp, 0, sizeof(TxRequest)); switch (signing_stage) { case STAGE_REQUEST_1_INPUT: - progress++; /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && @@ -304,10 +305,12 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_2_PREV_META: tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false); + progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; send_req_2_prev_input(); return; case STAGE_REQUEST_2_PREV_INPUT: + progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_input_hash(&tp, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); @@ -322,6 +325,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_OUTPUT: + progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); @@ -371,10 +375,10 @@ void signing_txack(TransactionType *tx) is_change = true; } } else - if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && - tx->outputs[0].address_n_count > 0) { - is_change = true; - } + if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && + tx->outputs[0].address_n_count > 0) { + is_change = true; + } if (is_change) { if (change_spend == 0) { // not set @@ -388,9 +392,6 @@ void signing_txack(TransactionType *tx) spending += tx->outputs[0].amount; co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); - if (!is_change) { - layoutProgress("Signing transaction", 1000 * progress / progress_total); - } if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); signing_abort(); @@ -436,6 +437,7 @@ void signing_txack(TransactionType *tx) } // Everything was checked, now phase 2 begins and the transaction is signed. + progress_meta_step = progress_step / (inputs_count + outputs_count); idx1 = 0; idx2 = 0; send_req_4_input(); @@ -443,13 +445,13 @@ void signing_txack(TransactionType *tx) return; } case STAGE_REQUEST_4_INPUT: + progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); tx_init(&tc, inputs_count, outputs_count, version, lock_time, false); memset(privkey, 0, 32); memset(pubkey, 0, 33); } - progress++; if (!tx_serialize_input_hash(&tc, tx->inputs)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); signing_abort(); @@ -498,7 +500,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_4_OUTPUT: - progress++; + progress = 500 + ((idx1 * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); co = compile_output(coin, root, tx->outputs, &bin_output, false); if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); @@ -562,6 +564,9 @@ void signing_txack(TransactionType *tx) input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); + // since this took a longer time, update progress + layoutProgress("Signing transaction", progress); + update_ctr = 0; if (idx1 < inputs_count - 1) { idx1++; idx2 = 0; @@ -573,7 +578,6 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_5_OUTPUT: - progress++; if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); signing_abort(); From 73c42402b9e9a8d3f10b539c44d564c28f9b1cd2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 20 Feb 2015 20:22:05 +0100 Subject: [PATCH 0109/1154] implement SignIdentity workflow --- firmware/crypto.c | 27 ++++++++++++++++++++++ firmware/crypto.h | 2 ++ firmware/fsm.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ firmware/fsm.h | 1 + firmware/layout2.c | 12 ++++++++++ firmware/layout2.h | 1 + firmware/messages.c | 2 ++ 7 files changed, 100 insertions(+) diff --git a/firmware/crypto.c b/firmware/crypto.c index d0f9f48357..9015b462fe 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -340,3 +340,30 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t layoutProgressUpdate(true); return 1; } + +int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) +{ + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); + if (identity->has_proto && identity->proto[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->proto), strlen(identity->proto)); + sha256_Update(&ctx, (const uint8_t *)"://", 3); + } + if (identity->has_user && identity->user[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->user), strlen(identity->user)); + sha256_Update(&ctx, (const uint8_t *)"@", 1); + } + if (identity->has_host && identity->host[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->host), strlen(identity->host)); + } + if (identity->has_port && identity->port[0]) { + sha256_Update(&ctx, (const uint8_t *)":", 1); + sha256_Update(&ctx, (const uint8_t *)(identity->port), strlen(identity->port)); + } + if (identity->has_path && identity->path[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); + } + sha256_Final(hash, &ctx); + return 1; +} diff --git a/firmware/crypto.h b/firmware/crypto.h index 4353aa635e..89878003c7 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -48,4 +48,6 @@ int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const ui int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); +int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash); + #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 6a4e07d711..4ea436c5b4 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -620,6 +620,61 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) layoutHome(); } +void fsm_msgSignIdentity(SignIdentity *msg) +{ + RESP_INIT(SignedIdentity); + + layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); + layoutHome(); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + uint8_t hash[32]; + if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); + layoutHome(); + return; + } + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 46; + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); + + const HDNode *node = fsm_getDerivedNode(address_n, 5); + if (!node) return; + + uint8_t message[128]; + memcpy(message, msg->challenge_hidden.bytes, msg->challenge_hidden.size); + const int len = strlen(msg->challenge_visual); + memcpy(message + msg->challenge_hidden.size, msg->challenge_visual, len); + + layoutProgressSwipe("Signing", 0); + if (cryptoMessageSign(message, msg->challenge_hidden.size + len, node->private_key, resp->signature.bytes) == 0) { + resp->has_address = true; + uint8_t addr_raw[21]; + ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type + base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); + resp->has_public_key = true; + resp->public_key.size = 33; + memcpy(resp->public_key.bytes, node->public_key, 33); + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_SignedIdentity, resp); + } else { + fsm_sendFailure(FailureType_Failure_Other, "Error signing identity"); + } + layoutHome(); +} + void fsm_msgEncryptMessage(EncryptMessage *msg) { if (!msg->has_pubkey) { diff --git a/firmware/fsm.h b/firmware/fsm.h index 6b7bde8e39..021eeb31a3 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -49,6 +49,7 @@ void fsm_msgGetAddress(GetAddress *msg); void fsm_msgEntropyAck(EntropyAck *msg); void fsm_msgSignMessage(SignMessage *msg); void fsm_msgVerifyMessage(VerifyMessage *msg); +void fsm_msgSignIdentity(SignIdentity *msg); void fsm_msgEncryptMessage(EncryptMessage *msg); void fsm_msgDecryptMessage(DecryptMessage *msg); //void fsm_msgPassphraseAck(PassphraseAck *msg); diff --git a/firmware/layout2.c b/firmware/layout2.c index 73819d0a2a..6eda7a3355 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -261,3 +261,15 @@ void layoutAddress(const char *address, const char *desc) oledRefresh(); } + +void layoutSignIdentity(const IdentityType *identity, const char *challenge) +{ + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + "Sign identity?", + identity->has_proto ? identity->proto : NULL, + identity->has_user ? identity->user : NULL, + identity->has_host ? identity->host : NULL, + challenge, + NULL, + NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index b109863079..790737a329 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -36,5 +36,6 @@ void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutAddress(const char *address, const char *desc); +void layoutSignIdentity(const IdentityType *identity, const char *challenge); #endif diff --git a/firmware/messages.c b/firmware/messages.c index 0692ff5c07..8c11cbeabe 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -60,6 +60,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *))fsm_msgGetAddress}, {'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *))fsm_msgEntropyAck}, {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, + {'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity}, {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, @@ -80,6 +81,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'o', MessageType_MessageType_Address, Address_fields, 0}, {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, + {'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0}, {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, From 399d4d31b7a3b16f23449f9a846b70b6a01ab312 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Feb 2015 15:14:44 +0100 Subject: [PATCH 0110/1154] replace transaction check hashing --- firmware/signing.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 3224808e07..f16f42debd 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -46,7 +46,8 @@ static uint32_t idx1, idx2; static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; -static TxStruct to, tp, ti, tc; +static TxStruct to, tp, ti; +static SHA256_CTX tc; static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; static uint64_t to_spend, spending, change_spend; const uint32_t version = 1; @@ -246,7 +247,11 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp multisig_fp_mismatch = false; tx_init(&to, inputs_count, outputs_count, version, lock_time, false); - tx_init(&tc, inputs_count, outputs_count, version, lock_time, false); + sha256_Init(&tc); + sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); + sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); + sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); + sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); layoutProgressSwipe("Signing transaction", 0); @@ -295,11 +300,7 @@ void signing_txack(TransactionType *tx) multisig_fp_set = true; } } - if (!tx_serialize_input_hash(&tc, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); - signing_abort(); - return; - } + sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); return; @@ -401,17 +402,12 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (!tx_serialize_output_hash(&tc, &bin_output)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); - signing_abort(); - return; - } + sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); if (idx1 < outputs_count - 1) { idx1++; send_req_3_output(); } else { - tx_hash_final(&tc, hash_check, false); - + sha256_Final(hash_check, &tc); // check fees if (spending > to_spend) { fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); @@ -448,15 +444,15 @@ void signing_txack(TransactionType *tx) progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); - tx_init(&tc, inputs_count, outputs_count, version, lock_time, false); + sha256_Init(&tc); + sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); + sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); + sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); + sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); memset(privkey, 0, 32); memset(pubkey, 0, 33); } - if (!tx_serialize_input_hash(&tc, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); - signing_abort(); - return; - } + sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); if (idx2 == idx1) { memcpy(&input, tx->inputs, sizeof(TxInputType)); memcpy(&node, root, sizeof(HDNode)); @@ -511,11 +507,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (!tx_serialize_output_hash(&tc, &bin_output)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); - signing_abort(); - return; - } + sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); if (!tx_serialize_output_hash(&ti, &bin_output)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); @@ -525,7 +517,7 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_output(); } else { - tx_hash_final(&tc, hash, false); + sha256_Final(hash, &tc); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); signing_abort(); From 137a60ce017c402ac160258bcc4b5f7b5aba0560 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Feb 2015 15:17:49 +0100 Subject: [PATCH 0111/1154] set multisig_fp_mismatch when non-multisig input is encountered --- firmware/messages.c | 1 + firmware/signing.c | 39 +++++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 8c11cbeabe..1c95d8167e 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -281,6 +281,7 @@ enum { void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) { static uint8_t msg_data[MSG_IN_SIZE]; + memset(msg_data, 0, sizeof(msg_data)); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); bool status = pb_decode(&stream, fields, msg_data); if (status) { diff --git a/firmware/signing.c b/firmware/signing.c index f16f42debd..26c202d5a9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -279,26 +279,29 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG && - tx->inputs[0].has_multisig && !multisig_fp_mismatch) { - if (multisig_fp_set) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { + if (tx->inputs[0].has_multisig && !multisig_fp_mismatch) { + if (multisig_fp_set) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + signing_abort(); + return; + } + multisig_fp_set = true; } - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - multisig_fp_set = true; } + } else { // InputScriptType_SPENDADDRESS + multisig_fp_mismatch = true; } sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); memcpy(&input, tx->inputs, sizeof(TxInputType)); From eefa689b335adf52a5089e7f3d396668a7cca465 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 25 Feb 2015 17:57:47 +0100 Subject: [PATCH 0112/1154] call layout functions where needed to rewrite the display after dialog choice --- firmware/layout2.c | 6 +++--- firmware/signing.c | 6 +++++- layout.c | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 6eda7a3355..db1f976bb5 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -111,7 +111,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, @@ -128,7 +128,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ { const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, @@ -145,7 +145,7 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) { (void)kb; const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, diff --git a/firmware/signing.c b/firmware/signing.c index 26c202d5a9..697f4054a9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -396,6 +396,9 @@ void signing_txack(TransactionType *tx) spending += tx->outputs[0].amount; co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); + if (!is_change) { + layoutProgress("Signing transaction", progress); + } if (co < 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); signing_abort(); @@ -426,6 +429,7 @@ void signing_txack(TransactionType *tx) layoutHome(); return; } + layoutProgress("Signing transaction", progress); } // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); @@ -434,9 +438,9 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - // Everything was checked, now phase 2 begins and the transaction is signed. progress_meta_step = progress_step / (inputs_count + outputs_count); + layoutProgress("Signing transaction", progress); idx1 = 0; idx2 = 0; send_req_4_input(); diff --git a/layout.c b/layout.c index cdcc034901..ecb97210b6 100644 --- a/layout.c +++ b/layout.c @@ -117,7 +117,6 @@ void layoutProgress(const char *desc, int permil) permil = OLED_WIDTH - 4; } oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); - // text oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); if (desc) { From 82308d8a382885892d1a58f6c254940ff137bfda Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 25 Feb 2015 20:26:21 +0100 Subject: [PATCH 0113/1154] make wording more verbose (in SignIdentity) --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index db1f976bb5..098e5ae14c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -265,7 +265,7 @@ void layoutAddress(const char *address, const char *desc) void layoutSignIdentity(const IdentityType *identity, const char *challenge) { layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - "Sign identity?", + "Login using this identity?", identity->has_proto ? identity->proto : NULL, identity->has_user ? identity->user : NULL, identity->has_host ? identity->host : NULL, From 127204637532325c354f4b7768b07418726ec8ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 2 Mar 2015 19:58:33 +0100 Subject: [PATCH 0114/1154] login -> sign in --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 098e5ae14c..4ea17ba108 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -265,7 +265,7 @@ void layoutAddress(const char *address, const char *desc) void layoutSignIdentity(const IdentityType *identity, const char *challenge) { layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - "Login using this identity?", + "Sign in using this identity?", identity->has_proto ? identity->proto : NULL, identity->has_user ? identity->user : NULL, identity->has_host ? identity->host : NULL, From d1c62659f7259a4123ed82e85bef806d463ee1a8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 2 Mar 2015 21:33:06 +0100 Subject: [PATCH 0115/1154] make signidentity dialog nicer --- firmware/layout2.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 4ea17ba108..7eca9f5e5b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -19,6 +19,7 @@ #include #include +#include #include "layout2.h" #include "storage.h" @@ -264,11 +265,41 @@ void layoutAddress(const char *address, const char *desc) void layoutSignIdentity(const IdentityType *identity, const char *challenge) { + char row_proto[8 + 8 + 1]; + char row_hostport[64 + 6 + 1]; + char row_user[64 + 8 + 1]; + + if (identity->has_proto && identity->proto[0]) { + strlcpy(row_proto, identity->proto, sizeof(row_proto)); + char *p = row_proto; + while (*p) { *p = toupper((int)*p); p++; } + strlcat(row_proto, " login:", sizeof(row_proto)); + } else { + strlcpy(row_proto, "Login:", sizeof(row_proto)); + } + + if (identity->has_host && identity->host[0]) { + strlcpy(row_hostport, identity->host, sizeof(row_hostport)); + if (identity->has_port && identity->port[0]) { + strlcat(row_hostport, ":", sizeof(row_hostport)); + strlcat(row_hostport, identity->user, sizeof(row_hostport)); + } + } else { + row_hostport[0] = 0; + } + + if (identity->has_user && identity->user[0]) { + strlcpy(row_user, "user: ", sizeof(row_user)); + strlcat(row_user, identity->user, sizeof(row_user)); + } else { + row_user[0] = 0; + } + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", "Sign in using this identity?", - identity->has_proto ? identity->proto : NULL, - identity->has_user ? identity->user : NULL, - identity->has_host ? identity->host : NULL, + row_proto[0] ? row_proto : NULL, + row_hostport[0] ? row_hostport : NULL, + row_user[0] ? row_user : NULL, challenge, NULL, NULL); From 65d734df58566d11365a3cf0d66f79811ac35381 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Mar 2015 02:09:15 +0100 Subject: [PATCH 0116/1154] add Darkcoin --- firmware/coins.c | 1 + firmware/coins.h | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 60a44429a4..59a28bf844 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,6 +26,7 @@ const CoinType coins[COINS_COUNT] = { {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, {true, "Litecoin", true, "LTC", true, 48, true, 10000000, true, 5}, {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000, true, 22}, + {true, "Darkcoin", true, "DRK", true, 76, true, 100000, true, 16}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/coins.h b/firmware/coins.h index 1995bb797d..b57566ee33 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 5 +#define COINS_COUNT 6 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index cc66922d13..da0af37c9c 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:5 +Features.coins max_count:6 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 50b2fd867e..873c950f79 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -370,7 +370,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[5]; + CoinType coins[6]; bool has_initialized; bool initialized; bool has_revision; @@ -624,7 +624,7 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Initializer values for message structs */ #define Initialize_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -677,7 +677,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkStop_init_default {0} #define DebugLinkLog_init_default {false, 0, false, "", false, ""} #define Initialize_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -917,7 +917,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 -#define Features_size (230 + 5*CoinType_size) +#define Features_size (236 + 6*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 From 24660f3e2cf1e2d1b285122ed0df36849fb5c1b3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Mar 2015 17:42:25 +0100 Subject: [PATCH 0117/1154] fix port in signidentity dialog --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 7eca9f5e5b..8175729bcf 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -282,7 +282,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) strlcpy(row_hostport, identity->host, sizeof(row_hostport)); if (identity->has_port && identity->port[0]) { strlcat(row_hostport, ":", sizeof(row_hostport)); - strlcat(row_hostport, identity->user, sizeof(row_hostport)); + strlcat(row_hostport, identity->port, sizeof(row_hostport)); } } else { row_hostport[0] = 0; From 0ee02eb09ae9614c808a9013b0570b67845d2e9e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Mar 2015 18:35:04 +0100 Subject: [PATCH 0118/1154] revert non-swiping dialogs --- firmware/layout2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 8175729bcf..74f8e6616e 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -112,7 +112,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialog(DIALOG_ICON_QUESTION, + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, @@ -129,7 +129,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ { const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee)); - layoutDialog(DIALOG_ICON_QUESTION, + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, @@ -146,7 +146,7 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) { (void)kb; const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialog(DIALOG_ICON_QUESTION, + layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, From 2451936f0ea64ee2078e110d12e157231a3f2119 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Mar 2015 18:10:09 +0100 Subject: [PATCH 0119/1154] add posibility to override tag to be built in firmware-docker-build, make master as default --- firmware-docker-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index cb4f524f71..11f7ba921b 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,6 +1,6 @@ #!/bin/bash IMAGETAG=trezor-mcu-build -FIRMWARETAG=v1.3.1 +FIRMWARETAG=${1:-master} docker build -t $IMAGETAG . docker run -t -v $(pwd):/output $IMAGETAG /bin/sh -c "\ From 1441dffe0e43987e0a0489b381a958f464e4654f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 Mar 2015 15:21:22 +0100 Subject: [PATCH 0120/1154] cmdtr -> trezorctl --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 10c9d23274..d63a35c690 100644 --- a/Makefile.include +++ b/Makefile.include @@ -85,7 +85,7 @@ flash2: $(NAME).hex -c "shutdown" upload: - ../../python-trezor/cmdtr.py firmware_update -f $(NAME).bin + ../../python-trezor/trezorctl firmware_update -f $(NAME).bin sign: $(NAME).bin ../bootloader/firmware_sign.py -f $(NAME).bin From fb2a085fffccae5dd50c608472df2cdd3a7b5521 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 Mar 2015 16:14:11 +0100 Subject: [PATCH 0121/1154] update trezor-crypto --- bootloader/Makefile | 1 - firmware/Makefile | 1 - trezor-crypto | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index fd8703d390..620d1bc76f 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -15,7 +15,6 @@ OBJS += $(MCU_DIR)/trezor-crypto/sha2.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 -CFLAGS += -DUSE_PUBKEY_VALIDATE=0 include $(MCU_DIR)/Makefile.include diff --git a/firmware/Makefile b/firmware/Makefile index 193738731a..74a642814e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -50,7 +50,6 @@ include ../Makefile.include CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DQR_MAX_VERSION=0 -CFLAGS += -DUSE_PUBKEY_VALIDATE=0 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' diff --git a/trezor-crypto b/trezor-crypto index d814f58a3b..cb9ccc5cf4 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit d814f58a3b027b154ae77bdf236a0cd08a421107 +Subproject commit cb9ccc5cf4ea3992172f31e8d1506f1a5b791157 From c286cd75f3e5695cb5b9d6ac7bcfb6fdfd7791a2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 17 Mar 2015 14:23:58 +0100 Subject: [PATCH 0122/1154] bn_substract_noprime -> bn_subtract --- firmware/crypto.c | 2 +- trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 9015b462fe..a78aa4002e 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -136,7 +136,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ sha256_Raw(hash, 32, hash); // e = -hash bn_read_be(hash, &e); - bn_substract_noprime(&order256k1, &e, &e); + bn_subtract(&order256k1, &e, &e); // r = r^-1 bn_inverse(&r, &order256k1); point_multiply(&s, &cp, &cp); diff --git a/trezor-crypto b/trezor-crypto index cb9ccc5cf4..e37ba822e6 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit cb9ccc5cf4ea3992172f31e8d1506f1a5b791157 +Subproject commit e37ba822e627550a453a1678d180f7e056b3d98f From f344ec9c9ba4d784906e239b21cf297b04b7bf4d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 17 Mar 2015 15:02:07 +0100 Subject: [PATCH 0123/1154] actually is SLIP-0013 --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4ea436c5b4..4604ec505c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -643,7 +643,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) return; } uint32_t address_n[5]; - address_n[0] = 0x80000000 | 46; + address_n[0] = 0x80000000 | 13; address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); From 40e174ac87da529f58aad26dd22baf94e3e73e96 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Mar 2015 13:34:09 +0100 Subject: [PATCH 0124/1154] bump storage version --- firmware/storage.c | 11 +++++++---- trezor-common | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 44494610c4..6eed1865c1 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -62,18 +62,21 @@ static char sessionPassphrase[51]; 0x0010 | ? | Storage structure */ -#define STORAGE_VERSION 3 +#define STORAGE_VERSION 4 void storage_from_flash(uint32_t version) { switch (version) { - case 1: // copy + case 1: // copy (since 1.0.0) memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; - case 2: // copy + case 2: // copy (since 1.2.1) memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; - case 3: // copy + case 3: // copy (since 1.3.1) + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + break; + case 4: // copy (since 1.3.2) memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; } diff --git a/trezor-common b/trezor-common index 69d476a3ba..137ae02853 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 69d476a3ba10c40209dd26789876b265cf03f384 +Subproject commit 137ae028531567ec2e042ffcd6d6c73a97cfd4c8 From 9761dd23e0cd28d7a98ce331e1676f7466336b7d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 21 Mar 2015 10:44:30 +0100 Subject: [PATCH 0125/1154] prepare 1.3.2 release --- Dockerfile | 4 ++-- README.rst | 4 ++-- firmware/trezor.h | 2 +- trezor-crypto | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index e77b0acd2d..db72b88ae7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty # install build tools and dependencies -ENV GCC_ARM_VERSION 4.9.3.2014q4-0trusty12 +ENV GCC_ARM_VERSION 4.9.3.2015q1-0trusty13 RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION python # clone the source code @@ -19,5 +19,5 @@ RUN git clone https://github.com/libopencm3/libopencm3 # build libopencm3 -ENV LIBOPENCM3_GITREV 8a15cec6bf99f59065879a14895fb8af8a8a53e7 +ENV LIBOPENCM3_GITREV fd141a81313876e3dc9253d682f7314fa2a59718 RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make diff --git a/README.rst b/README.rst index c12aa8303e..5b0929dcc7 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ How to build Trezor firmware? 1. Install Docker (from docker.com or from your distribution repositories) 2. ``git clone https://github.com/trezor/trezor-mcu.git`` 3. ``cd trezor-mcu`` -4. ``./firmware-docker-build.sh`` +4. ``./firmware-docker-build.sh TAG`` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) This creates trezor.bin in current directory and prints its fingerprint at the last line of the build log. @@ -21,6 +21,6 @@ How to get fingerprint of firmware signed and distributed by SatoshiLabs? 3. ``xxd -r -p trezor.signed.bin.hex trezor.signed.bin`` 4. ``./firmware-fingerprint.sh trezor.signed.bin`` -Step 4 should produce the same sha256 fingerprint like your local build. +Step 4 should produce the same sha256 fingerprint like your local build (for the same version tag). The reasoning for ``firmware-fingerprint.sh`` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. diff --git a/firmware/trezor.h b/firmware/trezor.h index 0a368c6627..1664edd343 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/trezor-crypto b/trezor-crypto index e37ba822e6..d4df66a8d0 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit e37ba822e627550a453a1678d180f7e056b3d98f +Subproject commit d4df66a8d05886999fcaac0671119f153bcb49e8 From e855946d1cfb8f54c2dd13971600e8fc0567c5cc Mon Sep 17 00:00:00 2001 From: ELMr4Ever Date: Sat, 28 Mar 2015 21:12:01 -0700 Subject: [PATCH 0126/1154] Darkcoin to Dash re-branding --- firmware/coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/coins.c b/firmware/coins.c index 59a28bf844..1c33addc38 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,7 +26,7 @@ const CoinType coins[COINS_COUNT] = { {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, {true, "Litecoin", true, "LTC", true, 48, true, 10000000, true, 5}, {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000, true, 22}, - {true, "Darkcoin", true, "DRK", true, 76, true, 100000, true, 16}, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16}, }; const CoinType *coinByShortcut(const char *shortcut) From 7c6d2fe395c8475efbc93257892f0efac3d1511c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 30 Mar 2015 14:38:33 +0200 Subject: [PATCH 0127/1154] ask for PIN in GetAddress and GetPublicKey messages --- firmware/fsm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4604ec505c..99d0095440 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -268,6 +268,11 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); + if (!protectPin(true)) { + layoutHome(); + return; + } + const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; @@ -500,6 +505,11 @@ void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); + if (!protectPin(true)) { + layoutHome(); + return; + } + const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); From bda4267c388caa07d71417e1910cbf2b6be5d7e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 30 Mar 2015 14:41:51 +0200 Subject: [PATCH 0128/1154] clear session on Initialize message --- firmware/fsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 99d0095440..ac0cd3ad08 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -113,6 +113,7 @@ void fsm_msgInitialize(Initialize *msg) (void)msg; recovery_abort(); signing_abort(); + session_clear(); RESP_INIT(Features); resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); resp->has_major_version = true; resp->major_version = VERSION_MAJOR; From aee35dc768c96c6c9dc8ea6ea95dee1d1cb88603 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 30 Mar 2015 15:47:03 +0200 Subject: [PATCH 0129/1154] add pin_cached + passphrase_cached fields to Features message; add GetFeatures message --- firmware/fsm.c | 8 ++++++++ firmware/fsm.h | 1 + firmware/messages.c | 1 + firmware/protob/messages.pb.c | 10 ++++++++-- firmware/protob/messages.pb.h | 23 +++++++++++++++++++---- trezor-common | 2 +- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ac0cd3ad08..fea3eef66a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -114,6 +114,12 @@ void fsm_msgInitialize(Initialize *msg) recovery_abort(); signing_abort(); session_clear(); + fsm_msgGetFeatures(0); +} + +void fsm_msgGetFeatures(GetFeatures *msg) +{ + (void)msg; RESP_INIT(Features); resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); resp->has_major_version = true; resp->major_version = VERSION_MAJOR; @@ -139,6 +145,8 @@ void fsm_msgInitialize(Initialize *msg) memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType)); resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; + resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); + resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/fsm.h b/firmware/fsm.h index 021eeb31a3..1a3fcf8f1e 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -28,6 +28,7 @@ void fsm_sendSuccess(const char *text); void fsm_sendFailure(FailureType code, const char *text); void fsm_msgInitialize(Initialize *msg); +void fsm_msgGetFeatures(GetFeatures *msg); void fsm_msgPing(Ping *msg); void fsm_msgChangePin(ChangePin *msg); void fsm_msgWipeDevice(WipeDevice *msg); diff --git a/firmware/messages.c b/firmware/messages.c index 1c95d8167e..7803efee62 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -40,6 +40,7 @@ struct MessagesMap_t { static const struct MessagesMap_t MessagesMap[] = { // in messages {'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *))fsm_msgInitialize}, + {'n', 'i', MessageType_MessageType_GetFeatures, GetFeatures_fields, (void (*)(void *))fsm_msgGetFeatures}, {'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *))fsm_msgPing}, {'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *))fsm_msgChangePin}, {'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *))fsm_msgWipeDevice}, diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 3e4e41bf27..8823d70f96 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -19,7 +19,11 @@ const pb_field_t Initialize_fields[1] = { PB_LAST_FIELD }; -const pb_field_t Features_fields[16] = { +const pb_field_t GetFeatures_fields[1] = { + PB_LAST_FIELD +}; + +const pb_field_t Features_fields[18] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), @@ -35,6 +39,8 @@ const pb_field_t Features_fields[16] = { PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), + PB_FIELD2( 16, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_cached, imported, 0), + PB_FIELD2( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), PB_LAST_FIELD }; @@ -365,7 +371,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 873c950f79..b56c8d37fa 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -60,6 +60,7 @@ typedef enum _MessageType { MessageType_MessageType_DecryptedMessage = 52, MessageType_MessageType_SignIdentity = 53, MessageType_MessageType_SignedIdentity = 54, + MessageType_MessageType_GetFeatures = 55, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, @@ -96,6 +97,10 @@ typedef struct _FirmwareErase { uint8_t dummy_field; } FirmwareErase; +typedef struct _GetFeatures { + uint8_t dummy_field; +} GetFeatures; + typedef struct _Initialize { uint8_t dummy_field; } Initialize; @@ -379,6 +384,10 @@ typedef struct _Features { Features_bootloader_hash_t bootloader_hash; bool has_imported; bool imported; + bool has_pin_cached; + bool pin_cached; + bool has_passphrase_cached; + bool passphrase_cached; } Features; typedef struct { @@ -624,7 +633,8 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Initializer values for message structs */ #define Initialize_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define GetFeatures_init_default {0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -677,7 +687,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define DebugLinkStop_init_default {0} #define DebugLinkLog_init_default {false, 0, false, "", false, ""} #define Initialize_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0} +#define GetFeatures_init_zero {0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -796,6 +807,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Features_revision_tag 13 #define Features_bootloader_hash_tag 14 #define Features_imported_tag 15 +#define Features_pin_cached_tag 16 +#define Features_passphrase_cached_tag 17 #define FirmwareUpload_payload_tag 1 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 @@ -862,7 +875,8 @@ extern const char SimpleSignTx_coin_name_default[17]; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; -extern const pb_field_t Features_fields[16]; +extern const pb_field_t GetFeatures_fields[1]; +extern const pb_field_t Features_fields[18]; extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[5]; extern const pb_field_t ChangePin_fields[2]; @@ -917,7 +931,8 @@ extern const pb_field_t DebugLinkLog_fields[4]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 -#define Features_size (236 + 6*CoinType_size) +#define GetFeatures_size 0 +#define Features_size (242 + 6*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 diff --git a/trezor-common b/trezor-common index 137ae02853..e96ec085d5 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 137ae028531567ec2e042ffcd6d6c73a97cfd4c8 +Subproject commit e96ec085d55c20eccecb47e0a55b33295164de6d From 956546ae5465529f5bfe0754d69070920a7a9247 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 31 Mar 2015 16:26:51 +0200 Subject: [PATCH 0130/1154] update trezor-crypto --- trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezor-crypto b/trezor-crypto index d4df66a8d0..a757693fe3 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit d4df66a8d05886999fcaac0671119f153bcb49e8 +Subproject commit a757693fe3904f60d80d36fe0bfe437dea55e02e From 4cbf29505d25f6fcabeaac2db645169e214b2831 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 31 Mar 2015 16:31:29 +0200 Subject: [PATCH 0131/1154] don't clear PIN on Initialize --- firmware/fsm.c | 4 ++-- firmware/storage.c | 8 +++++--- firmware/storage.h | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index fea3eef66a..b4025c5ee6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -113,7 +113,7 @@ void fsm_msgInitialize(Initialize *msg) (void)msg; recovery_abort(); signing_abort(); - session_clear(); + session_clear(false); // do not clear PIN fsm_msgGetFeatures(0); } @@ -447,7 +447,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) void fsm_msgClearSession(ClearSession *msg) { (void)msg; - session_clear(); + session_clear(true); // clear PIN as well fsm_sendSuccess("Session cleared"); } diff --git a/firmware/storage.c b/firmware/storage.c index 6eed1865c1..5718247c2a 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -117,14 +117,16 @@ void storage_reset(void) // reset storage struct memset(&storage, 0, sizeof(storage)); storage.version = STORAGE_VERSION; - session_clear(); + session_clear(true); // clear PIN as well } -void session_clear(void) +void session_clear(bool clear_pin) { sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); - sessionPinCached = false; + if (clear_pin) { + sessionPinCached = false; + } } static uint8_t meta_backup[FLASH_META_LEN]; diff --git a/firmware/storage.h b/firmware/storage.h index 2b7b9b4e75..b1041a8b93 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -29,7 +29,7 @@ void storage_init(void); void storage_reset_uuid(void); void storage_reset(void); void storage_commit(void); -void session_clear(void); +void session_clear(bool clear_pin); void storage_loadDevice(LoadDevice *msg); From 8b268692fe4cf98f31edfc9893b6fa6ac1d22d0c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 1 Apr 2015 17:17:37 +0200 Subject: [PATCH 0132/1154] prepare 1.3.3 release --- Dockerfile | 2 +- firmware/trezor.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index db72b88ae7..58c67f109b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,5 +19,5 @@ RUN git clone https://github.com/libopencm3/libopencm3 # build libopencm3 -ENV LIBOPENCM3_GITREV fd141a81313876e3dc9253d682f7314fa2a59718 +ENV LIBOPENCM3_GITREV 7dbb93c78411b37bec64b5ca5be55076b0ab1b15 RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make diff --git a/firmware/trezor.h b/firmware/trezor.h index 1664edd343..15999b831b 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 2 +#define VERSION_PATCH 3 #define STR(X) #X #define VERSTR(X) STR(X) From 00ccf6a8ce4e460230b44b552f5a7a55dc251064 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 1 Apr 2015 19:43:36 +0200 Subject: [PATCH 0133/1154] bump storage version --- firmware/storage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 5718247c2a..94470331e2 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -62,7 +62,7 @@ static char sessionPassphrase[51]; 0x0010 | ? | Storage structure */ -#define STORAGE_VERSION 4 +#define STORAGE_VERSION 5 void storage_from_flash(uint32_t version) { @@ -79,6 +79,9 @@ void storage_from_flash(uint32_t version) case 4: // copy (since 1.3.2) memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); break; + case 5: // copy (since 1.3.3) + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + break; } storage.version = STORAGE_VERSION; } From ba73f43f71a38d300c1b711dd71f31712a6ebb88 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 2 Apr 2015 16:48:50 +0200 Subject: [PATCH 0134/1154] change "sign in" screen --- firmware/layout2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 74f8e6616e..a61d566e0a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -265,7 +265,7 @@ void layoutAddress(const char *address, const char *desc) void layoutSignIdentity(const IdentityType *identity, const char *challenge) { - char row_proto[8 + 8 + 1]; + char row_proto[8 + 11 + 1]; char row_hostport[64 + 6 + 1]; char row_user[64 + 8 + 1]; @@ -273,9 +273,9 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) strlcpy(row_proto, identity->proto, sizeof(row_proto)); char *p = row_proto; while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, " login:", sizeof(row_proto)); + strlcat(row_proto, " login to:", sizeof(row_proto)); } else { - strlcpy(row_proto, "Login:", sizeof(row_proto)); + strlcpy(row_proto, "Login to:", sizeof(row_proto)); } if (identity->has_host && identity->host[0]) { @@ -296,7 +296,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) } layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", - "Sign in using this identity?", + "Do you want to sign in?", row_proto[0] ? row_proto : NULL, row_hostport[0] ? row_hostport : NULL, row_user[0] ? row_user : NULL, From 795f70075b859503c4ac3183310f096ebefcc065 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 2 Apr 2015 17:19:07 +0200 Subject: [PATCH 0135/1154] make SignIdentity.challenge_hidden and SignIdentity.challenge_visual longer (256 bytes) --- firmware/fsm.c | 2 +- firmware/protob/messages.options | 4 ++-- firmware/protob/messages.pb.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b4025c5ee6..c0da402483 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -671,7 +671,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) const HDNode *node = fsm_getDerivedNode(address_n, 5); if (!node) return; - uint8_t message[128]; + uint8_t message[256 + 256]; memcpy(message, msg->challenge_hidden.bytes, msg->challenge_hidden.size); const int len = strlen(msg->challenge_visual); memcpy(message + msg->challenge_hidden.size, msg->challenge_visual, len); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index da0af37c9c..a322f98601 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -86,8 +86,8 @@ EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 -SignIdentity.challenge_hidden max_size:64 -SignIdentity.challenge_visual max_size:64 +SignIdentity.challenge_hidden max_size:256 +SignIdentity.challenge_visual max_size:256 SignedIdentity.address max_size:36 SignedIdentity.public_key max_size:33 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index b56c8d37fa..b867cc947d 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -510,7 +510,7 @@ typedef struct _ResetDevice { typedef struct { size_t size; - uint8_t bytes[64]; + uint8_t bytes[256]; } SignIdentity_challenge_hidden_t; typedef struct _SignIdentity { @@ -519,7 +519,7 @@ typedef struct _SignIdentity { bool has_challenge_hidden; SignIdentity_challenge_hidden_t challenge_hidden; bool has_challenge_visual; - char challenge_visual[64]; + char challenge_visual[256]; } SignIdentity; typedef struct { @@ -975,7 +975,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) -#define SignIdentity_size (138 + IdentityType_size) +#define SignIdentity_size (524 + IdentityType_size) #define SignedIdentity_size 140 #define FirmwareErase_size 0 #define FirmwareUpload_size 2 From 0cc270e6df3eca352eb8c72b602b7d5a0633b086 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 2 Apr 2015 17:47:28 +0200 Subject: [PATCH 0136/1154] reorder Dockerfile --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 58c67f109b..4123d71a1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,8 @@ FROM ubuntu:14.04 +ENV GCC_ARM_VERSION 4.9.3.2015q1-0trusty13 + # add and update package repositories RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB @@ -10,8 +12,8 @@ RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty # install build tools and dependencies -ENV GCC_ARM_VERSION 4.9.3.2015q1-0trusty13 -RUN apt-get install -y build-essential git gcc-arm-none-eabi=$GCC_ARM_VERSION python +RUN apt-get install -y build-essential git python +RUN apt-get install -y gcc-arm-none-eabi=$GCC_ARM_VERSION # clone the source code From ea7e92f5dd8efb8d8ea21910815eecf99698eae8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 13 Apr 2015 18:53:58 +0200 Subject: [PATCH 0137/1154] make gears turn faster when signing --- firmware/signing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index 697f4054a9..ca6a6682df 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -267,7 +267,7 @@ void signing_txack(TransactionType *tx) } static int update_ctr = 0; - if (update_ctr++ == 50) { + if (update_ctr++ == 20) { layoutProgress("Signing transaction", progress); update_ctr = 0; } From 1501ca2f6775bf6147c58c4775e1a77e55b3b57a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 13 Apr 2015 19:52:38 +0200 Subject: [PATCH 0138/1154] activate screensaver on ClearSession message --- firmware/fsm.c | 1 + firmware/layout2.c | 11 +++++++++-- firmware/layout2.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index c0da402483..1d756f20b3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -448,6 +448,7 @@ void fsm_msgClearSession(ClearSession *msg) { (void)msg; session_clear(true); // clear PIN as well + layoutScreensaver(); fsm_sendSuccess("Session cleared"); } diff --git a/firmware/layout2.c b/firmware/layout2.c index a61d566e0a..51bc154408 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -49,14 +49,21 @@ void layoutProgressSwipe(const char *desc, int permil) layoutProgress(desc, permil); } +void layoutScreensaver(void) +{ + layoutLast = layoutScreensaver; + oledClear(); + oledRefresh(); +} + void layoutHome(void) { - if (layoutLast == layoutHome) { + if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { oledClear(); } else { - layoutLast = layoutHome; oledSwipeLeft(); } + layoutLast = layoutHome; const char *label = storage_getLabel(); const uint8_t *homescreen = storage_getHomescreen(); if (homescreen) { diff --git a/firmware/layout2.h b/firmware/layout2.h index 790737a329..70e35491c0 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -26,6 +26,7 @@ void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); +void layoutScreensaver(void); void layoutHome(void); void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); From 7d8fb375f0d42fba3de314259c6873190e05e319 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Apr 2015 18:16:30 +0200 Subject: [PATCH 0139/1154] seconds counter during pin lockdown --- firmware/protect.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index d3d77a2344..b79dae86ee 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -147,13 +147,25 @@ bool protectPin(bool use_cached) } uint32_t fails = storage_getPinFails(); if (fails) { - if (fails > 2) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait ...", NULL, NULL, NULL); - } uint32_t wait; wait = (fails < 32) ? (1u << fails) : 0xFFFFFFFF; while (--wait > 0) { - delay(10000000); + // convert wait to secstr string + char secstrbuf[20]; + strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf)); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + while (secs > 0 && secstr >= secstrbuf) { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } + if (wait == 1) { + secstrbuf[16] = 0; + } + layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); + // wait one second + delay(24000000); } } const char *pin; From 6c40522291011bcfb43fc56d4125e3d4f5f29b95 Mon Sep 17 00:00:00 2001 From: Henrik Nordstrom Date: Thu, 5 Mar 2015 22:09:30 +0100 Subject: [PATCH 0140/1154] Put firmware files in output/ and name them with the tag built --- firmware-docker-build.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 11f7ba921b..d734404dbf 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -3,7 +3,7 @@ IMAGETAG=trezor-mcu-build FIRMWARETAG=${1:-master} docker build -t $IMAGETAG . -docker run -t -v $(pwd):/output $IMAGETAG /bin/sh -c "\ +docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ git clone https://github.com/trezor/trezor-mcu && \ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ @@ -11,10 +11,9 @@ docker run -t -v $(pwd):/output $IMAGETAG /bin/sh -c "\ make && \ cd firmware && \ make && \ - cp trezor.bin /output \ - " + cp trezor.bin /output/trezor-$FIRMWARETAG.bin" echo "---------------------" echo "Firmware fingerprint:" -sha256sum trezor.bin +sha256sum output/trezor-$FIRMWARETAG.bin From b56cf9246bac921c93ea7307eea2d8fc511f6a2a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Apr 2015 21:20:51 +0200 Subject: [PATCH 0141/1154] fix last commit --- README.rst | 2 +- firmware-docker-build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 5b0929dcc7..9ba8eba5f4 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,7 @@ How to build Trezor firmware? 3. ``cd trezor-mcu`` 4. ``./firmware-docker-build.sh TAG`` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) -This creates trezor.bin in current directory and prints its fingerprint at the last line of the build log. +This creates file ``output/trezor-TAG.bin`` and prints its fingerprint at the last line of the build log. How to get fingerprint of firmware signed and distributed by SatoshiLabs? ------------------------------------------------------------------------- diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index d734404dbf..f705c8ffbd 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -11,7 +11,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ make && \ cd firmware && \ make && \ - cp trezor.bin /output/trezor-$FIRMWARETAG.bin" + cp trezor.bin /output/trezor-$FIRMWARETAG.bin" echo "---------------------" echo "Firmware fingerprint:" From 218b9984bb256a4567cd54418c32154466966ab4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 29 Apr 2015 19:10:48 +0200 Subject: [PATCH 0142/1154] New usbDelay that delays and handles USB requests Added usbDelay that polls usb port (for system requests) while delaying. This is called instead of delay in the button and pin delay functions. Experimental evaluation gave that the cycle count should be roughly divided by 28.5. --- firmware/protect.c | 4 ++-- firmware/usb.c | 7 +++++++ firmware/usb.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index b79dae86ee..1cac5edf53 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -57,7 +57,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // button acked - check buttons if (acked) { - delay(100000); + usbDelay(3500); buttonUpdate(); if (button.YesUp) { result = true; @@ -165,7 +165,7 @@ bool protectPin(bool use_cached) } layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second - delay(24000000); + usbDelay(840000); } } const char *pin; diff --git a/firmware/usb.c b/firmware/usb.c index 43c7bd9018..03baabd791 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -332,3 +332,10 @@ void usbTiny(char set) { tiny = set; } + +void usbDelay(int cycles) +{ + while (cycles--) { + usbd_poll(usbd_dev); + } +} diff --git a/firmware/usb.h b/firmware/usb.h index eec42e34e9..d1dc250187 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -24,5 +24,6 @@ void usbInit(void); void usbPoll(void); void usbReconnect(void); void usbTiny(char set); +void usbDelay(int cycles); #endif From 7af050febb3757bf7df9ad5dcbada82c6782cf58 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Apr 2015 01:35:49 +0200 Subject: [PATCH 0143/1154] no need for bignum.small.o as there is no difference anymore --- bootloader/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index 620d1bc76f..498bdd16bc 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -6,7 +6,7 @@ OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o -OBJS += $(MCU_DIR)/trezor-crypto/bignum.small.o +OBJS += $(MCU_DIR)/trezor-crypto/bignum.o OBJS += $(MCU_DIR)/trezor-crypto/ecdsa.small.o OBJS += $(MCU_DIR)/trezor-crypto/hmac.o OBJS += $(MCU_DIR)/trezor-crypto/ripemd160.o From e99aafd94928eb547f7590fdf90116dcb7ef0672 Mon Sep 17 00:00:00 2001 From: Darin Stanchfield Date: Tue, 5 May 2015 12:01:34 -0700 Subject: [PATCH 0144/1154] fixed salt passing to pbkdf2_hmac_sha512 --- firmware/storage.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 94470331e2..a3e2f84ac2 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -267,8 +267,10 @@ bool storage_getRootNode(HDNode *node) if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) { // decrypt hd node uint8_t secret[64]; + uint8_t salt[12]; + memcpy(salt, "TREZORHD", 8); layoutProgressSwipe("Waking up", 0); - pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (uint8_t *)"TREZORHD", 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); + pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); aes_cbc_decrypt(sessionRootNode.chain_code, sessionRootNode.chain_code, 32, secret + 32, &ctx); From 02040421cbd1f2716f2f0bbf7077c8f384309afb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 May 2015 13:37:44 +0200 Subject: [PATCH 0145/1154] fix param order in memset --- firmware/fsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 1d756f20b3..332733d5a5 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -795,8 +795,8 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) if (display_only) { resp->has_address = false; resp->has_message = false; - memset(resp->address, sizeof(resp->address), 0); - memset(&(resp->message), sizeof(resp->message), 0); + memset(resp->address, 0, sizeof(resp->address)); + memset(&(resp->message), 0, sizeof(resp->message)); } else { resp->has_address = signing; resp->has_message = true; From 0ac032917b502456c28bdb4a703c08b41e1c62fb Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 3 Jun 2015 22:21:16 +0300 Subject: [PATCH 0146/1154] enable Trezor to perform SSH public key authentication support both NIST256P1 and SECP256K1 ECDSA curves. --- .gitmodules | 4 +- firmware-docker-build.sh | 4 +- firmware/Makefile | 1 + firmware/crypto.c | 35 +++++++++------ firmware/crypto.h | 4 +- firmware/fsm.c | 75 +++++++++++++++++++++++++------- firmware/protob/messages.options | 2 + firmware/protob/messages.pb.c | 6 ++- firmware/protob/messages.pb.h | 22 ++++++---- firmware/signing.c | 3 +- trezor-common | 2 +- trezor-crypto | 2 +- 12 files changed, 113 insertions(+), 47 deletions(-) diff --git a/.gitmodules b/.gitmodules index 97aef8fa1c..4dcf3d77e0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "trezor-crypto"] path = trezor-crypto - url = https://github.com/trezor/trezor-crypto.git + url = https://github.com/romanz/trezor-crypto.git [submodule "trezor-common"] path = trezor-common - url = https://github.com/trezor/trezor-common.git + url = https://github.com/romanz/trezor-common.git [submodule "trezor-qrenc"] path = trezor-qrenc url = https://github.com/trezor/trezor-qrenc.git diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index f705c8ffbd..5df459a3a5 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,10 +1,10 @@ #!/bin/bash IMAGETAG=trezor-mcu-build -FIRMWARETAG=${1:-master} +FIRMWARETAG="ssh-agent" docker build -t $IMAGETAG . docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ + git clone https://github.com/romanz/trezor-mcu && \ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ diff --git a/firmware/Makefile b/firmware/Makefile index 74a642814e..fa4aa3e16a 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -22,6 +22,7 @@ OBJS += debug.o OBJS += ../trezor-crypto/bignum.o OBJS += ../trezor-crypto/ecdsa.o OBJS += ../trezor-crypto/secp256k1.o +OBJS += ../trezor-crypto/nist256p1.o OBJS += ../trezor-crypto/hmac.o OBJS += ../trezor-crypto/bip32.o OBJS += ../trezor-crypto/bip39.o diff --git a/firmware/crypto.c b/firmware/crypto.c index a78aa4002e..3470159dfc 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -20,12 +20,13 @@ #include #include "crypto.h" #include "sha2.h" -#include "ecdsa.h" #include "pbkdf2.h" #include "aes.h" #include "hmac.h" #include "bip32.h" #include "layout.h" +#include "secp256k1.h" +#include "nist256p1.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -83,6 +84,12 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } +int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) +{ + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + return ecdsa_sign(&nist256p1, privkey, message, message_len, signature + 1, NULL); +} + int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) { SHA256_CTX ctx; @@ -96,7 +103,7 @@ int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t sha256_Final(hash, &ctx); sha256_Raw(hash, 32, hash); uint8_t pby; - ecdsa_sign_digest(privkey, hash, signature + 1, &pby); + ecdsa_sign_digest(&secp256k1, privkey, hash, signature + 1, &pby); signature[0] = 27 + pby + 4; return 0; } @@ -124,7 +131,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ // x = r memcpy(&cp.x, &r, sizeof(bignum256)); // compute y from x - uncompress_coords(recid % 2, &cp.x, &cp.y); + uncompress_coords(&secp256k1, recid % 2, &cp.x, &cp.y); // calculate hash sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); @@ -136,13 +143,13 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ sha256_Raw(hash, 32, hash); // e = -hash bn_read_be(hash, &e); - bn_subtract(&order256k1, &e, &e); + bn_subtract(&secp256k1.order, &e, &e); // r = r^-1 - bn_inverse(&r, &order256k1); - point_multiply(&s, &cp, &cp); - scalar_multiply(&e, &cp2); - point_add(&cp2, &cp); - point_multiply(&r, &cp, &cp); + bn_inverse(&r, &secp256k1.order); + point_multiply(&secp256k1, &s, &cp, &cp); + scalar_multiply(&secp256k1, &e, &cp2); + point_add(&secp256k1, &cp2, &cp); + point_multiply(&secp256k1, &r, &cp, &cp); pubkey[0] = 0x04; bn_write_be(&cp.x, pubkey + 1); bn_write_be(&cp.y, pubkey + 33); @@ -155,7 +162,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ return 2; } // check if signature verifies the digest - if (ecdsa_verify_digest(pubkey, signature + 1, hash) != 0) { + if (ecdsa_verify_digest(&secp256k1, pubkey, signature + 1, hash) != 0) { return 3; } return 0; @@ -181,16 +188,16 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz // generate random nonce curve_point R; bignum256 k; - if (generate_k_random(&k) != 0) { + if (generate_k_random(&secp256k1, &k) != 0) { return 2; } // compute k*G - scalar_multiply(&k, &R); + scalar_multiply(&secp256k1, &k, &R); nonce[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, nonce + 1); *nonce_len = 33; // compute shared secret - point_multiply(&k, pubkey, &R); + point_multiply(&secp256k1, &k, pubkey, &R); uint8_t shared_secret[33]; shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, shared_secret + 1); @@ -222,7 +229,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le curve_point R; bignum256 k; bn_read_be(privkey, &k); - point_multiply(&k, nonce, &R); + point_multiply(&secp256k1, &k, nonce, &R); uint8_t shared_secret[33]; shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); bn_write_be(&R.x, shared_secret + 1); diff --git a/firmware/crypto.h b/firmware/crypto.h index 89878003c7..b9d03fde8a 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include "types.pb.h" @@ -32,6 +32,8 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); +int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); + int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 332733d5a5..a3d6e314f6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -44,6 +44,8 @@ #include "base58.h" #include "bip39.h" #include "ripemd160.h" +#include "secp256k1.h" +#include "nist256p1.h" // message methods @@ -285,6 +287,17 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; + uint8_t public_key[33]; // copy public key to temporary buffer + memcpy(public_key, node->public_key, sizeof(public_key)); + + if (msg->has_ecdsa_curve_name) { + const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); + if (curve) { + // correct public key (since fsm_getDerivedNode uses secp256k1 curve) + ecdsa_get_public_key33(curve, node->private_key, public_key); + } + } + resp->node.depth = node->depth; resp->node.fingerprint = node->fingerprint; resp->node.child_num = node->child_num; @@ -293,7 +306,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.has_private_key = false; resp->node.has_public_key = true; resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, node->public_key, 33); + memcpy(resp->node.public_key.bytes, public_key, 33); resp->has_xpub = true; hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); @@ -662,6 +675,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutHome(); return; } + uint32_t address_n[5]; address_n[0] = 0x80000000 | 13; address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); @@ -672,20 +686,51 @@ void fsm_msgSignIdentity(SignIdentity *msg) const HDNode *node = fsm_getDerivedNode(address_n, 5); if (!node) return; - uint8_t message[256 + 256]; - memcpy(message, msg->challenge_hidden.bytes, msg->challenge_hidden.size); - const int len = strlen(msg->challenge_visual); - memcpy(message + msg->challenge_hidden.size, msg->challenge_visual, len); + uint8_t public_key[33]; // copy public key to temporary buffer + memcpy(public_key, node->public_key, sizeof(public_key)); - layoutProgressSwipe("Signing", 0); - if (cryptoMessageSign(message, msg->challenge_hidden.size + len, node->private_key, resp->signature.bytes) == 0) { - resp->has_address = true; - uint8_t addr_raw[21]; - ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type - base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); + if (msg->has_ecdsa_curve_name) { + const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); + if (curve) { + // correct public key (since fsm_getDerivedNode uses secp256k1 curve) + ecdsa_get_public_key33(curve, node->private_key, public_key); + } + } + + bool sign_ssh = false; + if (msg->identity.has_proto) { + sign_ssh = (strcmp(msg->identity.proto, "ssh") == 0); + } + + uint8_t message_bytes[256 + 256]; + memcpy(message_bytes, msg->challenge_hidden.bytes, msg->challenge_hidden.size); + int message_size = msg->challenge_hidden.size; + + int result = 0; + if (sign_ssh) { + // SSH doesn't sign visual challenge. + layoutProgressSwipe("Signing SSH", 0); + result = sshMessageSign(message_bytes, message_size, node->private_key, resp->signature.bytes); + } else { + const int len = strlen(msg->challenge_visual); + memcpy(message_bytes + message_size, msg->challenge_visual, len); + message_size = message_size + len; + layoutProgressSwipe("Signing", 0); + result = cryptoMessageSign(message_bytes, message_size, node->private_key, resp->signature.bytes); + } + + if (result == 0) { + if (sign_ssh) { + resp->has_address = false; + } else { + resp->has_address = true; + uint8_t addr_raw[21]; + ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type + base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); + } resp->has_public_key = true; resp->public_key.size = 33; - memcpy(resp->public_key.bytes, node->public_key, 33); + memcpy(resp->public_key.bytes, public_key, 33); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); @@ -706,7 +751,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) return; } curve_point pubkey; - if (msg->pubkey.size != 33 || ecdsa_read_pubkey(msg->pubkey.bytes, &pubkey) == 0) { + if (msg->pubkey.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 0) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); return; } @@ -729,7 +774,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; uint8_t public_key[33]; - ecdsa_get_public_key33(node->private_key, public_key); + ecdsa_get_public_key33(&secp256k1, node->private_key, public_key); ecdsa_get_address_raw(public_key, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); @@ -766,7 +811,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) return; } curve_point nonce_pubkey; - if (msg->nonce.size != 33 || ecdsa_read_pubkey(msg->nonce.bytes, &nonce_pubkey) == 0) { + if (msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); return; } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index a322f98601..1a4b194baa 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -25,6 +25,7 @@ PassphraseAck.passphrase max_size:51 Entropy.entropy max_size:1024 GetPublicKey.address_n max_count:8 +GetPublicKey.ecdsa_curve_name max_size:32 PublicKey.xpub max_size:113 @@ -88,6 +89,7 @@ SignTx.coin_name max_size:17 SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 +SignIdentity.ecdsa_curve_name max_size:32 SignedIdentity.address max_size:36 SignedIdentity.public_key max_size:33 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 8823d70f96..c5737d6e8a 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -123,8 +123,9 @@ const pb_field_t Entropy_fields[2] = { PB_LAST_FIELD }; -const pb_field_t GetPublicKey_fields[2] = { +const pb_field_t GetPublicKey_fields[3] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), + PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0), PB_LAST_FIELD }; @@ -304,10 +305,11 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t SignIdentity_fields[4] = { +const pb_field_t SignIdentity_fields[5] = { PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_visual, challenge_hidden, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SignIdentity, ecdsa_curve_name, challenge_visual, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index b867cc947d..ea39b1c597 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -417,6 +417,8 @@ typedef struct _GetEntropy { typedef struct _GetPublicKey { size_t address_n_count; uint32_t address_n[8]; + bool has_ecdsa_curve_name; + char ecdsa_curve_name[32]; } GetPublicKey; typedef struct _LoadDevice { @@ -520,6 +522,8 @@ typedef struct _SignIdentity { SignIdentity_challenge_hidden_t challenge_hidden; bool has_challenge_visual; char challenge_visual[256]; + bool has_ecdsa_curve_name; + char ecdsa_curve_name[32]; } SignIdentity; typedef struct { @@ -650,7 +654,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define PassphraseAck_init_default {""} #define GetEntropy_init_default {0} #define Entropy_init_default {{0, {0}}} -#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} #define PublicKey_init_default {HDNodeType_init_default, false, ""} #define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} #define Address_init_default {""} @@ -677,7 +681,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin"} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} -#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} +#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_default {0} #define FirmwareUpload_init_default {{0, {0}}} @@ -704,7 +708,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define PassphraseAck_init_zero {""} #define GetEntropy_init_zero {0} #define Entropy_init_zero {{0, {0}}} -#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} +#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} #define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} #define Address_init_zero {""} @@ -731,7 +735,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} -#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} +#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_zero {0} #define FirmwareUpload_init_zero {{0, {0}}} @@ -816,6 +820,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define GetAddress_multisig_tag 4 #define GetEntropy_size_tag 1 #define GetPublicKey_address_n_tag 1 +#define GetPublicKey_ecdsa_curve_name_tag 2 #define LoadDevice_mnemonic_tag 1 #define LoadDevice_node_tag 2 #define LoadDevice_pin_tag 3 @@ -849,6 +854,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SignIdentity_identity_tag 1 #define SignIdentity_challenge_hidden_tag 2 #define SignIdentity_challenge_visual_tag 3 +#define SignIdentity_ecdsa_curve_name_tag 4 #define SignMessage_address_n_tag 1 #define SignMessage_message_tag 2 #define SignMessage_coin_name_tag 3 @@ -892,7 +898,7 @@ extern const pb_field_t PassphraseRequest_fields[1]; extern const pb_field_t PassphraseAck_fields[2]; extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; -extern const pb_field_t GetPublicKey_fields[2]; +extern const pb_field_t GetPublicKey_fields[3]; extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[5]; extern const pb_field_t Address_fields[2]; @@ -919,7 +925,7 @@ extern const pb_field_t SignTx_fields[4]; extern const pb_field_t SimpleSignTx_fields[5]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; -extern const pb_field_t SignIdentity_fields[4]; +extern const pb_field_t SignIdentity_fields[5]; extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t FirmwareErase_fields[1]; extern const pb_field_t FirmwareUpload_fields[2]; @@ -948,7 +954,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define PassphraseAck_size 53 #define GetEntropy_size 6 #define Entropy_size 1027 -#define GetPublicKey_size 48 +#define GetPublicKey_size 82 #define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size (75 + MultisigRedeemScriptType_size) #define Address_size 38 @@ -975,7 +981,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) -#define SignIdentity_size (524 + IdentityType_size) +#define SignIdentity_size (558 + IdentityType_size) #define SignedIdentity_size 140 #define FirmwareErase_size 0 #define FirmwareUpload_size 2 diff --git a/firmware/signing.c b/firmware/signing.c index ca6a6682df..289315bc37 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -25,6 +25,7 @@ #include "ecdsa.h" #include "protect.h" #include "crypto.h" +#include "secp256k1.h" static uint32_t inputs_count; static uint32_t outputs_count; @@ -536,7 +537,7 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(privkey, hash, sig, 0); + ecdsa_sign_digest(&secp256k1, privkey, hash, sig, 0); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (input.script_type == InputScriptType_SPENDMULTISIG) { if (!input.has_multisig) { diff --git a/trezor-common b/trezor-common index e96ec085d5..12288143f5 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit e96ec085d55c20eccecb47e0a55b33295164de6d +Subproject commit 12288143f563cc51e4ae1d990de08db3add87380 diff --git a/trezor-crypto b/trezor-crypto index a757693fe3..7c58fc11a4 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit a757693fe3904f60d80d36fe0bfe437dea55e02e +Subproject commit 7c58fc11a46361476e3a7862816adb0671de6a74 From 381f90b38adb7dd0a9f12d9965a22994a4ff8454 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 27 Jun 2015 10:20:19 +0300 Subject: [PATCH 0147/1154] cryptoMessageSign() should check the return value of ecdsa_sign_digest() --- firmware/crypto.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index a78aa4002e..9a439bad88 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -96,9 +96,11 @@ int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t sha256_Final(hash, &ctx); sha256_Raw(hash, 32, hash); uint8_t pby; - ecdsa_sign_digest(privkey, hash, signature + 1, &pby); - signature[0] = 27 + pby + 4; - return 0; + int result = ecdsa_sign_digest(&secp256k1, privkey, hash, signature + 1, &pby); + if (result == 0) { + signature[0] = 27 + pby + 4; + } + return result; } int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) From 551741c67a1121603615a04f022eea7164f31e4c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 28 Jun 2015 21:28:00 +0200 Subject: [PATCH 0148/1154] update submodules --- .gitmodules | 4 ++-- trezor-common | 2 +- trezor-crypto | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitmodules b/.gitmodules index 4dcf3d77e0..97aef8fa1c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "trezor-crypto"] path = trezor-crypto - url = https://github.com/romanz/trezor-crypto.git + url = https://github.com/trezor/trezor-crypto.git [submodule "trezor-common"] path = trezor-common - url = https://github.com/romanz/trezor-common.git + url = https://github.com/trezor/trezor-common.git [submodule "trezor-qrenc"] path = trezor-qrenc url = https://github.com/trezor/trezor-qrenc.git diff --git a/trezor-common b/trezor-common index 12288143f5..d334bbf740 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 12288143f563cc51e4ae1d990de08db3add87380 +Subproject commit d334bbf740fee0cef02010945c1e904bb5f1aae9 diff --git a/trezor-crypto b/trezor-crypto index 7c58fc11a4..71c24673ce 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 7c58fc11a46361476e3a7862816adb0671de6a74 +Subproject commit 71c24673ced80c83dc90539364fa1dbeeb12ee6d From eaf209d9992965edbe919272d69b294b9af87c31 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Jun 2015 16:36:50 +0200 Subject: [PATCH 0149/1154] implement CipherKeyValue.iv field --- firmware/fsm.c | 4 ++-- firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 16 ++++++++++++---- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index a3d6e314f6..cabcd82558 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -445,11 +445,11 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) if (encrypt) { aes_encrypt_ctx ctx; aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); } else { aes_decrypt_ctx ctx; aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); } resp->has_value = true; resp->value.size = msg->value.size; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 1a4b194baa..50499abcfe 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -80,6 +80,7 @@ DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 CipherKeyValue.key max_size:256 CipherKeyValue.value max_size:1024 +CipherKeyValue.iv max_size:16 CipheredKeyValue.value max_size:1024 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index c5737d6e8a..784210876c 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -251,13 +251,14 @@ const pb_field_t DecryptedMessage_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CipherKeyValue_fields[7] = { +const pb_field_t CipherKeyValue_fields[8] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), + PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, iv, ask_on_decrypt, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index ea39b1c597..b82a54cea4 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -154,6 +154,11 @@ typedef struct { uint8_t bytes[1024]; } CipherKeyValue_value_t; +typedef struct { + size_t size; + uint8_t bytes[16]; +} CipherKeyValue_iv_t; + typedef struct _CipherKeyValue { size_t address_n_count; uint32_t address_n[8]; @@ -167,6 +172,8 @@ typedef struct _CipherKeyValue { bool ask_on_encrypt; bool has_ask_on_decrypt; bool ask_on_decrypt; + bool has_iv; + CipherKeyValue_iv_t iv; } CipherKeyValue; typedef struct { @@ -673,7 +680,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define EncryptedMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define DecryptMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define DecryptedMessage_init_default {false, {0, {0}}, false, ""} -#define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0} +#define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_default {false, {0, {0}}} #define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} #define TxSize_init_default {false, 0} @@ -727,7 +734,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define EncryptedMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define DecryptMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define DecryptedMessage_init_zero {false, {0, {0}}, false, ""} -#define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0} +#define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_zero {false, {0, {0}}} #define EstimateTxSize_init_zero {0, 0, false, ""} #define TxSize_init_zero {false, 0} @@ -760,6 +767,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define CipherKeyValue_encrypt_tag 4 #define CipherKeyValue_ask_on_encrypt_tag 5 #define CipherKeyValue_ask_on_decrypt_tag 6 +#define CipherKeyValue_iv_tag 7 #define CipheredKeyValue_value_tag 1 #define DebugLinkDecision_yes_no_tag 1 #define DebugLinkLog_level_tag 1 @@ -917,7 +925,7 @@ extern const pb_field_t EncryptMessage_fields[6]; extern const pb_field_t EncryptedMessage_fields[4]; extern const pb_field_t DecryptMessage_fields[5]; extern const pb_field_t DecryptedMessage_fields[3]; -extern const pb_field_t CipherKeyValue_fields[7]; +extern const pb_field_t CipherKeyValue_fields[8]; extern const pb_field_t CipheredKeyValue_fields[2]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; @@ -973,7 +981,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define EncryptedMessage_size 1168 #define DecryptMessage_size 1216 #define DecryptedMessage_size 1065 -#define CipherKeyValue_size 1340 +#define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 #define TxSize_size 6 From 104369d97bf523e385005daa8a35ba4d64c3e34d Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 4 Jul 2015 14:49:30 +0300 Subject: [PATCH 0150/1154] firmware-docker-build: revert branch and repository --- firmware-docker-build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 5df459a3a5..f705c8ffbd 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,10 +1,10 @@ #!/bin/bash IMAGETAG=trezor-mcu-build -FIRMWARETAG="ssh-agent" +FIRMWARETAG=${1:-master} docker build -t $IMAGETAG . docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ - git clone https://github.com/romanz/trezor-mcu && \ + git clone https://github.com/trezor/trezor-mcu && \ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ From e4d86a49ab7ab09fb937e3a40fe6be79f18f439d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 4 Jul 2015 23:34:26 +0200 Subject: [PATCH 0151/1154] rework SignIdentity signing --- firmware/fsm.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index cabcd82558..db81f50224 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -697,26 +697,18 @@ void fsm_msgSignIdentity(SignIdentity *msg) } } - bool sign_ssh = false; - if (msg->identity.has_proto) { - sign_ssh = (strcmp(msg->identity.proto, "ssh") == 0); - } - - uint8_t message_bytes[256 + 256]; - memcpy(message_bytes, msg->challenge_hidden.bytes, msg->challenge_hidden.size); - int message_size = msg->challenge_hidden.size; + bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); int result = 0; - if (sign_ssh) { - // SSH doesn't sign visual challenge. + if (sign_ssh) { // SSH does not sign visual challenge layoutProgressSwipe("Signing SSH", 0); - result = sshMessageSign(message_bytes, message_size, node->private_key, resp->signature.bytes); + result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); } else { - const int len = strlen(msg->challenge_visual); - memcpy(message_bytes + message_size, msg->challenge_visual, len); - message_size = message_size + len; + uint8_t digest[64]; + sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); + sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); layoutProgressSwipe("Signing", 0); - result = cryptoMessageSign(message_bytes, message_size, node->private_key, resp->signature.bytes); + result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes); } if (result == 0) { From 9ae7d6bf657b382c5b44a0f8e6f658547d98d5c3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 4 Jul 2015 23:45:57 +0200 Subject: [PATCH 0152/1154] simplify layout Dialog in SignIdentity --- firmware/fsm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index db81f50224..837dc5fac1 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -700,14 +700,13 @@ void fsm_msgSignIdentity(SignIdentity *msg) bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); int result = 0; + layoutProgressSwipe("Signing", 0); if (sign_ssh) { // SSH does not sign visual challenge - layoutProgressSwipe("Signing SSH", 0); result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); } else { uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - layoutProgressSwipe("Signing", 0); result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes); } From 39e29c1037efd8905719786d5cb53381bb50fc46 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 7 Jul 2015 18:36:54 +0200 Subject: [PATCH 0153/1154] use -O3 instead of -Os --- Makefile.include | 2 +- bootloader/signatures.c | 7 ++++--- trezor-crypto | 2 +- trezor-qrenc | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile.include b/Makefile.include index d63a35c690..af22f3f4bb 100644 --- a/Makefile.include +++ b/Makefile.include @@ -9,7 +9,7 @@ OBJDUMP = $(PREFIX)objdump FLASH = st-flash OPENOCD = openocd -OPTFLAGS = -Os -g -DNDEBUG +OPTFLAGS = -O3 -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ -W \ diff --git a/bootloader/signatures.c b/bootloader/signatures.c index db9601b22f..85e921666f 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -21,6 +21,7 @@ #include "signatures.h" #include "ecdsa.h" +#include "secp256k1.h" #include "bootloader.h" #define PUBKEYS 5 @@ -52,13 +53,13 @@ int signatures_ok(void) if (sigindex1 == sigindex3) return 0; // duplicate use if (sigindex2 == sigindex3) return 0; // duplicate use - if (ecdsa_verify(pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + if (ecdsa_verify(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure return 0; } - if (ecdsa_verify(pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + if (ecdsa_verify(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure return 0; } - if (ecdsa_verify(pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture + if (ecdsa_verify(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture return 0; } diff --git a/trezor-crypto b/trezor-crypto index 71c24673ce..5ec72d3a5b 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 71c24673ced80c83dc90539364fa1dbeeb12ee6d +Subproject commit 5ec72d3a5ba1aa6b7c7c907d7e2059b6c9a8a690 diff --git a/trezor-qrenc b/trezor-qrenc index 1da1cedfd6..1183aa7146 160000 --- a/trezor-qrenc +++ b/trezor-qrenc @@ -1 +1 @@ -Subproject commit 1da1cedfd6bbd08784a3a4d7d6310b46830893cb +Subproject commit 1183aa714615dfaa9cfb771bca7ec8c11929a4c2 From e8b47901ced42fd437d27261a3fcd354f0fb0495 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 9 Jul 2015 22:58:05 +0200 Subject: [PATCH 0154/1154] show "Go to myTREZOR.com" instead of label when device is not initialized --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 51bc154408..bb2b945cc8 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -64,7 +64,7 @@ void layoutHome(void) oledSwipeLeft(); } layoutLast = layoutHome; - const char *label = storage_getLabel(); + const char *label = storage_isInitialized() ? storage_getLabel() : "Go to mytrezor.com"; const uint8_t *homescreen = storage_getHomescreen(); if (homescreen) { BITMAP b; From a8db9989c688c9d16f3701cc06d9a60c56ef60ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 22 Jul 2015 17:33:10 +0200 Subject: [PATCH 0155/1154] update trezor-common --- trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezor-common b/trezor-common index d334bbf740..3fc31bfe9c 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit d334bbf740fee0cef02010945c1e904bb5f1aae9 +Subproject commit 3fc31bfe9c42ebf3c0a63c48f44537994787f9c9 From e876aa5094eb9bc864c4cb77745491197c89e57c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 29 Jul 2015 15:38:00 +0200 Subject: [PATCH 0156/1154] changed coin max fees --- firmware/coins.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 1c33addc38..1200b118b6 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,12 +21,12 @@ #include "coins.h" const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 10000, true, 5}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, - {true, "Litecoin", true, "LTC", true, 48, true, 10000000, true, 5}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 100000000, true, 22}, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16}, + {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22}, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16}, }; const CoinType *coinByShortcut(const char *shortcut) From b678ba8811b74e57988af741ff20aac5475feb10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Aug 2015 19:07:31 +0200 Subject: [PATCH 0157/1154] update protob --- firmware/protob/messages.pb.c | 2 +- firmware/protob/messages.pb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 784210876c..3a49ebf04c 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -5,7 +5,7 @@ const char GetAddress_coin_name_default[17] = "Bitcoin"; const char LoadDevice_language_default[17] = "english"; -const uint32_t ResetDevice_strength_default = 128u; +const uint32_t ResetDevice_strength_default = 256u; const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index b82a54cea4..3f942e5bc5 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -667,7 +667,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define Address_init_default {""} #define WipeDevice_init_default {0} #define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} -#define ResetDevice_init_default {false, 0, false, 128u, false, 0, false, 0, false, "english", false, ""} +#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, ""} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} #define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0} From 0c6b3e26e20d81f6aaed109755d8fa28d9e2dd74 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Aug 2015 19:10:46 +0200 Subject: [PATCH 0158/1154] prepare 1.3.4 release --- Dockerfile | 4 ++-- firmware/trezor.h | 2 +- firmware/usb.c | 3 +-- trezor-crypto | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4123d71a1d..4cb96cdff5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:14.04 -ENV GCC_ARM_VERSION 4.9.3.2015q1-0trusty13 +ENV GCC_ARM_VERSION 4.9.3.2015q2-1trusty1 # add and update package repositories @@ -21,5 +21,5 @@ RUN git clone https://github.com/libopencm3/libopencm3 # build libopencm3 -ENV LIBOPENCM3_GITREV 7dbb93c78411b37bec64b5ca5be55076b0ab1b15 +ENV LIBOPENCM3_GITREV 7b29caed1a726b5cef4c269b6a6ef7a1f1dd105c RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make diff --git a/firmware/trezor.h b/firmware/trezor.h index 15999b831b..a9cf8b83e4 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 3 +#define VERSION_PATCH 4 #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/firmware/usb.c b/firmware/usb.c index 03baabd791..102b573da3 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -227,8 +227,7 @@ static const char *usb_strings[] = { (const char *)storage_uuid_str, }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; (void)dev; diff --git a/trezor-crypto b/trezor-crypto index 5ec72d3a5b..d659fd49a5 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit 5ec72d3a5ba1aa6b7c7c907d7e2059b6c9a8a690 +Subproject commit d659fd49a56992c8e903f7957bd3b221e3bc0f12 From db93a50f76204418a2cf7d2c7e0391f486729bf3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Aug 2015 00:45:59 +0200 Subject: [PATCH 0159/1154] update trezor-crypto --- trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezor-crypto b/trezor-crypto index d659fd49a5..cbbc0bdc71 160000 --- a/trezor-crypto +++ b/trezor-crypto @@ -1 +1 @@ -Subproject commit d659fd49a56992c8e903f7957bd3b221e3bc0f12 +Subproject commit cbbc0bdc7197e74d647aedcbfd064c43544318cf From ec98e58bce111bc68f304f2bb0981a169b81b63f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Aug 2015 16:38:53 +0200 Subject: [PATCH 0160/1154] simplify Dockerfile, add travis CI --- .travis.yml | 17 +++++++++++++++++ Dockerfile | 11 +++-------- README.md | 28 ++++++++++++++++++++++++++++ README.rst | 26 -------------------------- 4 files changed, 48 insertions(+), 34 deletions(-) create mode 100644 .travis.yml create mode 100644 README.md delete mode 100644 README.rst diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..6a12e14ef8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +sudo: false +language: c + +addons: + apt: + packages: + - build-essential + - git + - gcc-arm-none-eabi + +install: + - git clone https://github.com/libopencm3/libopencm3 + +script: + - cd libopencm3; make; cd .. + - TOOLCHAIN_DIR=libopencm3 make + - cd firmware; TOOLCHAIN_DIR=libopencm3 make; cd .. diff --git a/Dockerfile b/Dockerfile index 4cb96cdff5..adb7f76fbf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,18 +2,13 @@ FROM ubuntu:14.04 -ENV GCC_ARM_VERSION 4.9.3.2015q2-1trusty1 +# update repositories -# add and update package repositories - -RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FE324A81C208C89497EFC6246D1D8367A3421AFB -RUN gpg --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --fingerprint FE324A81C208C89497EFC6246D1D8367A3421AFB -RUN echo "deb http://ppa.launchpad.net/terry.guo/gcc-arm-embedded/ubuntu trusty main" >> /etc/apt/sources.list && apt-get update +RUN apt-get update # install build tools and dependencies -RUN apt-get install -y build-essential git python -RUN apt-get install -y gcc-arm-none-eabi=$GCC_ARM_VERSION +RUN apt-get install -y build-essential git python gcc-arm-none-eabi # clone the source code diff --git a/README.md b/README.md new file mode 100644 index 0000000000..5c5786626c --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +TREZOR Firmware +=============== + +[![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) + +http://bitcointrezor.com/ + +How to build TREZOR firmware? +----------------------------- + +1. Install Docker (from docker.com or from your distribution repositories) +2. `git clone https://github.com/trezor/trezor-mcu.git` +3. `cd trezor-mcu` +4. `./firmware-docker-build.sh TAG` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) + +This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log. + +How to get fingerprint of firmware signed and distributed by SatoshiLabs? +------------------------------------------------------------------------- + +1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json +2. Download it: `wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex` +3. `xxd -r -p trezor.signed.bin.hex trezor.signed.bin` +4. `./firmware-fingerprint.sh trezor.signed.bin` + +Step 4 should produce the same sha256 fingerprint like your local build (for the same version tag). + +The reasoning for `firmware-fingerprint.sh` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. diff --git a/README.rst b/README.rst deleted file mode 100644 index 9ba8eba5f4..0000000000 --- a/README.rst +++ /dev/null @@ -1,26 +0,0 @@ -TREZOR Firmware -=============== - -http://bitcointrezor.com/ - -How to build Trezor firmware? ------------------------------ - -1. Install Docker (from docker.com or from your distribution repositories) -2. ``git clone https://github.com/trezor/trezor-mcu.git`` -3. ``cd trezor-mcu`` -4. ``./firmware-docker-build.sh TAG`` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) - -This creates file ``output/trezor-TAG.bin`` and prints its fingerprint at the last line of the build log. - -How to get fingerprint of firmware signed and distributed by SatoshiLabs? -------------------------------------------------------------------------- - -1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json -2. Download it: ``wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex`` -3. ``xxd -r -p trezor.signed.bin.hex trezor.signed.bin`` -4. ``./firmware-fingerprint.sh trezor.signed.bin`` - -Step 4 should produce the same sha256 fingerprint like your local build (for the same version tag). - -The reasoning for ``firmware-fingerprint.sh`` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. From 90171e0aa6056b82df6a0211126c8dc4c3469f31 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Aug 2015 16:57:23 +0200 Subject: [PATCH 0161/1154] update bootloader and demo to new usb api --- .travis.yml | 4 +++- bootloader/Makefile | 16 +++++++--------- bootloader/usb.c | 3 +-- demo/demo.c | 16 ++++++++++++---- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a12e14ef8..8db60b8fcb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,4 +14,6 @@ install: script: - cd libopencm3; make; cd .. - TOOLCHAIN_DIR=libopencm3 make - - cd firmware; TOOLCHAIN_DIR=libopencm3 make; cd .. + - cd firmware; TOOLCHAIN_DIR=../libopencm3 make; cd .. + - cd bootloader; TOOLCHAIN_DIR=../libopencm3 make; cd .. + - cd demo; TOOLCHAIN_DIR=../libopencm3 make; cd .. diff --git a/bootloader/Makefile b/bootloader/Makefile index 498bdd16bc..1d87042ca2 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -1,22 +1,20 @@ NAME = bootloader -MCU_DIR=$(subst /bootloader,,$(PWD)) - OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o -OBJS += $(MCU_DIR)/trezor-crypto/bignum.o -OBJS += $(MCU_DIR)/trezor-crypto/ecdsa.small.o -OBJS += $(MCU_DIR)/trezor-crypto/hmac.o -OBJS += $(MCU_DIR)/trezor-crypto/ripemd160.o -OBJS += $(MCU_DIR)/trezor-crypto/secp256k1.small.o -OBJS += $(MCU_DIR)/trezor-crypto/sha2.o +OBJS += ../trezor-crypto/bignum.o +OBJS += ../trezor-crypto/ecdsa.small.o +OBJS += ../trezor-crypto/hmac.o +OBJS += ../trezor-crypto/ripemd160.o +OBJS += ../trezor-crypto/secp256k1.small.o +OBJS += ../trezor-crypto/sha2.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 -include $(MCU_DIR)/Makefile.include +include ../Makefile.include align: ./firmware_align.py $(NAME).bin diff --git a/bootloader/usb.c b/bootloader/usb.c index 4de353c030..94c93fcc2e 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -187,8 +187,7 @@ static const char *usb_strings[] = { "", // empty serial }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; (void)dev; diff --git a/demo/demo.c b/demo/demo.c index 0682e7ca7b..51242d650a 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -25,9 +25,9 @@ #include "layout.h" #include "oled.h" #include "setup.h" -//#include "util.h" #include "hmac.h" #include "pbkdf2.h" +#include "rng.h" const int states = 2; int state = 0; @@ -192,8 +192,7 @@ static const char *usb_strings[] = { "01234567", }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, - void (**complete)(usbd_device *, struct usb_setup_data *)) +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; (void)dev; @@ -239,8 +238,17 @@ void usbInit(void) usbd_register_set_config_callback(usbd_dev, hid_set_config); } +uint32_t __stack_chk_guard; + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever +} + int main(void) { + __stack_chk_guard = random32(); #ifndef APPVER setup(); oledInit(); @@ -264,7 +272,7 @@ int main(void) usbd_poll(usbd_dev); switch (state) { case 1: - layoutProgress("WORKING", frame % 41 * 25, frame % 4); + layoutProgress("WORKING", frame % 41 * 25); pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64, NULL); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); break; From f6820ad5f63e692cbf519e5b156b7d0ad28ff68b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Aug 2015 17:05:24 +0200 Subject: [PATCH 0162/1154] gcc-arm-none-eabi is not available in travis yet, install manually --- .travis.yml | 19 +++++++------------ Makefile.include | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8db60b8fcb..06d332fd7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,14 @@ -sudo: false language: c -addons: - apt: - packages: - - build-essential - - git - - gcc-arm-none-eabi - install: + - sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y + - sudo apt-get update + - sudo apt-get install -y build-essential git gcc-arm-none-eabi - git clone https://github.com/libopencm3/libopencm3 script: - - cd libopencm3; make; cd .. + - make -C libopencm3 - TOOLCHAIN_DIR=libopencm3 make - - cd firmware; TOOLCHAIN_DIR=../libopencm3 make; cd .. - - cd bootloader; TOOLCHAIN_DIR=../libopencm3 make; cd .. - - cd demo; TOOLCHAIN_DIR=../libopencm3 make; cd .. + - TOOLCHAIN_DIR=../libopencm3 make -C firmware + - TOOLCHAIN_DIR=../libopencm3 make -C bootloader + - TOOLCHAIN_DIR=../libopencm3 make -C demo diff --git a/Makefile.include b/Makefile.include index af22f3f4bb..8505ffc865 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,5 +1,5 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -TOOLCHAIN_DIR := $(TOP_DIR)/../libopencm3 +TOOLCHAIN_DIR ?= $(TOP_DIR)/../libopencm3 PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc From 8b1f8a4595ffe9db5718a43297ebfcbf26bdb9cf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Aug 2015 17:04:38 +0200 Subject: [PATCH 0163/1154] show "Web sign in to" when HTTPS is detected --- firmware/layout2.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index bb2b945cc8..2ede4a9e34 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -277,10 +277,14 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) char row_user[64 + 8 + 1]; if (identity->has_proto && identity->proto[0]) { - strlcpy(row_proto, identity->proto, sizeof(row_proto)); - char *p = row_proto; - while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, " login to:", sizeof(row_proto)); + if (strcmp(identity->proto, "https") == 0) { + strlcpy(row_proto, "Web sign in to:", sizeof(row_proto)); + } else { + strlcpy(row_proto, identity->proto, sizeof(row_proto)); + char *p = row_proto; + while (*p) { *p = toupper((int)*p); p++; } + strlcat(row_proto, " login to:", sizeof(row_proto)); + } } else { strlcpy(row_proto, "Login to:", sizeof(row_proto)); } From 1bb00adc37479070c2d9a3c767c95304881a0db8 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 24 Aug 2015 13:47:27 +0300 Subject: [PATCH 0164/1154] fsm: add compile-time assert for response size validation ttps://gcc.gnu.org/gcc-4.6/changes.html --- firmware/fsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 837dc5fac1..fa9a5d94e1 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -51,7 +51,9 @@ static uint8_t msg_resp[MSG_OUT_SIZE]; -#define RESP_INIT(TYPE) TYPE *resp = (TYPE *)msg_resp; memset(resp, 0, sizeof(TYPE)); +#define RESP_INIT(TYPE) TYPE *resp = (TYPE *)msg_resp; \ + _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ + memset(resp, 0, sizeof(TYPE)); void fsm_sendSuccess(const char *text) { From 755b0388f0dbbd25db9e21a04bf59b1be4e4332a Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 24 Aug 2015 15:42:11 +0300 Subject: [PATCH 0165/1154] firmware: exclude debug functionality from release build --- firmware/pinmatrix.c | 4 ++++ firmware/recovery.c | 4 ++++ firmware/reset.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 73ae3b4052..85d5ef7ed2 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -73,7 +73,11 @@ void pinmatrix_done(char *pin) memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm)); } +#if DEBUG_LINK + const char *pinmatrix_get(void) { return pinmatrix_perm; } + +#endif diff --git a/firmware/recovery.c b/firmware/recovery.c index 48213e0d6e..bd5bda70f7 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -169,6 +169,8 @@ void recovery_abort(void) } } +#if DEBUG_LINK + const char *recovery_get_fake_word(void) { return fake_word; @@ -178,3 +180,5 @@ uint32_t recovery_get_word_pos(void) { return word_pos; } + +#endif diff --git a/firmware/reset.c b/firmware/reset.c index 56d4d95f18..7e75f96ee6 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -149,6 +149,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) layoutHome(); } +#if DEBUG_LINK + uint32_t reset_get_int_entropy(uint8_t *entropy) { memcpy(entropy, int_entropy, 32); return 32; @@ -157,3 +159,5 @@ uint32_t reset_get_int_entropy(uint8_t *entropy) { const char *reset_get_word(void) { return current_word; } + +#endif From 8372504238d6f63bd67573476bc4f90937ad4aea Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Aug 2015 19:50:04 +0200 Subject: [PATCH 0166/1154] show home screen on Initialize --- firmware/fsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index fa9a5d94e1..32b25e28a4 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -118,6 +118,7 @@ void fsm_msgInitialize(Initialize *msg) recovery_abort(); signing_abort(); session_clear(false); // do not clear PIN + layoutHome(); fsm_msgGetFeatures(0); } From c08ff09f0f453bf7f26dff33bd7d0f2726ca3a3b Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sun, 6 Sep 2015 21:14:23 +0300 Subject: [PATCH 0167/1154] storage: add compile-time assert for sizeof(Storage) validation --- firmware/storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/storage.c b/firmware/storage.c index a3e2f84ac2..d5f5bc9f9d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -39,6 +39,7 @@ #include "protect.h" #include "layout2.h" +_Static_assert(sizeof(Storage) <= FLASH_STORAGE_LEN, "Storage struct is too large for TREZOR flash"); Storage storage; uint8_t storage_uuid[12]; From 9328cad7f191de23c0891600d9a82c3b966762f0 Mon Sep 17 00:00:00 2001 From: Mark Bryars Date: Tue, 3 Nov 2015 00:08:18 +0100 Subject: [PATCH 0168/1154] Add U2F support --- firmware/Makefile | 1 + firmware/protob/storage.pb.c | 3 +- firmware/protob/storage.pb.h | 11 +- firmware/storage.c | 12 + firmware/storage.h | 2 + firmware/u2f.c | 725 +++++++++++++++++++++++++++++++++++ firmware/u2f.h | 58 +++ firmware/u2f/u2f.h | 141 +++++++ firmware/u2f/u2f_hid.h | 140 +++++++ firmware/u2f/u2f_keys.h | 46 +++ firmware/usb.c | 116 +++++- trezor-common | 2 +- 12 files changed, 1245 insertions(+), 12 deletions(-) create mode 100644 firmware/u2f.c create mode 100644 firmware/u2f.h create mode 100644 firmware/u2f/u2f.h create mode 100644 firmware/u2f/u2f_hid.h create mode 100644 firmware/u2f/u2f_keys.h diff --git a/firmware/Makefile b/firmware/Makefile index fa4aa3e16a..a321a77922 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -3,6 +3,7 @@ APPVER = 1.0.0 NAME = trezor OBJS += usb.o +OBJS += u2f.o OBJS += messages.o OBJS += storage.o OBJS += trezor.o diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 68da897f29..67f1619a8f 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -5,7 +5,7 @@ -const pb_field_t Storage_fields[11] = { +const pb_field_t Storage_fields[12] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -16,6 +16,7 @@ const pb_field_t Storage_fields[11] = { PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), + PB_FIELD2( 11, UINT32 , OPTIONAL, STATIC , OTHER, Storage, u2f_counter, homescreen, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 2f51923fd2..c5d942eb90 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -37,13 +37,15 @@ typedef struct _Storage { bool imported; bool has_homescreen; Storage_homescreen_t homescreen; + bool has_u2f_counter; + uint32_t u2f_counter; } Storage; /* Default values for struct fields */ /* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 @@ -56,12 +58,13 @@ typedef struct _Storage { #define Storage_label_tag 8 #define Storage_imported_tag 9 #define Storage_homescreen_tag 10 +#define Storage_u2f_counter_tag 11 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[11]; +extern const pb_field_t Storage_fields[12]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (1359 + HDNodeType_size) +#define Storage_size (1365 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/storage.c b/firmware/storage.c index d5f5bc9f9d..f28bce5891 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -401,3 +401,15 @@ bool storage_isInitialized(void) { return storage.has_node || storage.has_mnemonic; } + +uint32_t storage_nextU2FCounter(void) +{ + if(!storage.has_u2f_counter) { + storage.has_u2f_counter = true; + storage.u2f_counter = 1; + } else { + storage.u2f_counter++; + } + storage_commit(); + return storage.u2f_counter; +} diff --git a/firmware/storage.h b/firmware/storage.h index b1041a8b93..793c8c4ea3 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -58,6 +58,8 @@ void storage_resetPinFails(void); void storage_increasePinFails(void); uint32_t storage_getPinFails(void); +uint32_t storage_nextU2FCounter(void); + bool storage_isInitialized(void); extern Storage storage; diff --git a/firmware/u2f.c b/firmware/u2f.c new file mode 100644 index 0000000000..09f2ca810b --- /dev/null +++ b/firmware/u2f.c @@ -0,0 +1,725 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2015 Mark Bryars + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + + +#include +#include + +#include "debug.h" +#include "storage.h" +#include "bip32.h" +#include "layout2.h" +#include "usb.h" +#include "buttons.h" +#include "trezor.h" +#include "nist256p1.h" +#include "rng.h" + +#include "u2f/u2f.h" +#include "u2f/u2f_hid.h" +#include "u2f/u2f_keys.h" +#include "u2f.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +// About 1/2 Second according to values used in protect.c +#define U2F_TIMEOUT 840000/2 +#define U2F_OUT_PKT_BUFFER_LEN 128 + +// Initialise without a cid +static uint32_t cid = CID_BROADCAST; + +// Circular Output buffer +static uint32_t u2f_out_start = 0; +static uint32_t u2f_out_end = 0; +static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; + +#define U2F_PUBKEY_LEN 65 +#define KEY_HANDLE_LEN 64 + +// Auth/Register request state machine +typedef enum { + INIT = 0, + BTN_NO = 1, + BTN_YES = 2, + AUTH = 10, + AUTH_FAIL = 11, + AUTH_PASS = 12, + REG = 20, + REG_FAIL = 21, + REG_PASS = 22 +} U2F_STATE; + +static U2F_STATE last_req_state = INIT; + +typedef struct { + uint8_t reserved; + uint8_t appId[U2F_APPID_SIZE]; + uint8_t chal[U2F_CHAL_SIZE]; + uint8_t keyHandle[KEY_HANDLE_LEN]; + uint8_t pubKey[U2F_PUBKEY_LEN]; +} U2F_REGISTER_SIG_STR; + +typedef struct { + uint8_t appId[U2F_APPID_SIZE]; + uint8_t flags; + uint8_t ctr[4]; + uint8_t chal[U2F_CHAL_SIZE]; +} U2F_AUTHENTICATE_SIG_STR; + +uint8_t buttonState(void) +{ + buttonUpdate(); + + if ((button.NoDown > 10) || button.NoUp) + return BTN_NO; + if ((button.YesDown > 10) || button.YesUp) + return BTN_YES; + return 0; +} + +void int2hex(uint8_t *dst, const uint32_t i) +{ + dst[0] = '0' + ((i >> 28) & 0x0F); + dst[1] = '0' + ((i >> 24) & 0x0F); + dst[2] = '0' + ((i >> 20) & 0x0F); + dst[3] = '0' + ((i >> 16) & 0x0F); + dst[4] = '0' + ((i >> 12) & 0x0F); + dst[5] = '0' + ((i >> 8) & 0x0F); + dst[6] = '0' + ((i >> 4) & 0x0F); + dst[7] = '0' + (i & 0x0F); + dst[8] = '\0'; + + int t = 0; + for (; t < 8; t++) { + if (dst[t] > '9') + dst[t] += 7; // 'A'-'9'+1 + } +} + +char *debugInt(const uint32_t i) +{ + static uint8_t n = 0; + static uint8_t id[8][9]; + int2hex(id[n], i); + debugLog(0, "", (const char *)id[n]); + char *ret = (char *)id[n]; + n = (n + 1) % 8; + return ret; +} + +static uint32_t dialog_timeout = 0; + +void LayoutHomeAfterTimeout(void) +{ + static bool timeoutLock = false; + + if (timeoutLock || dialog_timeout == 0) + return; // Dialog has cleared or already in loop + + timeoutLock = true; + U2F_STATE rs = last_req_state; + U2F_STATE bs = INIT; + while (dialog_timeout-- && rs == last_req_state && bs == 0) { + usbPoll(); // may trigger new request + bs = buttonState(); + } + timeoutLock = false; + + if (rs != last_req_state) + return; // Reset by new request don't clear screen + + if (dialog_timeout == 0) { + last_req_state += BTN_NO; // Timeout is like button no + } + else { + last_req_state += bs; + dialog_timeout = 0; + } + + layoutHome(); +} + +uint32_t next_cid(void) +{ + // extremely unlikely but hey + do { + cid = random32(); + } while (cid == 0 || cid == CID_BROADCAST); + return cid; +} + +void u2fhid_read(const U2FHID_FRAME *f) +{ + static uint8_t seq, cmd; + static uint32_t len; + static uint8_t *buf_ptr; + static uint8_t buf[7609]; + + if ((f->cid != CID_BROADCAST) && (f->cid != cid)) { + return; // Not for us + } + + if (f->type & TYPE_INIT) { + seq = 0; + buf_ptr = buf; + len = MSG_LEN(*f); + cmd = f->type; + memcpy(buf_ptr, f->init.data, sizeof(f->init.data)); + buf_ptr += sizeof(f->init.data); + } + else { + if (f->cont.seq == seq) { + seq++; + memcpy(buf_ptr, f->cont.data, sizeof(f->cont.data)); + buf_ptr += sizeof(f->cont.data); + } + else { + return send_u2fhid_error(ERR_INVALID_SEQ); + } + } + + // Broadcast is reserved for init + if (cid == CID_BROADCAST && cmd != U2FHID_INIT) + return; + + // Check length isnt bigger than spec max + if (len > sizeof(buf)) + return send_u2fhid_error(ERR_INVALID_LEN); + + // Do we need to wait for more data + if ((buf_ptr - buf) < (signed)len) { + // debugLog(0, "", "u2fhid_read wait"); + return; + } + + // We have all the data + switch (cmd) { + case U2FHID_PING: + u2fhid_ping(buf, len); + break; + case U2FHID_MSG: + u2fhid_msg((APDU *)buf, len); + break; + case U2FHID_LOCK: + u2fhid_lock(buf, len); + break; + case U2FHID_INIT: + u2fhid_init((const U2FHID_INIT_REQ *)buf); + break; + case U2FHID_WINK: + u2fhid_wink(buf, len); + break; + // case U2FHID_SYNC: + // u2fhid_sync(buf, len); + break; + default: + send_u2fhid_error(ERR_INVALID_CMD); + break; + } +} + +void u2fhid_ping(const uint8_t *buf, uint32_t len) +{ + debugLog(0, "", "u2fhid_ping"); + send_u2fhid_msg(U2FHID_PING, buf, len); +} + +void u2fhid_wink(const uint8_t *buf, uint32_t len) +{ + debugLog(0, "", "u2fhid_wink"); + (void)buf; + + if (len > 0) + return send_u2fhid_error(ERR_INVALID_LEN); + + if (dialog_timeout > 0) + dialog_timeout = U2F_TIMEOUT; + + U2FHID_FRAME f; + bzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = U2FHID_WINK; + f.init.bcntl = 0; + queue_u2f_pkt(&f); +} + +void u2fhid_sync(const uint8_t *buf, uint32_t len) +{ + debugLog(0, "", "u2fhid_sync"); + (void)buf; + + if (len > 0) + return send_u2fhid_error(ERR_INVALID_LEN); + + // Abort things. + dialog_timeout = 0; +} + +void u2fhid_lock(const uint8_t *buf, uint32_t len) +{ + debugLog(0, "", "u2fhid_lock"); + (void)buf; + (void)len; + send_u2fhid_error(ERR_INVALID_CMD); +} + +void u2fhid_init(const U2FHID_INIT_REQ *init_req) +{ + debugLog(0, "", "u2fhid_init"); + U2FHID_FRAME f; + U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; + + bzero(&f, sizeof(f)); + f.cid = CID_BROADCAST; + f.init.cmd = U2FHID_INIT; + f.init.bcnth = 0; + f.init.bcntl = sizeof(U2FHID_INIT_RESP); + + memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); + resp->cid = next_cid(); + resp->versionInterface = U2FHID_IF_VERSION; + resp->versionMajor = VERSION_MAJOR; + resp->versionMinor = VERSION_MINOR; + resp->versionBuild = VERSION_PATCH; + resp->capFlags = CAPFLAG_WINK; + + queue_u2f_pkt(&f); +} + +void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) +{ + // debugLog(0, "", "u2f_write_pkt"); + uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN; + if (u2f_out_start == next) { + debugLog(0, "", "u2f_write_pkt full"); + return; // Buffer full :( + } + memcpy(u2f_out_packets[u2f_out_end], u2f_pkt, HID_RPT_SIZE); + u2f_out_end = next; +} + +uint8_t *u2f_out_data(void) +{ + if (u2f_out_start == u2f_out_end) + return NULL; // No data + // debugLog(0, "", "u2f_out_data"); + uint32_t t = u2f_out_start; + u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN; + return u2f_out_packets[t]; +} + +void u2fhid_msg(const APDU *a, uint32_t len) +{ + static bool lock = false; + + if ((APDU_LEN(*a) + sizeof(APDU)) > len) { + debugLog(0, "", "BAD APDU LENGTH"); + debugInt(APDU_LEN(*a)); + debugInt(len); + return; + } + + // Very crude locking, incase another message comes in while we wait. This + // actually can probably be removed as no code inside calls usbPoll anymore + if (lock) + return send_u2fhid_error(ERR_CHANNEL_BUSY); + + lock = true; + + switch (a->ins) { + case U2F_REGISTER: + u2f_register(a); + break; + case U2F_AUTHENTICATE: + u2f_authenticate(a); + break; + case U2F_VERSION: + u2f_version(a); + break; + default: + debugLog(0, "", "u2f unknown cmd"); + send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); + } + + lock = false; + + LayoutHomeAfterTimeout(); +} + +void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) +{ + U2FHID_FRAME f; + uint8_t *p = (uint8_t *)data; + uint32_t l = len; + uint32_t psz; + uint8_t seq = 0; + + // debugLog(0, "", "send_u2fhid_msg"); + + bzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = cmd; + f.init.bcnth = len >> 8; + f.init.bcntl = len & 0xff; + + // Init packet + psz = MIN(sizeof(f.init.data), l); + memcpy(f.init.data, p, psz); + queue_u2f_pkt(&f); + l -= psz; + p += psz; + + // Cont packet(s) + for (; l > 0; l -= psz, p += psz) { + // debugLog(0, "", "send_u2fhid_msg con"); + bzero(&f.cont.data, sizeof(f.cont.data)); + f.cont.seq = seq++; + psz = MIN(sizeof(f.cont.data), l); + memcpy(f.cont.data, p, psz); + queue_u2f_pkt(&f); + } + + if (data + len != p) { + debugLog(0, "", "send_u2fhid_msg is bad"); + debugInt(data + len - p); + } +} + +void send_u2fhid_error(uint8_t err) +{ + U2FHID_FRAME f; + + bzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = U2FHID_ERROR; + f.init.bcntl = 1; + f.init.data[0] = err; + queue_u2f_pkt(&f); +} + +void u2f_version(const APDU *a) +{ + // INCLUDES SW_NO_ERROR + static const uint8_t version_response[] = {'U', '2', 'F', '_', + 'V', '2', 0x90, 0x00}; + (void)a; + debugLog(0, "", "u2f version"); + send_u2f_msg(version_response, sizeof(version_response)); +} + +const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) +{ + static HDNode node; + if (!storage_getRootNode(&node)) { + layoutHome(); + debugLog(0, "", "ERR: Device not init"); + return 0; + } + if (!address_n || address_n_count == 0) { + return &node; + } + if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + layoutHome(); + debugLog(0, "", "ERR: Derive private failed"); + return 0; + } + return &node; +} + +const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) +{ + uint8_t keybase[64]; + + // First half of keyhandle is random + random_buffer(key_handle, 32); + + // prepare keypair from /random data + const HDNode *node = + getDerivedNode((uint32_t*)key_handle, 32/sizeof(uint32_t)); + + // For second half of keyhandle + // Signature of app_id and random data + memcpy(&keybase[0], app_id, 32); + memcpy(&keybase[32], key_handle, 32); + uint8_t sig[64]; + ecdsa_sign(&nist256p1, node->private_key, + (uint8_t *)&keybase, sizeof(keybase), sig, + NULL); + + // Copy 32 bytes of signature into keyhandle + memcpy(&key_handle[32], sig, 32); + + // Done! + return node; +} + + +const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) +{ + uint8_t keybase[64]; + memcpy(&keybase[0], app_id, 32); + memcpy(&keybase[32], key_handle, 32); + + const HDNode *node = + getDerivedNode((uint32_t*)key_handle, 32/sizeof(uint32_t)); + + uint8_t sig[64]; + ecdsa_sign(&nist256p1, node->private_key, + (uint8_t *)&keybase, sizeof(keybase), sig, + NULL); + + if (memcmp(&key_handle[32], sig, 32) !=0) + return NULL; + + // Done! + return node; +} + + +void u2f_register(const APDU *a) +{ + static U2F_REGISTER_REQ last_req; + const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; + + // Validate basic request parameters + debugLog(0, "", "u2f register"); + if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { + debugLog(0, "", "u2f register - badlen"); + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + // If this request is different from last request, reset state machine + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } + + // First Time request, return not present and display request dialog + if (last_req_state == 0) { + // wake up crypto system to be ready for signing + getDerivedNode(NULL, 0); + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + buttonUpdate(); // Clear button state + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Register", + NULL, "Register U2F", "security key", "", "", "", NULL); + dialog_timeout = U2F_TIMEOUT; + last_req_state = REG; + return; + } + + // Still awaiting Keypress + if (last_req_state == REG) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } + + // Buttons said no! + if (last_req_state == REG_FAIL) { + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + // Buttons said yes + if (last_req_state == REG_PASS) { + uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; + U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; + bzero(data, sizeof(data)); + + + resp->registerId = U2F_REGISTER_ID; + resp->keyHandleLen = KEY_HANDLE_LEN; + // Generate keypair for this appId + const HDNode *node = + generateKeyHandle(req->appId, (uint8_t*)&resp->keyHandleCertSig); + + if (!node) { + debugLog(0, "", "getDerivedNode Fail"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + ecdsa_get_public_key65(&nist256p1, node->private_key, + (uint8_t *)&resp->pubKey); + + memcpy(resp->keyHandleCertSig + resp->keyHandleLen, + U2F_ATT_CERT, sizeof(U2F_ATT_CERT)); + + uint8_t sig[64]; + U2F_REGISTER_SIG_STR sig_base; + sig_base.reserved = 0; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); + memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); + ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, + sizeof(sig_base), sig, NULL); + + // Where to write the signature in the response + uint8_t *resp_sig = resp->keyHandleCertSig + + resp->keyHandleLen + sizeof(U2F_ATT_CERT); + // Convert to der for the response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); + + // Append success bytes + memcpy(resp->keyHandleCertSig + resp->keyHandleLen + + sizeof(U2F_ATT_CERT) + sig_len, + "\x90\x00", 2); + + int l = 1 /* registerId */ + U2F_PUBKEY_LEN + + 1 /* keyhandleLen */ + resp->keyHandleLen + + sizeof(U2F_ATT_CERT) + sig_len + 2; + + send_u2f_msg(data, l); + return; + } + + // Didnt expect to get here + dialog_timeout = 0; +} + +void u2f_authenticate(const APDU *a) +{ + const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; + static U2F_AUTHENTICATE_REQ last_req; + + if (APDU_LEN(*a) < 64) { /// FIXME: decent value + debugLog(0, "", "u2f authenticate - badlen"); + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + if (req->keyHandleLen != KEY_HANDLE_LEN) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + const HDNode *node = + validateKeyHandle(req->appId, req->keyHandle); + + if (!node) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + if (a->p1 == U2F_AUTH_CHECK_ONLY) { + debugLog(0, "", "u2f authenticate check"); + // This is a success for a good keyhandle + // A failed check would have happened earlier + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } + + if (a->p1 != U2F_AUTH_ENFORCE) { + debugLog(0, "", "u2f authenticate unknown"); + // error:bad key handle + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } + + debugLog(0, "", "u2f authenticate enforce"); + + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } + + if (last_req_state == INIT) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + buttonUpdate(); // Clear button state + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Authenticate", NULL, + "Authenticate U2F", "security key", "", "", "", NULL); + dialog_timeout = U2F_TIMEOUT; + last_req_state = AUTH; + return; + } + + // Awaiting Keypress + if (last_req_state == AUTH) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } + + // Buttons said no! + if (last_req_state == AUTH_FAIL) { + send_u2f_error( + U2F_SW_WRONG_DATA); // error:bad key handle + return; + } + + // Buttons said yes + if (last_req_state == AUTH_PASS) { + uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; + U2F_AUTHENTICATE_RESP *resp = + (U2F_AUTHENTICATE_RESP *)&buf; + + const uint32_t ctr = storage_nextU2FCounter(); + resp->flags = U2F_AUTH_FLAG_TUP; + resp->ctr[0] = ctr >> 24 & 0xff; + resp->ctr[1] = ctr >> 16 & 0xff; + resp->ctr[2] = ctr >> 8 & 0xff; + resp->ctr[3] = ctr & 0xff; + + // Build and sign response + U2F_AUTHENTICATE_SIG_STR sig_base; + uint8_t sig[64]; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + sig_base.flags = resp->flags; + memcpy(sig_base.ctr, resp->ctr, 4); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + ecdsa_sign(&nist256p1, node->private_key, + (uint8_t *)&sig_base, sizeof(sig_base), sig, + NULL); + + // Copy DER encoded signature into response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); + + // Append OK + memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - + U2F_MAX_EC_SIG_SIZE + sig_len, + "\x90\x00", 2); + send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - + U2F_MAX_EC_SIG_SIZE + sig_len + + 2); + last_req_state = INIT; + } +} + +void send_u2f_error(const uint16_t err) +{ + uint8_t data[2]; + data[0] = err >> 8 & 0xFF; + data[1] = err & 0xFF; + send_u2f_msg(data, 2); +} + +void send_u2f_msg(const uint8_t *data, const uint32_t len) +{ + send_u2fhid_msg(U2FHID_MSG, data, len); +} diff --git a/firmware/u2f.h b/firmware/u2f.h new file mode 100644 index 0000000000..cd1d102bf4 --- /dev/null +++ b/firmware/u2f.h @@ -0,0 +1,58 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2015 Mark Bryars + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __U2F_H__ +#define __U2F_H__ + +#include +#include +#include "u2f/u2f_hid.h" +#include "trezor.h" + +typedef struct { + uint8_t cla, ins, p1, p2; + uint8_t lc1, lc2, lc3; + uint8_t data[]; +} APDU; + +#define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3)) + +void u2fhid_read(const U2FHID_FRAME *buf); +bool u2fhid_write(uint8_t *buf); +void u2fhid_init(const U2FHID_INIT_REQ *init_req); +void u2fhid_ping(const uint8_t *buf, uint32_t len); +void u2fhid_wink(const uint8_t *buf, uint32_t len); +void u2fhid_sync(const uint8_t *buf, uint32_t len); +void u2fhid_lock(const uint8_t *buf, uint32_t len); +void u2fhid_msg(const APDU *a, uint32_t len); +void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt); + +uint8_t *u2f_out_data(void); +void u2f_register(const APDU *a); +void u2f_version(const APDU *a); +void u2f_authenticate(const APDU *a); + +void send_u2f_msg(const uint8_t *data, const uint32_t len); +void send_u2f_error(const uint16_t err); + +void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, + const uint32_t len); +void send_u2fhid_error(const uint8_t err); + +#endif diff --git a/firmware/u2f/u2f.h b/firmware/u2f/u2f.h new file mode 100644 index 0000000000..4291c594b2 --- /dev/null +++ b/firmware/u2f/u2f.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2013-2015 Yubico AB + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +// Common U2F raw message format header. +// 2014-08-14 J Ehrensvard, Yubico, Inc. + +#ifndef __U2F_H_INCLUDED__ +#define __U2F_H_INCLUDED__ + +#ifdef _MSC_VER // Windows +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; +#else +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +// General constants + +#define U2F_EC_KEY_SIZE 32 // EC key size in bytes +#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point +#define U2F_MAX_KH_SIZE 128 // Max size of key handle +#define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate +#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature +#define U2F_CTR_SIZE 4 // Size of counter field +#define U2F_APPID_SIZE 32 // Size of application id +#define U2F_CHAL_SIZE 32 // Size of challenge + +#define ENC_SIZE(x) ((x + 7) & 0xfff8) + +// EC (uncompressed) point + +#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format + + typedef struct + { + uint8_t pointFormat; // Point type + uint8_t x[U2F_EC_KEY_SIZE]; // X-value + uint8_t y[U2F_EC_KEY_SIZE]; // Y-value + } U2F_EC_POINT; + +// U2F native commands + +#define U2F_REGISTER 0x01 // Registration command +#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command +#define U2F_VERSION 0x03 // Read version string command + +#define U2F_VENDOR_FIRST 0x40 // First vendor defined command +#define U2F_VENDOR_LAST 0x7f // Last vendor defined command + +// U2F_CMD_REGISTER command defines + +#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier +#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier + + typedef struct + { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id + } U2F_REGISTER_REQ; + + typedef struct + { + uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) + U2F_EC_POINT pubKey; // Generated public key + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle + U2F_MAX_ATT_CERT_SIZE + // Attestation certificate + U2F_MAX_EC_SIG_SIZE]; // Registration signature + } U2F_REGISTER_RESP; + +// U2F_CMD_AUTHENTICATE command defines + +// Authentication control byte + +#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign +#define U2F_AUTH_CHECK_ONLY 0x07 // Check only +#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set + + typedef struct + { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle + } U2F_AUTHENTICATE_REQ; + + typedef struct + { + uint8_t flags; // U2F_AUTH_FLAG_ values + uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) + uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature + } U2F_AUTHENTICATE_RESP; + +// Common raw message format (ISO7816-4:2005 mapping) + + typedef struct + { + uint8_t cla; // Class - reserved + uint8_t ins; // U2F instruction + uint8_t p1; // U2F parameter 1 + uint8_t p2; // U2F parameter 2 + uint8_t lc1; // Length field, set to zero + uint8_t lc2; // Length field, MSB + uint8_t lc3; // Length field, LSB + uint8_t data[1]; // Data field + } U2F_MSG; + +// Command status responses + +#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR +#define U2F_SW_WRONG_DATA 0x6984 // SW_WRONG_DATA +#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED +#define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED +#define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED + +#ifdef __cplusplus +} +#endif + +#endif // __U2F_H_INCLUDED__ diff --git a/firmware/u2f/u2f_hid.h b/firmware/u2f/u2f_hid.h new file mode 100644 index 0000000000..d576d197c3 --- /dev/null +++ b/firmware/u2f/u2f_hid.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2013-2015 Yubico AB + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +// Common U2F HID transport header. +// 2014-08-21 J Ehrensvard, Yubico, Inc. + +#ifndef __U2FHID_H_INCLUDED__ +#define __U2FHID_H_INCLUDED__ + +#ifdef _MSC_VER // Windows +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; +#else +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Size of HID reports + +#define HID_RPT_SIZE 64 // Default size of raw HID report + +// Frame layout - command- and continuation frames + +#define CID_BROADCAST 0xffffffff // Broadcast channel id + +#define TYPE_MASK 0x80 // Frame type mask +#define TYPE_INIT 0x80 // Initial frame identifier +#define TYPE_CONT 0x00 // Continuation frame identifier + + typedef struct + { + uint32_t cid; // Channel identifier + union + { + uint8_t type; // Frame type - b7 defines type + struct + { + uint8_t cmd; // Command - b7 set + uint8_t bcnth; // Message byte count - high part + uint8_t bcntl; // Message byte count - low part + uint8_t data[HID_RPT_SIZE - 7]; // Data payload + } init; + struct + { + uint8_t seq; // Sequence number - b7 cleared + uint8_t data[HID_RPT_SIZE - 5]; // Data payload + } cont; + }; + } U2FHID_FRAME; + +#define FRAME_TYPE(f) ((f).type & TYPE_MASK) +#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) +#define MSG_LEN(f) (((f).init.bcnth << 8) + (f).init.bcntl) +#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) + +// HID usage- and usage-page definitions + +#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page +#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection +#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report +#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report + +// General constants + +#define U2FHID_IF_VERSION 2 // Current interface implementation version +#define U2FHID_FRAME_TIMEOUT 500 // Default frame timeout in ms +#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms + +// U2FHID native commands + +#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only +#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame +#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command +#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization +#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink +#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response + +#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command +#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command + +// U2FHID_INIT command defines + +#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge +#define CAPFLAG_WINK 0x01 // Device supports WINK command +#define CAPFLAG_LOCK 0x02 // Device supports LOCK command + + typedef struct + { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + } U2FHID_INIT_REQ; + + typedef struct + { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint32_t cid; // Channel identifier + uint8_t versionInterface; // Interface version + uint8_t versionMajor; // Major version number + uint8_t versionMinor; // Minor version number + uint8_t versionBuild; // Build version number + uint8_t capFlags; // Capabilities flags + } U2FHID_INIT_RESP; + +// Low-level error codes. Return as negatives. + +#define ERR_NONE 0x00 // No error +#define ERR_INVALID_CMD 0x01 // Invalid command +#define ERR_INVALID_PAR 0x02 // Invalid parameter +#define ERR_INVALID_LEN 0x03 // Invalid message length +#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing +#define ERR_MSG_TIMEOUT 0x05 // Message has timed out +#define ERR_CHANNEL_BUSY 0x06 // Channel busy +#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock +#define ERR_INVALID_CID 0x0b // Command not allowed on this cid +#define ERR_OTHER 0x7f // Other unspecified error + +#ifdef __cplusplus +} +#endif + +#endif // __U2FHID_H_INCLUDED__ diff --git a/firmware/u2f/u2f_keys.h b/firmware/u2f/u2f_keys.h new file mode 100644 index 0000000000..73c8378f71 --- /dev/null +++ b/firmware/u2f/u2f_keys.h @@ -0,0 +1,46 @@ +#ifndef __U2F_KEYS_H_INCLUDED__ +#define __U2F_KEYS_H_INCLUDED__ + +#include + +uint8_t U2F_ATT_PRIV_KEY[] = {0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, + 0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, + 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, + 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b}; + +uint8_t U2F_ATT_PUB_KEY[] = { + 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9, 0x0d, + 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36, + 0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, + 0x52, 0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, + 0xdb, 0x8a, 0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, + 0x43, 0xa5, 0x26, 0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1}; + +uint8_t U2F_ATT_CERT[] = { + 0x30, 0x82, 0x01, 0x19, 0x30, 0x81, 0xC0, 0x02, 0x09, 0x00, 0x8B, 0x3F, + 0xA6, 0x46, 0xDE, 0x01, 0xCB, 0xB8, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0A, 0x54, 0x72, 0x65, 0x7A, 0x6F, + 0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x35, 0x31, + 0x30, 0x31, 0x31, 0x32, 0x33, 0x32, 0x33, 0x34, 0x36, 0x5A, 0x17, 0x0D, + 0x32, 0x35, 0x31, 0x30, 0x30, 0x38, 0x32, 0x33, 0x32, 0x33, 0x34, 0x36, + 0x5A, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0C, 0x0A, 0x54, 0x72, 0x65, 0x7A, 0x6F, 0x72, 0x20, 0x55, 0x32, 0x46, + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, + 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xD9, 0x18, 0xBD, 0xFA, 0x8A, 0x54, 0xAC, 0x92, 0xE9, + 0x0D, 0xA9, 0x1F, 0xCA, 0x7A, 0xA2, 0x64, 0x54, 0xC0, 0xD1, 0x73, 0x36, + 0x31, 0x4D, 0xDE, 0x83, 0xA5, 0x4B, 0x86, 0xB5, 0xDF, 0x4E, 0xF0, 0x52, + 0x65, 0x9A, 0x1D, 0x6F, 0xFC, 0xB7, 0x46, 0x7F, 0x1A, 0xCD, 0xDB, 0x8A, + 0x33, 0x08, 0x0B, 0x5E, 0xED, 0x91, 0x89, 0x13, 0xF4, 0x43, 0xA5, 0x26, + 0x1B, 0xC7, 0x7B, 0x68, 0x60, 0x6F, 0xC1, 0x30, 0x0A, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, + 0x02, 0x21, 0x00, 0x89, 0x38, 0x50, 0x13, 0xBB, 0x13, 0xF1, 0xE9, 0xEF, + 0x7A, 0x1B, 0x47, 0x59, 0x19, 0xBA, 0x18, 0x55, 0x32, 0xE6, 0x76, 0xD1, + 0xAD, 0x69, 0x9D, 0x97, 0x07, 0x89, 0x80, 0x08, 0x4F, 0xAA, 0xE8, 0x02, + 0x20, 0x35, 0x9A, 0x5F, 0x1D, 0xE5, 0x0A, 0x12, 0xA0, 0x9C, 0x96, 0x3D, + 0x5A, 0x39, 0xA8, 0x83, 0x3C, 0xBA, 0x2E, 0xAD, 0xD5, 0x90, 0x23, 0x85, + 0x81, 0x7D, 0xF0, 0xC7, 0x72, 0x8E, 0x79, 0x09, 0xD0, +}; + +#endif // __U2F_KEYS_H_INCLUDED__ diff --git a/firmware/usb.c b/firmware/usb.c index 102b573da3..e084742af7 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -24,6 +24,7 @@ #include "usb.h" #include "debug.h" #include "messages.h" +#include "u2f.h" #include "storage.h" #include "util.h" @@ -31,6 +32,8 @@ #define ENDPOINT_ADDRESS_OUT (0x01) #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#define ENDPOINT_ADDRESS_U2F_IN (0x83) +#define ENDPOINT_ADDRESS_U2F_OUT (0x03) static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, @@ -111,6 +114,25 @@ static const uint8_t hid_report_descriptor[] = { 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, }; +static const uint8_t hid_report_descriptor_u2f[] = { + 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) + 0x09, 0x01, // USAGE (U2F HID Authenticator Device) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75,0x08, // REPORT_SIZE (8) + 0x95,0x40, // REPORT_COUNT (64) + 0x81,0x02, // INPUT (Data,Var,Abs) + 0x09,0x21, // USAGE (Output Report Data) + 0x15,0x00, // LOGICAL_MINIMUM (0) + 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75,0x08, // REPORT_SIZE (8) + 0x95,0x40, // REPORT_COUNT (64) + 0x91,0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + static const struct { struct usb_hid_descriptor hid_descriptor; struct { @@ -131,6 +153,27 @@ static const struct { } }; +static const struct { + struct usb_hid_descriptor hid_descriptor_u2f; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report_u2f; +} __attribute__((packed)) hid_function_u2f = { + .hid_descriptor_u2f = { + .bLength = sizeof(hid_function_u2f), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report_u2f = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor_u2f), + } +}; + + static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -162,6 +205,41 @@ static const struct usb_interface_descriptor hid_iface[] = {{ .extralen = sizeof(hid_function), }}; +static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor hid_iface_u2f[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, +#if DEBUG_LINK + .bInterfaceNumber = 2, +#else + .bInterfaceNumber = 1, +#endif + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints_u2f, + .extra = &hid_function_u2f, + .extralen = sizeof(hid_function_u2f), +}}; + #if DEBUG_LINK static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, @@ -198,6 +276,9 @@ static const struct usb_interface_descriptor hid_iface_debug[] = {{ static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, .altsetting = hid_iface, +}, { + .num_altsetting = 1, + .altsetting = hid_iface_u2f, #if DEBUG_LINK }, { .num_altsetting = 1, @@ -210,9 +291,9 @@ static const struct usb_config_descriptor config = { .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, #if DEBUG_LINK - .bNumInterfaces = 2, + .bNumInterfaces = 3, #else - .bNumInterfaces = 1, + .bNumInterfaces = 2, #endif .bConfigurationValue = 1, .iConfiguration = 0, @@ -237,11 +318,18 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (req->wValue != 0x2200)) return 0; - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + if (req->wIndex==1) { + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = sizeof(hid_report_descriptor_u2f); + return 1; + } - return 1; + debugLog(0, "", "hid_control_request trezor"); + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + return 1; } static volatile char tiny = 0; @@ -259,6 +347,16 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } } +static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) +{ + (void)ep; + static uint8_t buf[64] __attribute__ ((aligned(4))); + + debugLog(0, "", "hid_u2f_rx_callback"); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; + u2fhid_read((const U2FHID_FRAME *)buf); +} + #if DEBUG_LINK static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) { @@ -280,6 +378,8 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_u2f_rx_callback); #if DEBUG_LINK usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); @@ -311,6 +411,10 @@ void usbPoll(void) if (data) { while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} } + data = u2f_out_data(); + if (data) { + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) != 64 ) {} + } #if DEBUG_LINK // write pending debug data data = msg_debug_out_data(); diff --git a/trezor-common b/trezor-common index 3fc31bfe9c..72268e816b 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 3fc31bfe9c42ebf3c0a63c48f44537994787f9c9 +Subproject commit 72268e816b8e8e06f698b3729223a255c7c74167 From e1095e3ad40e344f9d6fbbea933040c164d724e0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Nov 2015 18:46:21 +0100 Subject: [PATCH 0169/1154] update trezor-common --- trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezor-common b/trezor-common index 3fc31bfe9c..72268e816b 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 3fc31bfe9c42ebf3c0a63c48f44537994787f9c9 +Subproject commit 72268e816b8e8e06f698b3729223a255c7c74167 From 32f88199978ba0d882c60b0e7b4959e42714274f Mon Sep 17 00:00:00 2001 From: Mark Bryars Date: Thu, 5 Nov 2015 01:24:37 +0100 Subject: [PATCH 0170/1154] Generate hardened keys in a unique root --- firmware/u2f.c | 23 ++++++++++++++++++----- firmware/u2f.h | 2 ++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 09f2ca810b..db55c88c0d 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -447,12 +447,20 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) { uint8_t keybase[64]; - // First half of keyhandle is random - random_buffer(key_handle, 32); + // Derivation path is m/'U2F/'r/'r/'r/'r/'r/'r/'r/'r + uint32_t i, key_path[9]; + key_path[0] = U2F_KEY_PATH; + for (i = 1; i < 9; i++) { + // high bit for hardened keys + key_path[i]= 0x80000000 | random32(); + } + + // First half of keyhandle is key_path + memcpy(key_handle, &key_path[1], 32); // prepare keypair from /random data const HDNode *node = - getDerivedNode((uint32_t*)key_handle, 32/sizeof(uint32_t)); + getDerivedNode(key_path, sizeof(key_path) / sizeof(uint32_t)); // For second half of keyhandle // Signature of app_id and random data @@ -473,12 +481,17 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) { + uint32_t key_path[9]; + key_path[0] = U2F_KEY_PATH; + memcpy(&key_path[1], key_handle, 32); + + const HDNode *node = + getDerivedNode(key_path, sizeof(key_path) / sizeof(uint32_t)); + uint8_t keybase[64]; memcpy(&keybase[0], app_id, 32); memcpy(&keybase[32], key_handle, 32); - const HDNode *node = - getDerivedNode((uint32_t*)key_handle, 32/sizeof(uint32_t)); uint8_t sig[64]; ecdsa_sign(&nist256p1, node->private_key, diff --git a/firmware/u2f.h b/firmware/u2f.h index cd1d102bf4..847710a4c6 100644 --- a/firmware/u2f.h +++ b/firmware/u2f.h @@ -25,6 +25,8 @@ #include "u2f/u2f_hid.h" #include "trezor.h" +#define U2F_KEY_PATH 0x80553246 + typedef struct { uint8_t cla, ins, p1, p2; uint8_t lc1, lc2, lc3; From 50c8811af970754a47452efec1b4df558c8ba491 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Nov 2015 19:52:16 +0100 Subject: [PATCH 0171/1154] double sized font for reset device --- firmware/reset.c | 15 ++++++---- oled.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++-- oled.h | 1 + 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/firmware/reset.c b/firmware/reset.c index 7e75f96ee6..8ec4c1bc7b 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -77,7 +77,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect awaiting_entropy = true; } -static char current_word[10]; +static char current_word[10], current_word_display[11]; void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { @@ -122,17 +122,22 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) if (word_pos == 3 || word_pos == 23) { desc[2] = 'r'; desc[3] = 'd'; } + current_word_display[0] = 0x01; + for (j = 0; current_word[j]; j++) { + current_word_display[j + 1] = current_word[j] + 'A' - 'a'; + } + current_word_display[j + 1] = 0; if (word_pos == (int)strength/32*3) { // last word if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } else { if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL); + layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { diff --git a/oled.c b/oled.c index 6b3ef56743..3f569e1e74 100644 --- a/oled.c +++ b/oled.c @@ -55,6 +55,20 @@ #define OLED_RST_PORT GPIOB #define OLED_RST_PIN GPIO1 // PB1 | Reset display +/* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64). + * The contents of this display are buffered in _oledbuffer. This is + * an array of OLED_WIDTH * OLED_HEIGHT/8 bytes. At byte y*OLED_WIDTH + x + * it stores the column of pixels from (x,8y) to (x,8y+7); the LSB stores + * the top most pixel. The pixel (0,0) is the top left corner of the + * display. + */ + +/* Macros to manipulate a single pixel in _oledbuffer: + * OLED_BUFSET(X,Y) sets pixel X,Y (white) + * OLED_BUFCLR(X,Y) clears pixel X,Y (black) + * OLED_BUFTGL(X,Y) toggles pixel X,Y (inverts it) + */ + #define OLED_BUFSET(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] |= (1 << (7 - (Y)%8)) #define OLED_BUFCLR(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] &= ~(1 << (7 - (Y)%8)) #define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8)) @@ -62,6 +76,9 @@ static uint8_t _oledbuffer[OLED_BUFSIZE]; static char is_debug_mode = 0; +/* + * Send a block of data via the SPI bus. + */ inline void SPISend(uint32_t base, uint8_t *data, int len) { int i; @@ -72,6 +89,9 @@ inline void SPISend(uint32_t base, uint8_t *data, int len) delay(800); } +/* + * Initialize the display. + */ void oledInit() { static uint8_t s[25] = { @@ -121,11 +141,20 @@ void oledInit() oledRefresh(); } +/* + * Clears the display buffer (sets all pixels to black) + */ void oledClear() { memset(_oledbuffer, 0, sizeof(_oledbuffer)); } +/* + * Refresh the display. This copies the buffer to the display to show the + * contents. This must be called after every operation to the buffer to + * make the change visible. All other operations only change the buffer + * not the content of the display. + */ void oledRefresh() { static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; @@ -207,6 +236,26 @@ void oledDrawChar(int x, int y, char c) } } +void oledDrawZoomedChar(int x, int y, int z, char c) +{ + int char_width; + const uint8_t *char_data; + + if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; + + char_width = fontCharWidth(c); + char_data = fontCharData(c); + + int xoffset, yoffset; + for (xoffset = 0; xoffset < char_width; xoffset++) { + for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { + if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { + oledBox(x + xoffset * z, y + yoffset * z, x + xoffset * z + z - 1, y + yoffset * z + z - 1, 1); + } + } + } +} + char oledConvertChar(const char c) { uint8_t a = c; if (a < 0x80) return c; @@ -233,13 +282,23 @@ int oledStringWidth(const char *text) { void oledDrawString(int x, int y, const char* text) { if (!text) return; + int size = 1; + if (*text == 0x01) { // double size + text++; + size = 2; + } int l = 0; char c; for (; *text; text++) { c = oledConvertChar(*text); if (c) { - oledDrawChar(x + l, y, c); - l += fontCharWidth(c) + 1; + if (size > 1) { + oledDrawZoomedChar(x + l, y, size, c); + l += fontCharWidth(c) * size + 1; + } else { + oledDrawChar(x + l, y, c); + l += fontCharWidth(c) + 1; + } } } } @@ -283,6 +342,9 @@ void oledInvert(int x1, int y1, int x2, int y2) } } +/* + * Draw a filled rectangle. + */ void oledBox(int x1, int y1, int x2, int y2, char val) { int x, y; @@ -300,6 +362,9 @@ void oledHLine(int y) { } } +/* + * Draw a rectangle frame. + */ void oledFrame(int x1, int y1, int x2, int y2) { int x, y; @@ -313,6 +378,10 @@ void oledFrame(int x1, int y1, int x2, int y2) } } +/* + * Animates the display, swiping the current contents out to the left. + * This clears the display. + */ void oledSwipeLeft(void) { int i, j, k; @@ -333,6 +402,10 @@ void oledSwipeLeft(void) } } +/* + * Animates the display, swiping the current contents out to the right. + * This clears the display. + */ void oledSwipeRight(void) { int i, j, k; diff --git a/oled.h b/oled.h index c3b8db2c69..cbabb36ac7 100644 --- a/oled.h +++ b/oled.h @@ -39,6 +39,7 @@ const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); void oledClearPixel(int x, int y); void oledDrawChar(int x, int y, char c); +void oledDrawZoomedChar(int x, int y, int z, char c); int oledStringWidth(const char *text); void oledDrawString(int x, int y, const char* text); void oledDrawStringCenter(int y, const char* text); From c71abf91a6490a73d1eae5e2c64a79685708b063 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 18 Nov 2015 23:35:28 +0100 Subject: [PATCH 0172/1154] cleanup oledDrawChar code --- buttons.h | 1 + oled.c | 53 ++++++++++++++++------------------------------------- oled.h | 8 ++++---- 3 files changed, 21 insertions(+), 41 deletions(-) diff --git a/buttons.h b/buttons.h index 58b7188019..08f0c8e036 100644 --- a/buttons.h +++ b/buttons.h @@ -21,6 +21,7 @@ #define __BUTTONS_H__ #include +#include struct buttonState { volatile bool YesUp; diff --git a/oled.c b/oled.c index 3f569e1e74..a63d810a9f 100644 --- a/oled.c +++ b/oled.c @@ -74,7 +74,7 @@ #define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8)) static uint8_t _oledbuffer[OLED_BUFSIZE]; -static char is_debug_mode = 0; +static bool is_debug_mode = 0; /* * Send a block of data via the SPI bus. @@ -193,7 +193,7 @@ const uint8_t *oledGetBuffer() return _oledbuffer; } -void oledSetDebug(char set) +void oledSetDebug(bool set) { is_debug_mode = set; oledRefresh(); @@ -216,7 +216,7 @@ void oledClearPixel(int x, int y) OLED_BUFCLR(x,y); } -void oledDrawChar(int x, int y, char c) +void oledDrawChar(int x, int y, char c, int zoom) { int char_width; const uint8_t *char_data; @@ -226,31 +226,15 @@ void oledDrawChar(int x, int y, char c) char_width = fontCharWidth(c); char_data = fontCharData(c); - int xoffset, yoffset; - for (xoffset = 0; xoffset < char_width; xoffset++) { - for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { - if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { - oledDrawPixel(x + xoffset, y + yoffset); - } - } - } -} - -void oledDrawZoomedChar(int x, int y, int z, char c) -{ - int char_width; - const uint8_t *char_data; - - if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - - char_width = fontCharWidth(c); - char_data = fontCharData(c); - - int xoffset, yoffset; - for (xoffset = 0; xoffset < char_width; xoffset++) { - for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { - if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { - oledBox(x + xoffset * z, y + yoffset * z, x + xoffset * z + z - 1, y + yoffset * z + z - 1, 1); + int xo, yo; + for (xo = 0; xo < char_width; xo++) { + for (yo = 0; yo < FONT_HEIGHT; yo++) { + if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { + if (zoom <= 1) { + oledDrawPixel(x + xo, y + yo); + } else { + oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true); + } } } } @@ -292,13 +276,8 @@ void oledDrawString(int x, int y, const char* text) for (; *text; text++) { c = oledConvertChar(*text); if (c) { - if (size > 1) { - oledDrawZoomedChar(x + l, y, size, c); - l += fontCharWidth(c) * size + 1; - } else { - oledDrawChar(x + l, y, c); - l += fontCharWidth(c) + 1; - } + oledDrawChar(x + l, y, c, size); + l += size * (fontCharWidth(c) + 1); } } } @@ -345,12 +324,12 @@ void oledInvert(int x1, int y1, int x2, int y2) /* * Draw a filled rectangle. */ -void oledBox(int x1, int y1, int x2, int y2, char val) +void oledBox(int x1, int y1, int x2, int y2, bool set) { int x, y; for (x = x1; x <= x2; x++) { for (y = y1; y <= y2; y++) { - val ? oledDrawPixel(x, y) : oledClearPixel(x, y); + set ? oledDrawPixel(x, y) : oledClearPixel(x, y); } } } diff --git a/oled.h b/oled.h index cbabb36ac7..6fccc363ad 100644 --- a/oled.h +++ b/oled.h @@ -21,6 +21,7 @@ #define __OLED_H__ #include +#include #include "bitmaps.h" #include "fonts.h" @@ -33,20 +34,19 @@ void oledInit(void); void oledClear(void); void oledRefresh(void); -void oledSetDebug(char set); +void oledSetDebug(bool set); void oledSetBuffer(uint8_t *buf); const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); void oledClearPixel(int x, int y); -void oledDrawChar(int x, int y, char c); -void oledDrawZoomedChar(int x, int y, int z, char c); +void oledDrawChar(int x, int y, char c, int zoom); int oledStringWidth(const char *text); void oledDrawString(int x, int y, const char* text); void oledDrawStringCenter(int y, const char* text); void oledDrawStringRight(int x, int y, const char* text); void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledInvert(int x1, int y1, int x2, int y2); -void oledBox(int x1, int y1, int x2, int y2, char val); +void oledBox(int x1, int y1, int x2, int y2, bool set); void oledHLine(int y); void oledFrame(int x1, int y1, int x2, int y2); void oledSwipeLeft(void); From 27183323a44e05baf36b3362147a9a1df55c689f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Nov 2015 11:03:16 +0100 Subject: [PATCH 0173/1154] fail sooner when the device is not initialized --- firmware/fsm.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 32b25e28a4..94bb0bb31b 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -282,6 +282,11 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + if (!protectPin(true)) { layoutHome(); return; @@ -363,6 +368,11 @@ void fsm_msgResetDevice(ResetDevice *msg) void fsm_msgSignTx(SignTx *msg) { + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + if (msg->inputs_count < 1) { fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); layoutHome(); @@ -406,6 +416,10 @@ void fsm_msgTxAck(TxAck *msg) void fsm_msgCipherKeyValue(CipherKeyValue *msg) { + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } if (!msg->has_key) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); return; @@ -531,6 +545,11 @@ void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + if (!protectPin(true)) { layoutHome(); return; @@ -599,6 +618,11 @@ void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); @@ -660,6 +684,11 @@ void fsm_msgSignIdentity(SignIdentity *msg) { RESP_INIT(SignedIdentity); + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); @@ -736,6 +765,10 @@ void fsm_msgSignIdentity(SignIdentity *msg) void fsm_msgEncryptMessage(EncryptMessage *msg) { + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } if (!msg->has_pubkey) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); return; @@ -792,6 +825,10 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) void fsm_msgDecryptMessage(DecryptMessage *msg) { + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } if (!msg->has_nonce) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); return; From f557e6149d5bca3559f18c2888d02b20bd28673c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Nov 2015 11:48:26 +0100 Subject: [PATCH 0174/1154] implement GetPublicKey.show_display option --- firmware/fsm.c | 9 +++++++++ firmware/layout2.c | 11 +++++++++++ firmware/layout2.h | 1 + firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 11 +++++++---- firmware/protob/storage.pb.c | 3 ++- firmware/protob/storage.pb.h | 11 +++++++---- firmware/protob/types.pb.h | 3 ++- trezor-common | 2 +- 9 files changed, 42 insertions(+), 12 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 94bb0bb31b..a9cd886e61 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -306,6 +306,15 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) } } + if (msg->has_show_display && msg->show_display) { + layoutPublicKey(public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show public key cancelled"); + layoutHome(); + return; + } + } + resp->node.depth = node->depth; resp->node.fingerprint = node->fingerprint; resp->node.child_num = node->child_num; diff --git a/firmware/layout2.c b/firmware/layout2.c index 2ede4a9e34..f10d2ce43f 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -270,6 +270,17 @@ void layoutAddress(const char *address, const char *desc) oledRefresh(); } +void layoutPublicKey(const uint8_t *pubkey) +{ + char hex[32*2+1], desc[16]; + strlcpy(desc, "Public Key: 00", sizeof(desc)); + data2hex(pubkey, 1, desc + 12); + data2hex(pubkey + 1, 32, hex); + const char **str = split_message((const uint8_t *)hex, 32*2, 16); + layoutDialogSwipe(DIALOG_ICON_QUESTION, NULL, "Continue", NULL, + desc, str[0], str[1], str[2], str[3], NULL); +} + void layoutSignIdentity(const IdentityType *identity, const char *challenge) { char row_proto[8 + 11 + 1]; diff --git a/firmware/layout2.h b/firmware/layout2.h index 70e35491c0..90ce8e1963 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -37,6 +37,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutAddress(const char *address, const char *desc); +void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); #endif diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 3a49ebf04c..9ef79a45ac 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -123,9 +123,10 @@ const pb_field_t Entropy_fields[2] = { PB_LAST_FIELD }; -const pb_field_t GetPublicKey_fields[3] = { +const pb_field_t GetPublicKey_fields[4] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetPublicKey, show_display, ecdsa_curve_name, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 3f942e5bc5..c69ac8453e 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -426,6 +426,8 @@ typedef struct _GetPublicKey { uint32_t address_n[8]; bool has_ecdsa_curve_name; char ecdsa_curve_name[32]; + bool has_show_display; + bool show_display; } GetPublicKey; typedef struct _LoadDevice { @@ -661,7 +663,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define PassphraseAck_init_default {""} #define GetEntropy_init_default {0} #define Entropy_init_default {{0, {0}}} -#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} +#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_default {HDNodeType_init_default, false, ""} #define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} #define Address_init_default {""} @@ -715,7 +717,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define PassphraseAck_init_zero {""} #define GetEntropy_init_zero {0} #define Entropy_init_zero {{0, {0}}} -#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} +#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} #define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} #define Address_init_zero {""} @@ -829,6 +831,7 @@ extern const char SimpleSignTx_coin_name_default[17]; #define GetEntropy_size_tag 1 #define GetPublicKey_address_n_tag 1 #define GetPublicKey_ecdsa_curve_name_tag 2 +#define GetPublicKey_show_display_tag 3 #define LoadDevice_mnemonic_tag 1 #define LoadDevice_node_tag 2 #define LoadDevice_pin_tag 3 @@ -906,7 +909,7 @@ extern const pb_field_t PassphraseRequest_fields[1]; extern const pb_field_t PassphraseAck_fields[2]; extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; -extern const pb_field_t GetPublicKey_fields[3]; +extern const pb_field_t GetPublicKey_fields[4]; extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[5]; extern const pb_field_t Address_fields[2]; @@ -962,7 +965,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define PassphraseAck_size 53 #define GetEntropy_size 6 #define Entropy_size 1027 -#define GetPublicKey_size 82 +#define GetPublicKey_size 84 #define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size (75 + MultisigRedeemScriptType_size) #define Address_size 38 diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 68da897f29..67f1619a8f 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -5,7 +5,7 @@ -const pb_field_t Storage_fields[11] = { +const pb_field_t Storage_fields[12] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -16,6 +16,7 @@ const pb_field_t Storage_fields[11] = { PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), + PB_FIELD2( 11, UINT32 , OPTIONAL, STATIC , OTHER, Storage, u2f_counter, homescreen, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 2f51923fd2..c5d942eb90 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -37,13 +37,15 @@ typedef struct _Storage { bool imported; bool has_homescreen; Storage_homescreen_t homescreen; + bool has_u2f_counter; + uint32_t u2f_counter; } Storage; /* Default values for struct fields */ /* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}} +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 @@ -56,12 +58,13 @@ typedef struct _Storage { #define Storage_label_tag 8 #define Storage_imported_tag 9 #define Storage_homescreen_tag 10 +#define Storage_u2f_counter_tag 11 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[11]; +extern const pb_field_t Storage_fields[12]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (1359 + HDNodeType_size) +#define Storage_size (1365 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index f31812d194..29e8e9ec92 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -53,7 +53,8 @@ typedef enum _ButtonRequestType { ButtonRequestType_ButtonRequest_ProtectCall = 7, ButtonRequestType_ButtonRequest_SignTx = 8, ButtonRequestType_ButtonRequest_FirmwareCheck = 9, - ButtonRequestType_ButtonRequest_Address = 10 + ButtonRequestType_ButtonRequest_Address = 10, + ButtonRequestType_ButtonRequest_PublicKey = 11 } ButtonRequestType; typedef enum _PinMatrixRequestType { diff --git a/trezor-common b/trezor-common index 72268e816b..9983a12276 160000 --- a/trezor-common +++ b/trezor-common @@ -1 +1 @@ -Subproject commit 72268e816b8e8e06f698b3729223a255c7c74167 +Subproject commit 9983a12276689afff8e28e1bd78605b8e6d63c1c From ed76d030efbebd4de1b9d5f316e5a10d86ae860f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 14 Dec 2015 22:53:14 +0100 Subject: [PATCH 0175/1154] check for sessionPassphraseCached --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index d5f5bc9f9d..da046c50a5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -265,7 +265,7 @@ bool storage_getRootNode(HDNode *node) if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode) == 0) { return false; } - if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) { + if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { // decrypt hd node uint8_t secret[64]; uint8_t salt[12]; From 8d183608c25bbc6417594d739b10e184f889c293 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 15 Dec 2015 00:20:34 +0100 Subject: [PATCH 0176/1154] include libopencm3 as submodule --- .gitmodules | 3 +++ Dockerfile | 9 --------- Makefile.include | 8 ++++---- firmware-docker-build.sh | 3 +++ libopencm3 | 1 + 5 files changed, 11 insertions(+), 13 deletions(-) create mode 160000 libopencm3 diff --git a/.gitmodules b/.gitmodules index 97aef8fa1c..87453ddb1e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "trezor-qrenc"] path = trezor-qrenc url = https://github.com/trezor/trezor-qrenc.git +[submodule "libopencm3"] + path = libopencm3 + url = https://github.com/libopencm3/libopencm3.git diff --git a/Dockerfile b/Dockerfile index adb7f76fbf..29efb93146 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,12 +9,3 @@ RUN apt-get update # install build tools and dependencies RUN apt-get install -y build-essential git python gcc-arm-none-eabi - -# clone the source code - -RUN git clone https://github.com/libopencm3/libopencm3 - -# build libopencm3 - -ENV LIBOPENCM3_GITREV 7b29caed1a726b5cef4c269b6a6ef7a1f1dd105c -RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make diff --git a/Makefile.include b/Makefile.include index 8505ffc865..97bc3a6045 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,5 +1,5 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -TOOLCHAIN_DIR ?= $(TOP_DIR)/../libopencm3 +TOOLCHAIN_DIR ?= $(TOP_DIR)libopencm3 PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc @@ -42,9 +42,9 @@ CFLAGS += $(OPTFLAGS) \ -DSTM32F2 \ -I$(TOOLCHAIN_DIR)/include \ -I$(TOP_DIR) \ - -I$(TOP_DIR)/gen \ - -I$(TOP_DIR)/trezor-crypto \ - -I$(TOP_DIR)/trezor-qrenc + -I$(TOP_DIR)gen \ + -I$(TOP_DIR)trezor-crypto \ + -I$(TOP_DIR)trezor-qrenc ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index f705c8ffbd..d571d95e10 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -8,6 +8,9 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ + cd libopencm3 && + make && \ + cd .. && \ make && \ cd firmware && \ make && \ diff --git a/libopencm3 b/libopencm3 new file mode 160000 index 0000000000..b1049f9a6f --- /dev/null +++ b/libopencm3 @@ -0,0 +1 @@ +Subproject commit b1049f9a6f43882968dcf82ca1df3f1eee67e367 From 06a70556e036ce1356fd3693d7c4aff45617d10c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 15 Dec 2015 00:30:10 +0100 Subject: [PATCH 0177/1154] cleanup docker build and travis file --- .travis.yml | 9 ++++----- firmware-docker-build.sh | 9 +++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06d332fd7a..2ccad05c84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,10 @@ install: - sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y - sudo apt-get update - sudo apt-get install -y build-essential git gcc-arm-none-eabi - - git clone https://github.com/libopencm3/libopencm3 script: - make -C libopencm3 - - TOOLCHAIN_DIR=libopencm3 make - - TOOLCHAIN_DIR=../libopencm3 make -C firmware - - TOOLCHAIN_DIR=../libopencm3 make -C bootloader - - TOOLCHAIN_DIR=../libopencm3 make -C demo + - make + - make -C firmware + - make -C bootloader + - make -C demo diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index d571d95e10..1aaf2c35e7 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -8,13 +8,10 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ - cd libopencm3 && + make -C libopencm3 && \ make && \ - cd .. && \ - make && \ - cd firmware && \ - make && \ - cp trezor.bin /output/trezor-$FIRMWARETAG.bin" + make -C firmware && \ + cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin" echo "---------------------" echo "Firmware fingerprint:" From 6e3aec0c1b120c8527e271c7cc90901d1cac8566 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 15 Dec 2015 23:01:54 +0100 Subject: [PATCH 0178/1154] move submodules to vendor subdirectory --- .gitmodules | 8 +++---- Makefile.include | 6 ++--- bootloader/Makefile | 12 +++++----- demo/Makefile | 18 +++++++-------- firmware-docker-build.sh | 2 +- firmware/Makefile | 32 +++++++++++++-------------- firmware/protob/messages.proto | 2 +- firmware/protob/storage.proto | 2 +- firmware/protob/types.proto | 2 +- gen/bitmaps/.gitignore | 2 -- libopencm3 | 1 - setup.c | 2 +- trezor-crypto | 1 - vendor/libopencm3 | 1 + trezor-common => vendor/trezor-common | 0 vendor/trezor-crypto | 1 + trezor-qrenc => vendor/trezor-qrenc | 0 17 files changed, 45 insertions(+), 47 deletions(-) delete mode 100644 gen/bitmaps/.gitignore delete mode 160000 libopencm3 delete mode 160000 trezor-crypto create mode 160000 vendor/libopencm3 rename trezor-common => vendor/trezor-common (100%) create mode 160000 vendor/trezor-crypto rename trezor-qrenc => vendor/trezor-qrenc (100%) diff --git a/.gitmodules b/.gitmodules index 87453ddb1e..4fe0f75397 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "trezor-crypto"] - path = trezor-crypto + path = vendor/trezor-crypto url = https://github.com/trezor/trezor-crypto.git [submodule "trezor-common"] - path = trezor-common + path = vendor/trezor-common url = https://github.com/trezor/trezor-common.git [submodule "trezor-qrenc"] - path = trezor-qrenc + path = vendor/trezor-qrenc url = https://github.com/trezor/trezor-qrenc.git [submodule "libopencm3"] - path = libopencm3 + path = vendor/libopencm3 url = https://github.com/libopencm3/libopencm3.git diff --git a/Makefile.include b/Makefile.include index 97bc3a6045..6a83e366c4 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,5 +1,5 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -TOOLCHAIN_DIR ?= $(TOP_DIR)libopencm3 +TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc @@ -43,8 +43,8 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOOLCHAIN_DIR)/include \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ - -I$(TOP_DIR)trezor-crypto \ - -I$(TOP_DIR)trezor-qrenc + -I$(TOP_DIR)vendor/trezor-crypto \ + -I$(TOP_DIR)vendor/trezor-qrenc ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) diff --git a/bootloader/Makefile b/bootloader/Makefile index 1d87042ca2..85b9aa0480 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -4,12 +4,12 @@ OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o -OBJS += ../trezor-crypto/bignum.o -OBJS += ../trezor-crypto/ecdsa.small.o -OBJS += ../trezor-crypto/hmac.o -OBJS += ../trezor-crypto/ripemd160.o -OBJS += ../trezor-crypto/secp256k1.small.o -OBJS += ../trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/ecdsa.small.o +OBJS += ../vendor/trezor-crypto/hmac.o +OBJS += ../vendor/trezor-crypto/ripemd160.o +OBJS += ../vendor/trezor-crypto/secp256k1.small.o +OBJS += ../vendor/trezor-crypto/sha2.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 diff --git a/demo/Makefile b/demo/Makefile index 5f16147c7e..57dcb068e3 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -4,14 +4,14 @@ NAME = demo OBJS += demo.o -OBJS += ../trezor-crypto/bignum.o -OBJS += ../trezor-crypto/bip32.o -OBJS += ../trezor-crypto/ecdsa.o -OBJS += ../trezor-crypto/hmac.o -OBJS += ../trezor-crypto/ripemd160.o -OBJS += ../trezor-crypto/secp256k1.o -OBJS += ../trezor-crypto/sha2.o -OBJS += ../trezor-crypto/bip39.o -OBJS += ../trezor-crypto/pbkdf2.o +OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/bip32.o +OBJS += ../vendor/trezor-crypto/ecdsa.o +OBJS += ../vendor/trezor-crypto/hmac.o +OBJS += ../vendor/trezor-crypto/ripemd160.o +OBJS += ../vendor/trezor-crypto/secp256k1.o +OBJS += ../vendor/trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/bip39.o +OBJS += ../vendor/trezor-crypto/pbkdf2.o include ../Makefile.include diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 1aaf2c35e7..7deeff5f7a 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -8,7 +8,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ - make -C libopencm3 && \ + make -C vendor/libopencm3 && \ make && \ make -C firmware && \ cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin" diff --git a/firmware/Makefile b/firmware/Makefile index fa4aa3e16a..bd86a79a5a 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -19,25 +19,25 @@ OBJS += crypto.o OBJS += debug.o -OBJS += ../trezor-crypto/bignum.o -OBJS += ../trezor-crypto/ecdsa.o -OBJS += ../trezor-crypto/secp256k1.o -OBJS += ../trezor-crypto/nist256p1.o -OBJS += ../trezor-crypto/hmac.o -OBJS += ../trezor-crypto/bip32.o -OBJS += ../trezor-crypto/bip39.o -OBJS += ../trezor-crypto/pbkdf2.o -OBJS += ../trezor-crypto/base58.o +OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/ecdsa.o +OBJS += ../vendor/trezor-crypto/secp256k1.o +OBJS += ../vendor/trezor-crypto/nist256p1.o +OBJS += ../vendor/trezor-crypto/hmac.o +OBJS += ../vendor/trezor-crypto/bip32.o +OBJS += ../vendor/trezor-crypto/bip39.o +OBJS += ../vendor/trezor-crypto/pbkdf2.o +OBJS += ../vendor/trezor-crypto/base58.o -OBJS += ../trezor-crypto/ripemd160.o -OBJS += ../trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/ripemd160.o +OBJS += ../vendor/trezor-crypto/sha2.o -OBJS += ../trezor-crypto/aescrypt.o -OBJS += ../trezor-crypto/aeskey.o -OBJS += ../trezor-crypto/aestab.o -OBJS += ../trezor-crypto/aes_modes.o +OBJS += ../vendor/trezor-crypto/aescrypt.o +OBJS += ../vendor/trezor-crypto/aeskey.o +OBJS += ../vendor/trezor-crypto/aestab.o +OBJS += ../vendor/trezor-crypto/aes_modes.o -OBJS += ../trezor-qrenc/qr_encode.o +OBJS += ../vendor/trezor-qrenc/qr_encode.o # OBJS += protob/pb_common.o OBJS += protob/pb_decode.o diff --git a/firmware/protob/messages.proto b/firmware/protob/messages.proto index f788ef73ab..4f4140fbd0 120000 --- a/firmware/protob/messages.proto +++ b/firmware/protob/messages.proto @@ -1 +1 @@ -../../trezor-common/protob/messages.proto \ No newline at end of file +../../vendor/trezor-common/protob/messages.proto \ No newline at end of file diff --git a/firmware/protob/storage.proto b/firmware/protob/storage.proto index b7b890d7bf..7502e62f6d 120000 --- a/firmware/protob/storage.proto +++ b/firmware/protob/storage.proto @@ -1 +1 @@ -../../trezor-common/protob/storage.proto \ No newline at end of file +../../vendor/trezor-common/protob/storage.proto \ No newline at end of file diff --git a/firmware/protob/types.proto b/firmware/protob/types.proto index 6f8a7a998f..8eed39a0a4 120000 --- a/firmware/protob/types.proto +++ b/firmware/protob/types.proto @@ -1 +1 @@ -../../trezor-common/protob/types.proto \ No newline at end of file +../../vendor/trezor-common/protob/types.proto \ No newline at end of file diff --git a/gen/bitmaps/.gitignore b/gen/bitmaps/.gitignore deleted file mode 100644 index 68359a7869..0000000000 --- a/gen/bitmaps/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.c -*.h diff --git a/libopencm3 b/libopencm3 deleted file mode 160000 index b1049f9a6f..0000000000 --- a/libopencm3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b1049f9a6f43882968dcf82ca1df3f1eee67e367 diff --git a/setup.c b/setup.c index cb6ad1bf03..c85bd8d0c1 100644 --- a/setup.c +++ b/setup.c @@ -25,7 +25,7 @@ void setup(void) { // setup clock - clock_scale_t clock = hse_8mhz_3v3[CLOCK_3V3_120MHZ]; + struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; rcc_clock_setup_hse_3v3(&clock); // enable GPIO clock - A (oled), B(oled), C (buttons) diff --git a/trezor-crypto b/trezor-crypto deleted file mode 160000 index cbbc0bdc71..0000000000 --- a/trezor-crypto +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cbbc0bdc7197e74d647aedcbfd064c43544318cf diff --git a/vendor/libopencm3 b/vendor/libopencm3 new file mode 160000 index 0000000000..e8a4a37b9c --- /dev/null +++ b/vendor/libopencm3 @@ -0,0 +1 @@ +Subproject commit e8a4a37b9c2f1f1cfad4d1f92b8151dac3f113c0 diff --git a/trezor-common b/vendor/trezor-common similarity index 100% rename from trezor-common rename to vendor/trezor-common diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto new file mode 160000 index 0000000000..3556c74740 --- /dev/null +++ b/vendor/trezor-crypto @@ -0,0 +1 @@ +Subproject commit 3556c74740b64484eeec4716d57c197828b330a0 diff --git a/trezor-qrenc b/vendor/trezor-qrenc similarity index 100% rename from trezor-qrenc rename to vendor/trezor-qrenc From 18b7b8bdc3d755bc1667efeae5f2d288d75bb046 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 15 Dec 2015 23:22:42 +0100 Subject: [PATCH 0179/1154] fix travis build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2ccad05c84..8bb34ee731 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ install: - sudo apt-get install -y build-essential git gcc-arm-none-eabi script: - - make -C libopencm3 + - make -C vendor/libopencm3 - make - make -C firmware - make -C bootloader From 285f06fe2f820b2483b3da7df2360025d8a9dc87 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 15:13:39 +0100 Subject: [PATCH 0180/1154] update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 3556c74740..9a8e982153 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 3556c74740b64484eeec4716d57c197828b330a0 +Subproject commit 9a8e982153d3acab75c0707e3c88872f6c5c781c From 1d3c7ee3f2225171994aa2669b9ceed06796b6f8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 15:36:43 +0100 Subject: [PATCH 0181/1154] cleanup Waking up screen usage --- firmware/storage.c | 2 -- vendor/trezor-crypto | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index da046c50a5..047f110f32 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -270,7 +270,6 @@ bool storage_getRootNode(HDNode *node) uint8_t secret[64]; uint8_t salt[12]; memcpy(salt, "TREZORHD", 8); - layoutProgressSwipe("Waking up", 0); pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); @@ -288,7 +287,6 @@ bool storage_getRootNode(HDNode *node) return false; } uint8_t seed[64]; - layoutProgressSwipe("Waking up", 0); mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039 if (hdnode_from_seed(seed, sizeof(seed), &sessionRootNode) == 0) { return false; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 9a8e982153..fbc0df736a 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 9a8e982153d3acab75c0707e3c88872f6c5c781c +Subproject commit fbc0df736a6583d1fa3b89d4e57889bd9ad3a191 From 0eab05cd53aa50701db1b7600654e8f4d1f5e349 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jan 2016 20:39:05 +0100 Subject: [PATCH 0182/1154] add gitian build (work in progress) --- gitian/gitian.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 gitian/gitian.yml diff --git a/gitian/gitian.yml b/gitian/gitian.yml new file mode 100644 index 0000000000..2f24b9777f --- /dev/null +++ b/gitian/gitian.yml @@ -0,0 +1,19 @@ +--- +name: "trezor-mcu" +enable_cache: true +suites: +- "trusty" +architectures: +- "amd64" +packages: +- "build-essential" +- "gcc-arm-none-eabi" +reference_datetime: "2015-06-01 00:00:00" +remotes: +- "url": "https://github.com/trezor/trezor-mcu.git" + "dir": "trezor-mcu" +files: [] +script: | + make -C vendor/libopencm3 + make + make -C firmware From 63bc16d375461af744f36c8cf83df21d03267671 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Feb 2016 13:53:08 +0100 Subject: [PATCH 0183/1154] signatures_ok function in bootloader exports firmware hash if needed --- bootloader/bootloader.c | 2 +- bootloader/signatures.c | 16 ++++++++++++---- bootloader/signatures.h | 2 +- bootloader/usb.c | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 065b83a097..10613943f3 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -128,7 +128,7 @@ int main(void) oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); - if (!signatures_ok()) { + if (!signatures_ok(NULL)) { show_unofficial_warning(); } diff --git a/bootloader/signatures.c b/bootloader/signatures.c index 85e921666f..a4bca418ba 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -18,10 +18,12 @@ */ #include +#include #include "signatures.h" #include "ecdsa.h" #include "secp256k1.h" +#include "sha2.h" #include "bootloader.h" #define PUBKEYS 5 @@ -36,7 +38,7 @@ static const uint8_t *pubkey[PUBKEYS] = { #define SIGNATURES 3 -int signatures_ok(void) +int signatures_ok(uint8_t *store_hash) { uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); uint8_t sigindex1, sigindex2, sigindex3; @@ -53,13 +55,19 @@ int signatures_ok(void) if (sigindex1 == sigindex3) return 0; // duplicate use if (sigindex2 == sigindex3) return 0; // duplicate use - if (ecdsa_verify(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + uint8_t hash[32]; + sha256_Raw((uint8_t *)FLASH_APP_START, codelen, hash); + if (store_hash) { + memcpy(store_hash, hash, 32); + } + + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure return 0; } - if (ecdsa_verify(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, hash) != 0) { // failure return 0; } - if (ecdsa_verify(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, hash) != 0) { // failture return 0; } diff --git a/bootloader/signatures.h b/bootloader/signatures.h index e081be3520..019609346d 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -20,6 +20,6 @@ #ifndef __SIGNATURES_H__ #define __SIGNATURES_H__ -int signatures_ok(void); +int signatures_ok(uint8_t *store_hash); #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 94c93fcc2e..9363a3d6c8 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -444,7 +444,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); // check if to restore old storage area but only if signatures are ok - if ((flags & 0x01) && signatures_ok()) { + if ((flags & 0x01) && signatures_ok(NULL)) { // copy new stuff memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); // replace "TRZR" in header with 0000 when hash not confirmed From fa0b238b4516d2b142f7c0c318ce1f909bb9847b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Feb 2016 14:16:59 +0100 Subject: [PATCH 0184/1154] show firmware hash screen after unofficial firmware dialog --- bootloader/bootloader.c | 41 ++++++++++++++++++++++++++++++++++------- bootloader/bootloader.h | 6 ++++-- bootloader/usb.c | 12 +++--------- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 10613943f3..48f3cba8d4 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -38,7 +38,23 @@ #error Bootloader cannot be used in app mode #endif -void show_unofficial_warning(void) +void layoutFirmwareHash(uint8_t *hash) +{ + char str[4][17]; + int i; + for (i = 0; i < 4; i++) { + data2hex(hash + i * 8, 8, str[i]); + } + layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); +} + +void show_halt(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + system_halt(); +} + +void show_unofficial_warning(uint8_t *hash) { layoutDialog(DIALOG_ICON_WARNING, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); @@ -47,12 +63,22 @@ void show_unofficial_warning(void) buttonUpdate(); } while (!button.YesUp && !button.NoUp); - if (button.YesUp) { - return; // yes button was pressed -> return + if (button.NoUp) { + show_halt(); // no button was pressed -> halt } - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); - system_halt(); + layoutFirmwareHash(hash); + + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + + if (button.NoUp) { + show_halt(); // no button was pressed -> halt + } + + // everything is OK, user pressed 2x Continue -> continue program } void load_app(void) @@ -128,8 +154,9 @@ int main(void) oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); - if (!signatures_ok(NULL)) { - show_unofficial_warning(); + uint8_t hash[32]; + if (!signatures_ok(hash)) { + show_unofficial_warning(hash); } load_app(); diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 3546d150d0..3a37d60443 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,15 +22,17 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 -#define VERSION_PATCH 5 +#define VERSION_PATCH 6 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x02" -#define VERSION_PATCH_CHAR "\x05" +#define VERSION_PATCH_CHAR "\x06" #include "memory.h" +void layoutFirmwareHash(uint8_t *hash); + #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 9363a3d6c8..e9355d6673 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -425,15 +425,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (msg_id != 0x001B) { // ButtonAck message (id 27) return; } - char digest[64]; - sha256_End(&ctx, digest); - char str[4][17]; - strlcpy(str[0], digest, 17); - strlcpy(str[1], digest + 16, 17); - strlcpy(str[2], digest + 32, 17); - strlcpy(str[3], digest + 48, 17); - layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); - + uint8_t hash[32]; + sha256_Final(hash, &ctx); + layoutFirmwareHash(hash); do { delay(100000); buttonUpdate(); From 4c9149818a846266ebc029a54ec74e9746ba07f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 12 Feb 2016 18:29:06 +0100 Subject: [PATCH 0185/1154] bump version (to 1.3.5) --- firmware/trezor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index a9cf8b83e4..a3ea5f4b48 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 4 +#define VERSION_PATCH 5 #define STR(X) #X #define VERSTR(X) STR(X) From 28651bd96662fd1cb13453efbfaa38ad26ed8bce Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Feb 2016 14:44:19 +0100 Subject: [PATCH 0186/1154] update submodules --- vendor/libopencm3 | 2 +- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- vendor/trezor-qrenc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/libopencm3 b/vendor/libopencm3 index e8a4a37b9c..6d4a7d1d0c 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit e8a4a37b9c2f1f1cfad4d1f92b8151dac3f113c0 +Subproject commit 6d4a7d1d0c2697e5a515e4943d4734987979a7cf diff --git a/vendor/trezor-common b/vendor/trezor-common index 9983a12276..4eca753fcf 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 9983a12276689afff8e28e1bd78605b8e6d63c1c +Subproject commit 4eca753fcfb94acdb87f73e05c4235bb5420a5a1 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index fbc0df736a..bb52cb4ac9 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit fbc0df736a6583d1fa3b89d4e57889bd9ad3a191 +Subproject commit bb52cb4ac93dd36e22bac7fef003f5b5488f2e08 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 1183aa7146..9e0228f54d 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 1183aa714615dfaa9cfb771bca7ec8c11929a4c2 +Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380 From 7675a0aa5ff6e82f300c50df13a71ff0b81f9b44 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Feb 2016 15:29:19 +0100 Subject: [PATCH 0187/1154] fix usage of inline/static --- firmware/messages.c | 6 +++--- util.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 7803efee62..50d37da97e 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -139,7 +139,7 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE]; #endif -inline void msg_out_append(uint8_t c) +static inline void msg_out_append(uint8_t c) { if (msg_out_cur == 0) { msg_out[msg_out_end * 64] = '?'; @@ -155,7 +155,7 @@ inline void msg_out_append(uint8_t c) #if DEBUG_LINK -inline void msg_debug_out_append(uint8_t c) +static inline void msg_debug_out_append(uint8_t c) { if (msg_debug_out_cur == 0) { msg_debug_out[msg_debug_out_end * 64] = '?'; @@ -171,7 +171,7 @@ inline void msg_debug_out_append(uint8_t c) #endif -inline void msg_out_pad(void) +static inline void msg_out_pad(void) { if (msg_out_cur == 0) return; while (msg_out_cur < 64) { diff --git a/util.h b/util.h index d7bb5b4244..e31c5801c8 100644 --- a/util.h +++ b/util.h @@ -22,7 +22,7 @@ #include -inline void delay(uint32_t wait); +void delay(uint32_t wait); // converts uint32 to hexa (8 digits) void uint32hex(uint32_t num, char *str); From a7ef132ce507f8f365391aba284dabeb290afc23 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Feb 2016 00:21:09 +0100 Subject: [PATCH 0188/1154] rework OPTFLAGS, add DBGFLAGS (so it's easier to just replace -O3 to -Os for building bootloader) --- Makefile.include | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 6a83e366c4..82803f5b93 100644 --- a/Makefile.include +++ b/Makefile.include @@ -9,9 +9,11 @@ OBJDUMP = $(PREFIX)objdump FLASH = st-flash OPENOCD = openocd -OPTFLAGS = -O3 -g -DNDEBUG +OPTFLAGS ?= -O3 +DBGFLAGS ?= -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ + $(DBGFLAGS) \ -W \ -Wall \ -Wextra \ From da027f7652dd25ff7071562b57f3dd9a9349db72 Mon Sep 17 00:00:00 2001 From: karek314 Date: Fri, 19 Feb 2016 00:24:33 +0100 Subject: [PATCH 0189/1154] bootloader autobuild in docker --- README.md | 12 +++++++++++- bootloader-docker-build.sh | 21 +++++++++++++++++++++ firmware-docker-build.sh | 6 ++++-- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100755 bootloader-docker-build.sh diff --git a/README.md b/README.md index 5c5786626c..c52f67cb26 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,23 @@ http://bitcointrezor.com/ How to build TREZOR firmware? ----------------------------- -1. Install Docker (from docker.com or from your distribution repositories) +1. Install Docker 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` 4. `./firmware-docker-build.sh TAG` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log. +How to build TREZOR bootloader? +----------------------------- + +1. Install Docker +2. `git clone https://github.com/trezor/trezor-mcu.git` +3. `cd trezor-mcu` +4. `./bootloader-docker-build.sh` + +This creates file `output/bootloader.bin` and prints its fingerprint and size at the last line of the build log. + How to get fingerprint of firmware signed and distributed by SatoshiLabs? ------------------------------------------------------------------------- diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh new file mode 100755 index 0000000000..918a64ec17 --- /dev/null +++ b/bootloader-docker-build.sh @@ -0,0 +1,21 @@ +#!/bin/bash +IMAGETAG=trezor-mcu-build +FIRMWARETAG=${1:-master} + +docker build -t $IMAGETAG . +docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ + git clone https://github.com/trezor/trezor-mcu && \ + cd trezor-mcu && \ + git checkout $FIRMWARETAG && \ + git submodule update --init && \ + make -C vendor/libopencm3 && \ + make && \ + make -C bootloader && \ + cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin" + +echo "---------------------" +echo "Bootloader fingerprint:" +FILENAME=output/bootloader-$FIRMWARETAG.bin +sha256sum "$FILENAME" +FILESIZE=$(stat -c%s "$FILENAME") +echo "Bootloader size: $FILESIZE bytes (out of 32768 maximum)" diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 7deeff5f7a..cd95ac5b7e 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -15,5 +15,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ echo "---------------------" echo "Firmware fingerprint:" - -sha256sum output/trezor-$FIRMWARETAG.bin +FILENAME=output/trezor-$FIRMWARETAG.bin +sha256sum "$FILENAME" +FILESIZE=$(stat -c%s "$FILENAME") +echo "Firmware size: $FILESIZE bytes (out of 491520 maximum)" From d77152b5a5ac88a8804373d3d9b1d1f65e5cbe4c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Feb 2016 13:33:55 +0100 Subject: [PATCH 0190/1154] use OPTFLAGS=-Os for bootloader docker build --- bootloader-docker-build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index 918a64ec17..636a095aa0 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -9,6 +9,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ git checkout $FIRMWARETAG && \ git submodule update --init && \ make -C vendor/libopencm3 && \ + export OPTFLAGS=-Os make && \ make -C bootloader && \ cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin" From d8aeb63854e102bea0fcd75f3d2a816d6db3fde8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Apr 2016 04:47:09 +0200 Subject: [PATCH 0191/1154] pass version/lock_time parameters from SignTx message to signing_init function --- firmware/fsm.c | 2 +- firmware/protob/messages.pb.c | 12 ++++++++++-- firmware/protob/messages.pb.h | 32 ++++++++++++++++++++++++-------- firmware/signing.c | 8 +++++--- firmware/signing.h | 2 +- vendor/libopencm3 | 2 +- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 8 files changed, 44 insertions(+), 18 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index a9cd886e61..f505c3b23c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -404,7 +404,7 @@ void fsm_msgSignTx(SignTx *msg) const HDNode *node = fsm_getDerivedNode(0, 0); if (!node) return; - signing_init(msg->inputs_count, msg->outputs_count, coin, node); + signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); } void fsm_msgCancel(Cancel *msg) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 9ef79a45ac..b0eb77ff23 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -12,7 +12,11 @@ const char SignMessage_coin_name_default[17] = "Bitcoin"; const char EncryptMessage_coin_name_default[17] = "Bitcoin"; const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; +const uint32_t SignTx_version_default = 1u; +const uint32_t SignTx_lock_time_default = 0u; const char SimpleSignTx_coin_name_default[17] = "Bitcoin"; +const uint32_t SimpleSignTx_version_default = 1u; +const uint32_t SimpleSignTx_lock_time_default = 0u; const pb_field_t Initialize_fields[1] = { @@ -280,18 +284,22 @@ const pb_field_t TxSize_fields[2] = { PB_LAST_FIELD }; -const pb_field_t SignTx_fields[4] = { +const pb_field_t SignTx_fields[6] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, version, coin_name, &SignTx_version_default), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, lock_time, version, &SignTx_lock_time_default), PB_LAST_FIELD }; -const pb_field_t SimpleSignTx_fields[5] = { +const pb_field_t SimpleSignTx_fields[7] = { PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), + PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, version, coin_name, &SimpleSignTx_version_default), + PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, lock_time, version, &SimpleSignTx_lock_time_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index c69ac8453e..4049e7f9ed 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -553,6 +553,10 @@ typedef struct _SignTx { uint32_t inputs_count; bool has_coin_name; char coin_name[17]; + bool has_version; + uint32_t version; + bool has_lock_time; + uint32_t lock_time; } SignTx; typedef struct { @@ -583,6 +587,10 @@ typedef struct _SimpleSignTx { TransactionType transactions[0]; bool has_coin_name; char coin_name[17]; + bool has_version; + uint32_t version; + bool has_lock_time; + uint32_t lock_time; } SimpleSignTx; typedef struct _Success { @@ -642,7 +650,11 @@ extern const char SignMessage_coin_name_default[17]; extern const char EncryptMessage_coin_name_default[17]; extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; +extern const uint32_t SignTx_version_default; +extern const uint32_t SignTx_lock_time_default; extern const char SimpleSignTx_coin_name_default[17]; +extern const uint32_t SimpleSignTx_version_default; +extern const uint32_t SimpleSignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} @@ -686,8 +698,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define CipheredKeyValue_init_default {false, {0, {0}}} #define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} #define TxSize_init_default {false, 0} -#define SignTx_init_default {0, 0, false, "Bitcoin"} -#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin"} +#define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} +#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} @@ -740,8 +752,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define CipheredKeyValue_init_zero {false, {0, {0}}} #define EstimateTxSize_init_zero {0, 0, false, ""} #define TxSize_init_zero {false, 0} -#define SignTx_init_zero {0, 0, false, ""} -#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""} +#define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} +#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} @@ -872,6 +884,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SignTx_outputs_count_tag 1 #define SignTx_inputs_count_tag 2 #define SignTx_coin_name_tag 3 +#define SignTx_version_tag 4 +#define SignTx_lock_time_tag 5 #define SignedIdentity_address_tag 1 #define SignedIdentity_public_key_tag 2 #define SignedIdentity_signature_tag 3 @@ -879,6 +893,8 @@ extern const char SimpleSignTx_coin_name_default[17]; #define SimpleSignTx_outputs_tag 2 #define SimpleSignTx_transactions_tag 3 #define SimpleSignTx_coin_name_tag 4 +#define SimpleSignTx_version_tag 5 +#define SimpleSignTx_lock_time_tag 6 #define Success_message_tag 1 #define TxAck_tx_tag 1 #define TxRequest_request_type_tag 1 @@ -932,8 +948,8 @@ extern const pb_field_t CipherKeyValue_fields[8]; extern const pb_field_t CipheredKeyValue_fields[2]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; -extern const pb_field_t SignTx_fields[4]; -extern const pb_field_t SimpleSignTx_fields[5]; +extern const pb_field_t SignTx_fields[6]; +extern const pb_field_t SimpleSignTx_fields[7]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; @@ -988,8 +1004,8 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 #define TxSize_size 6 -#define SignTx_size 31 -#define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) +#define SignTx_size 43 +#define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) #define SignIdentity_size (558 + IdentityType_size) diff --git a/firmware/signing.c b/firmware/signing.c index 289315bc37..43999fd0df 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -51,8 +51,8 @@ static TxStruct to, tp, ti; static SHA256_CTX tc; static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; static uint64_t to_spend, spending, change_spend; -const uint32_t version = 1; -const uint32_t lock_time = 0; +static uint32_t version = 1; +static uint32_t lock_time = 0; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; @@ -224,12 +224,14 @@ void send_req_finished(void) msg_write(MessageType_MessageType_TxRequest, &resp); } -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root) +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time) { inputs_count = _inputs_count; outputs_count = _outputs_count; coin = _coin; root = _root; + version = _version; + lock_time = _lock_time; idx1 = 0; to_spend = 0; diff --git a/firmware/signing.h b/firmware/signing.h index bcb66fec6b..ef1b9914ee 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -25,7 +25,7 @@ #include "bip32.h" #include "types.pb.h" -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root); +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); void signing_abort(void); void signing_txack(TransactionType *tx); diff --git a/vendor/libopencm3 b/vendor/libopencm3 index 6d4a7d1d0c..d3fff11c1f 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit 6d4a7d1d0c2697e5a515e4943d4734987979a7cf +Subproject commit d3fff11c1f68b706591c0d51c82d18a0bc88dc17 diff --git a/vendor/trezor-common b/vendor/trezor-common index 4eca753fcf..0567a429cf 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 4eca753fcfb94acdb87f73e05c4235bb5420a5a1 +Subproject commit 0567a429cfc8c6fdf9e08c79270750c102fc4f70 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index bb52cb4ac9..f4dd151eb9 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit bb52cb4ac93dd36e22bac7fef003f5b5488f2e08 +Subproject commit f4dd151eb9ef989b88dc79218a2b0115934e4268 From 56238e63fc5389daad209c1a9e4558815772f337 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 19 Apr 2016 18:23:12 +0200 Subject: [PATCH 0192/1154] Added curve type to HD node. Create a different root node for every curve type to separate the key space. --- firmware/crypto.c | 2 +- firmware/fsm.c | 44 +++++++++++---------------- firmware/storage.c | 72 +++++++++++++++++++++++--------------------- firmware/storage.h | 4 ++- vendor/trezor-crypto | 2 +- 5 files changed, 61 insertions(+), 63 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 84d611de68..27e07fd6a7 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -282,7 +282,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node) == 0) { + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { return 0; } layoutProgressUpdate(true); diff --git a/firmware/fsm.c b/firmware/fsm.c index f505c3b23c..b3466c7852 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -93,10 +93,10 @@ const CoinType *fsm_getCoin(const char *name) return coin; } -const HDNode *fsm_getDerivedNode(uint32_t *address_n, size_t address_n_count) +const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) { static HDNode node; - if (!storage_getRootNode(&node)) { + if (!storage_getRootNode(&node, curve)) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); layoutHome(); return 0; @@ -292,20 +292,16 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) return; } - const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + const HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count); if (!node) return; uint8_t public_key[33]; // copy public key to temporary buffer memcpy(public_key, node->public_key, sizeof(public_key)); - if (msg->has_ecdsa_curve_name) { - const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); - if (curve) { - // correct public key (since fsm_getDerivedNode uses secp256k1 curve) - ecdsa_get_public_key33(curve, node->private_key, public_key); - } - } - if (msg->has_show_display && msg->show_display) { layoutPublicKey(public_key); if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { @@ -401,7 +397,7 @@ void fsm_msgSignTx(SignTx *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(0, 0); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0); if (!node) return; signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); @@ -445,7 +441,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) layoutHome(); return; } - const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; bool encrypt = msg->has_encrypt && msg->encrypt; @@ -566,7 +562,7 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; if (msg->has_multisig) { @@ -646,7 +642,7 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe("Signing", 0); @@ -724,20 +720,16 @@ void fsm_msgSignIdentity(SignIdentity *msg) address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); - const HDNode *node = fsm_getDerivedNode(address_n, 5); + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); if (!node) return; uint8_t public_key[33]; // copy public key to temporary buffer memcpy(public_key, node->public_key, sizeof(public_key)); - if (msg->has_ecdsa_curve_name) { - const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); - if (curve) { - // correct public key (since fsm_getDerivedNode uses secp256k1 curve) - ecdsa_get_public_key33(curve, node->private_key, public_key); - } - } - bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); int result = 0; @@ -807,7 +799,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) layoutHome(); return; } - node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; uint8_t public_key[33]; ecdsa_get_public_key33(&secp256k1, node->private_key, public_key); @@ -859,7 +851,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) layoutHome(); return; } - const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe("Decrypting", 0); diff --git a/firmware/storage.c b/firmware/storage.c index 047f110f32..a2c4ce2b31 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -45,8 +45,8 @@ Storage storage; uint8_t storage_uuid[12]; char storage_uuid_str[25]; -static bool sessionRootNodeCached; -static HDNode sessionRootNode; +static bool sessionSeedCached; +static uint8_t sessionSeed[64]; static bool sessionPinCached; @@ -126,8 +126,10 @@ void storage_reset(void) void session_clear(bool clear_pin) { - sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); - sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); + sessionSeedCached = false; + memset(&sessionSeed, 0, sizeof(sessionSeed)); + sessionPassphraseCached = false; + memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); if (clear_pin) { sessionPinCached = false; } @@ -186,14 +188,14 @@ void storage_loadDevice(LoadDevice *msg) storage.has_node = true; storage.has_mnemonic = false; memcpy(&storage.node, &(msg->node), sizeof(HDNodeType)); - sessionRootNodeCached = false; - memset(&sessionRootNode, 0, sizeof(sessionRootNode)); + sessionSeedCached = false; + memset(&sessionSeed, 0, sizeof(sessionSeed)); } else if (msg->has_mnemonic) { storage.has_mnemonic = true; storage.has_node = false; strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic)); - sessionRootNodeCached = false; - memset(&sessionRootNode, 0, sizeof(sessionRootNode)); + sessionSeedCached = false; + memset(&sessionSeed, 0, sizeof(sessionSeed)); } if (msg->has_language) { @@ -224,7 +226,7 @@ void storage_setLanguage(const char *lang) void storage_setPassphraseProtection(bool passphrase_protection) { - sessionRootNodeCached = false; + sessionSeedCached = false; sessionPassphraseCached = false; storage.has_passphrase_protection = true; @@ -249,20 +251,34 @@ void get_root_node_callback(uint32_t iter, uint32_t total) layoutProgress("Waking up", 1000 * iter / total); } -bool storage_getRootNode(HDNode *node) +const uint8_t *storage_getSeed(void) { // root node is properly cached - if (sessionRootNodeCached) { - memcpy(node, &sessionRootNode, sizeof(HDNode)); - return true; + if (sessionSeedCached) { + return sessionSeed; } + // if storage has mnemonic, convert it to node and use it + if (storage.has_mnemonic) { + if (!protectPassphrase()) { + return NULL; + } + mnemonic_to_seed(storage.mnemonic, sessionPassphrase, sessionSeed, get_root_node_callback); // BIP-0039 + sessionSeedCached = true; + return sessionSeed; + } + + return NULL; +} + +bool storage_getRootNode(HDNode *node, const char *curve) +{ // if storage has node, decrypt and use it - if (storage.has_node) { + if (storage.has_node && strcmp(curve, "secp256k1") == 0) { if (!protectPassphrase()) { return false; } - if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode) == 0) { + if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { return false; } if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { @@ -273,30 +289,18 @@ bool storage_getRootNode(HDNode *node) pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); - aes_cbc_decrypt(sessionRootNode.chain_code, sessionRootNode.chain_code, 32, secret + 32, &ctx); - aes_cbc_decrypt(sessionRootNode.private_key, sessionRootNode.private_key, 32, secret + 32, &ctx); + aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); + aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); } - memcpy(node, &sessionRootNode, sizeof(HDNode)); - sessionRootNodeCached = true; return true; } - // if storage has mnemonic, convert it to node and use it - if (storage.has_mnemonic) { - if (!protectPassphrase()) { - return false; - } - uint8_t seed[64]; - mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039 - if (hdnode_from_seed(seed, sizeof(seed), &sessionRootNode) == 0) { - return false; - } - memcpy(node, &sessionRootNode, sizeof(HDNode)); - sessionRootNodeCached = true; - return true; + const uint8_t *seed = storage_getSeed(); + if (seed == NULL) { + return false; } - - return false; + + return hdnode_from_seed(seed, 64, curve, node); } const char *storage_getLabel(void) diff --git a/firmware/storage.h b/firmware/storage.h index b1041a8b93..fb7b6b779d 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -33,7 +33,9 @@ void session_clear(bool clear_pin); void storage_loadDevice(LoadDevice *msg); -bool storage_getRootNode(HDNode *node); +const uint8_t *storage_getSeed(void); + +bool storage_getRootNode(HDNode *node, const char *curve); const char *storage_getLabel(void); void storage_setLabel(const char *label); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f4dd151eb9..c983afd72f 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f4dd151eb9ef989b88dc79218a2b0115934e4268 +Subproject commit c983afd72f40a8c65355af076afd9c132878e8a5 From 03c501d9e3633248bf3423a29827de398e656ac0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 20 Apr 2016 15:39:15 +0200 Subject: [PATCH 0193/1154] Do not use hardcoded string for secp256k1. --- firmware/storage.c | 3 ++- vendor/trezor-crypto | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index a2c4ce2b31..19e70dd2d0 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -31,6 +31,7 @@ #include "pbkdf2.h" #include "bip32.h" #include "bip39.h" +#include "secp256k1.h" #include "util.h" #include "memory.h" #include "rng.h" @@ -274,7 +275,7 @@ const uint8_t *storage_getSeed(void) bool storage_getRootNode(HDNode *node, const char *curve) { // if storage has node, decrypt and use it - if (storage.has_node && strcmp(curve, "secp256k1") == 0) { + if (storage.has_node && strcmp(curve, SECP256K1_NAME) == 0) { if (!protectPassphrase()) { return false; } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index c983afd72f..d577410fc4 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit c983afd72f40a8c65355af076afd9c132878e8a5 +Subproject commit d577410fc4a87262c107fb25657158f8f8ba720e From 0fa0e331f29be60fa2796e0ea328213fa86b71e9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Apr 2016 16:54:04 +0200 Subject: [PATCH 0194/1154] update trezor-crypto submodule --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index d577410fc4..bf34b4269c 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit d577410fc4a87262c107fb25657158f8f8ba720e +Subproject commit bf34b4269ccb9ab929625506a5370ea9c8382139 From 2b2414cb91e11685b490d4417cf16c7d0d606181 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 15 Apr 2016 22:04:45 +0300 Subject: [PATCH 0195/1154] Add GPG v2.1 support by signing message digest --- firmware/crypto.c | 10 ++++++++++ firmware/crypto.h | 2 ++ firmware/fsm.c | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 27e07fd6a7..201a7c128b 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -90,6 +90,16 @@ int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *pr return ecdsa_sign(&nist256p1, privkey, message, message_len, signature + 1, NULL); } +int gpgMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) +{ + // GPG should sign a SHA256 digest of the original message. + if (message_len != 32) { + return 1; + } + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + return ecdsa_sign_digest(&nist256p1, privkey, message, signature + 1, NULL); +} + int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) { SHA256_CTX ctx; diff --git a/firmware/crypto.h b/firmware/crypto.h index b9d03fde8a..aefdc97a19 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -34,6 +34,8 @@ uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); +int gpgMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); + int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index b3466c7852..ef983638ea 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -731,11 +731,14 @@ void fsm_msgSignIdentity(SignIdentity *msg) memcpy(public_key, node->public_key, sizeof(public_key)); bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); + bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); int result = 0; layoutProgressSwipe("Signing", 0); if (sign_ssh) { // SSH does not sign visual challenge result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); + } else if (sign_gpg) { // GPG should sign a message digest + result = gpgMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); } else { uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); @@ -744,7 +747,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) } if (result == 0) { - if (sign_ssh) { + if (curve != SECP256K1_NAME) { resp->has_address = false; } else { resp->has_address = true; From 6813ffb431a48c96dd691e4d7f60c7f16535995d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 21 Apr 2016 07:29:20 +0200 Subject: [PATCH 0196/1154] Remove the public_key hack. It is no longer necessary to move the public key into a temporary buffer since the node is specific for the curve and contains the right public key. --- firmware/fsm.c | 16 +++++----------- vendor/trezor-crypto | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ef983638ea..64e0dbf588 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -97,7 +97,7 @@ const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t { static HDNode node; if (!storage_getRootNode(&node, curve)) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve"); layoutHome(); return 0; } @@ -299,11 +299,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) const HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count); if (!node) return; - uint8_t public_key[33]; // copy public key to temporary buffer - memcpy(public_key, node->public_key, sizeof(public_key)); - if (msg->has_show_display && msg->show_display) { - layoutPublicKey(public_key); + layoutPublicKey(node->public_key); if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show public key cancelled"); layoutHome(); @@ -319,7 +316,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.has_private_key = false; resp->node.has_public_key = true; resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, public_key, 33); + memcpy(resp->node.public_key.bytes, node->public_key, 33); resp->has_xpub = true; hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); @@ -727,9 +724,6 @@ void fsm_msgSignIdentity(SignIdentity *msg) const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); if (!node) return; - uint8_t public_key[33]; // copy public key to temporary buffer - memcpy(public_key, node->public_key, sizeof(public_key)); - bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); @@ -747,7 +741,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) } if (result == 0) { - if (curve != SECP256K1_NAME) { + if (strcmp(curve, SECP256K1_NAME) != 0) { resp->has_address = false; } else { resp->has_address = true; @@ -757,7 +751,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) } resp->has_public_key = true; resp->public_key.size = 33; - memcpy(resp->public_key.bytes, public_key, 33); + memcpy(resp->public_key.bytes, node->public_key, 33); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index bf34b4269c..de30ffbf9a 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit bf34b4269ccb9ab929625506a5370ea9c8382139 +Subproject commit de30ffbf9a68bfd6f2fb3633f855998c8e375628 From 51f02ff763c69ce6270c9f80695e44ccf45dff39 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 22 Apr 2016 17:49:00 +0200 Subject: [PATCH 0197/1154] ed25519 support --- Makefile.include | 1 + firmware/Makefile | 4 ++++ firmware/crypto.c | 18 ++++++++++-------- firmware/crypto.h | 7 ++++--- firmware/fsm.c | 10 +++++----- firmware/storage.c | 2 +- vendor/trezor-crypto | 2 +- 7 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Makefile.include b/Makefile.include index 82803f5b93..782d2d59c1 100644 --- a/Makefile.include +++ b/Makefile.include @@ -46,6 +46,7 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ + -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc ifdef APPVER diff --git a/firmware/Makefile b/firmware/Makefile index bd86a79a5a..b44135d463 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -21,8 +21,10 @@ OBJS += debug.o OBJS += ../vendor/trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/ecdsa.o +OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o @@ -54,3 +56,5 @@ CFLAGS += -DQR_MAX_VERSION=0 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' +CFLAGS += -DED25519_CUSTOMRANDOM=1 +CFLAGS += -DED25519_CUSTOMHASH=1 diff --git a/firmware/crypto.c b/firmware/crypto.c index 201a7c128b..b57a2828d7 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -25,8 +25,8 @@ #include "hmac.h" #include "bip32.h" #include "layout.h" +#include "curves.h" #include "secp256k1.h" -#include "nist256p1.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -84,23 +84,23 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } -int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) +int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return ecdsa_sign(&nist256p1, privkey, message, message_len, signature + 1, NULL); + return hdnode_sign(node, message, message_len, signature + 1, NULL); } -int gpgMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) +int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { // GPG should sign a SHA256 digest of the original message. if (message_len != 32) { return 1; } signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return ecdsa_sign_digest(&nist256p1, privkey, message, signature + 1, NULL); + return hdnode_sign_digest(node, message, signature + 1, NULL); } -int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature) +int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -113,7 +113,7 @@ int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t sha256_Final(hash, &ctx); sha256_Raw(hash, 32, hash); uint8_t pby; - int result = ecdsa_sign_digest(&secp256k1, privkey, hash, signature + 1, &pby); + int result = hdnode_sign_digest(node, hash, signature + 1, &pby); if (result == 0) { signature[0] = 27 + pby + 4; } @@ -183,11 +183,13 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) { if (privkey && address_raw) { // signing == true + HDNode node; payload[0] = display_only ? 0x81 : 0x01; uint32_t l = ser_length(msg_size, payload + 1); memcpy(payload + 1 + l, msg, msg_size); memcpy(payload + 1 + l + msg_size, address_raw, 21); - if (cryptoMessageSign(msg, msg_size, privkey, payload + 1 + l + msg_size + 21) != 0) { + hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node); + if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) { return 1; } *payload_len = 1 + l + msg_size + 21 + 65; diff --git a/firmware/crypto.h b/firmware/crypto.h index aefdc97a19..efde2265dc 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "types.pb.h" @@ -32,11 +33,11 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); -int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); +int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int gpgMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); +int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature); +int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 64e0dbf588..bf79eb59cc 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -44,8 +44,8 @@ #include "base58.h" #include "bip39.h" #include "ripemd160.h" +#include "curves.h" #include "secp256k1.h" -#include "nist256p1.h" // message methods @@ -643,7 +643,7 @@ void fsm_msgSignMessage(SignMessage *msg) if (!node) return; layoutProgressSwipe("Signing", 0); - if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { + if (cryptoMessageSign(node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); @@ -730,14 +730,14 @@ void fsm_msgSignIdentity(SignIdentity *msg) int result = 0; layoutProgressSwipe("Signing", 0); if (sign_ssh) { // SSH does not sign visual challenge - result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); + result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); } else if (sign_gpg) { // GPG should sign a message digest - result = gpgMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); + result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); } else { uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes); + result = cryptoMessageSign(node, digest, 64, resp->signature.bytes); } if (result == 0) { diff --git a/firmware/storage.c b/firmware/storage.c index 19e70dd2d0..4f5fb9e71b 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -31,7 +31,7 @@ #include "pbkdf2.h" #include "bip32.h" #include "bip39.h" -#include "secp256k1.h" +#include "curves.h" #include "util.h" #include "memory.h" #include "rng.h" diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index de30ffbf9a..55edf71e27 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit de30ffbf9a68bfd6f2fb3633f855998c8e375628 +Subproject commit 55edf71e274c4b803f9b0acb2847df51532fa302 From 9e8c369f93f36ca0219527eb138531c1abe61dd9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Apr 2016 23:03:57 +0200 Subject: [PATCH 0198/1154] show address in verifymessage layout --- firmware/fsm.c | 12 +++++++++++- firmware/layout2.c | 10 +++++++++- firmware/layout2.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index bf79eb59cc..4d99c850f2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -673,8 +673,18 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); } if (msg->signature.size == 65 && cryptoMessageVerify(msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { + layoutVerifyAddress(msg->address); + if (!protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); + layoutHome(); + return; + } layoutVerifyMessage(msg->message.bytes, msg->message.size); - protectButton(ButtonRequestType_ButtonRequest_Other, true); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); + layoutHome(); + return; + } fsm_sendSuccess("Message verified"); } else { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); diff --git a/firmware/layout2.c b/firmware/layout2.c index f10d2ce43f..75039bc4fb 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -196,10 +196,18 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) str[0], str[1], str[2], str[3], NULL, NULL); } +void layoutVerifyAddress(const char *address) +{ + const char **str = split_message((const uint8_t *)address, strlen(address), 17); + layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", + "Address from signature:", + NULL, str[0], str[1], str[2], NULL, NULL); +} + void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", + layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", "Verified message", str[0], str[1], str[2], str[3], NULL, NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index 90ce8e1963..1b725d5c5c 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -32,6 +32,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutSignMessage(const uint8_t *msg, uint32_t len); +void layoutVerifyAddress(const char *address); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); From 035a6e754ff51de8b1b07414fae6a7126d280e3b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Apr 2016 23:40:24 +0200 Subject: [PATCH 0199/1154] fix last commit --- firmware/fsm.c | 2 +- firmware/layout2.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4d99c850f2..930a761810 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -674,7 +674,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) } if (msg->signature.size == 65 && cryptoMessageVerify(msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); - if (!protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); layoutHome(); return; diff --git a/firmware/layout2.c b/firmware/layout2.c index 75039bc4fb..4dee967dff 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -200,8 +200,9 @@ void layoutVerifyAddress(const char *address) { const char **str = split_message((const uint8_t *)address, strlen(address), 17); layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", + "Confirm address?", "Address from signature:", - NULL, str[0], str[1], str[2], NULL, NULL); + NULL, str[0], str[1], str[2], NULL); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) From b8539a6972f1ee4524dab6b754658de083d55a42 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Apr 2016 23:46:36 +0200 Subject: [PATCH 0200/1154] fix wording --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 4dee967dff..4d77c385ac 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -201,7 +201,7 @@ void layoutVerifyAddress(const char *address) const char **str = split_message((const uint8_t *)address, strlen(address), 17); layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", "Confirm address?", - "Address from signature:", + "Message signed by:", NULL, str[0], str[1], str[2], NULL); } From 5e5138066afa2db79f5658ccb7ab23ec7bb2430d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 26 Apr 2016 11:53:58 +0200 Subject: [PATCH 0201/1154] adapt the reorder of hash_final functions --- bootloader/usb.c | 2 +- firmware/crypto.c | 8 ++++---- firmware/reset.c | 2 +- firmware/signing.c | 4 ++-- firmware/transaction.c | 4 ++-- vendor/trezor-crypto | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index e9355d6673..0f17df6a0c 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -426,7 +426,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } uint8_t hash[32]; - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); layoutFirmwareHash(hash); do { delay(100000); diff --git a/firmware/crypto.c b/firmware/crypto.c index b57a2828d7..22f545ecfc 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -110,7 +110,7 @@ int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message sha256_Update(&ctx, varint, l); sha256_Update(&ctx, message, message_len); uint8_t hash[32]; - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); sha256_Raw(hash, 32, hash); uint8_t pby; int result = hdnode_sign_digest(node, hash, signature + 1, &pby); @@ -151,7 +151,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ uint32_t l = ser_length(message_len, varint); sha256_Update(&ctx, varint, l); sha256_Update(&ctx, message, message_len); - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); sha256_Raw(hash, 32, hash); // e = -hash bn_read_be(hash, &e); @@ -357,7 +357,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); } sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); layoutProgressUpdate(true); return 1; } @@ -385,6 +385,6 @@ int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) if (identity->has_path && identity->path[0]) { sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); } - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); return 1; } diff --git a/firmware/reset.c b/firmware/reset.c index 8ec4c1bc7b..1ecad15f4d 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -89,7 +89,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Init(&ctx); sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); - sha256_Final(int_entropy, &ctx); + sha256_Final(&ctx, int_entropy); strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic)); memset(int_entropy, 0, 32); awaiting_entropy = false; diff --git a/firmware/signing.c b/firmware/signing.c index 43999fd0df..cfc28d6984 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -416,7 +416,7 @@ void signing_txack(TransactionType *tx) idx1++; send_req_3_output(); } else { - sha256_Final(hash_check, &tc); + sha256_Final(&tc, hash_check); // check fees if (spending > to_spend) { fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); @@ -527,7 +527,7 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_output(); } else { - sha256_Final(hash, &tc); + sha256_Final(&tc, hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 61b98090bf..45b70da2d0 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -223,7 +223,7 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, d[1] = 0xAE; sha256_Update(&ctx, d, 2); - sha256_Final(hash, &ctx); + sha256_Final(&ctx, hash); return 1; } @@ -425,7 +425,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { - sha256_Final(hash, &(t->ctx)); + sha256_Final(&(t->ctx), hash); sha256_Raw(hash, 32, hash); if (!reverse) return; uint8_t i, k; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 55edf71e27..ed6debf8c4 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 55edf71e274c4b803f9b0acb2847df51532fa302 +Subproject commit ed6debf8c4ec5ef9c7ef31a1a7eddf76aa33ccd8 From e0539f8f8bd8493471987d5ce1e4729588e00a4e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 25 Apr 2016 13:14:15 +0200 Subject: [PATCH 0202/1154] Move public key recovery (verify) to trezor-crypto --- firmware/crypto.c | 54 ++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 22f545ecfc..e49b4b27a0 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -122,28 +122,9 @@ int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) { - bignum256 r, s, e; - curve_point cp, cp2; SHA256_CTX ctx; uint8_t pubkey[65], addr_raw[21], hash[32]; - uint8_t nV = signature[0]; - if (nV < 27 || nV >= 35) { - return 1; - } - bool compressed; - compressed = (nV >= 31); - if (compressed) { - nV -= 4; - } - uint8_t recid = nV - 27; - // read r and s - bn_read_be(signature + 1, &r); - bn_read_be(signature + 33, &s); - // x = r - memcpy(&cp.x, &r, sizeof(bignum256)); - // compute y from x - uncompress_coords(&secp256k1, recid % 2, &cp.x, &cp.y); // calculate hash sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); @@ -153,30 +134,27 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ sha256_Update(&ctx, message, message_len); sha256_Final(&ctx, hash); sha256_Raw(hash, 32, hash); - // e = -hash - bn_read_be(hash, &e); - bn_subtract(&secp256k1.order, &e, &e); - // r = r^-1 - bn_inverse(&r, &secp256k1.order); - point_multiply(&secp256k1, &s, &cp, &cp); - scalar_multiply(&secp256k1, &e, &cp2); - point_add(&secp256k1, &cp2, &cp); - point_multiply(&secp256k1, &r, &cp, &cp); - pubkey[0] = 0x04; - bn_write_be(&cp.x, pubkey + 1); - bn_write_be(&cp.y, pubkey + 33); - // check if the address is correct - if (compressed) { - pubkey[0] = 0x02 | (cp.y.val[0] & 0x01); + + uint8_t recid = signature[0] - 27; + if (recid >= 8) { + return 1; } + bool compressed = (recid >= 4); + recid &= 3; + + // check if signature verifies the digest and recover the public key + if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) { + return 3; + } + // convert public key to compressed pubkey if necessary + if (compressed) { + pubkey[0] = 0x02 | (pubkey[64] & 1); + } + // check if the address is correct ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw); if (memcmp(addr_raw, address_raw, 21) != 0) { return 2; } - // check if signature verifies the digest - if (ecdsa_verify_digest(&secp256k1, pubkey, signature + 1, hash) != 0) { - return 3; - } return 0; } From da98a3a6fdd81e0e95095f9f13d34c521bd55bc0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 18:12:03 +0200 Subject: [PATCH 0203/1154] Don't reflash storage after each PIN entry Instead of reflashing the whole storage, we use a designated area in the second storage block, where we mark each PIN failure by a single zero bit. This is because one can set bits in flash to zero but not to one. If the PIN was entered successfully the whole word is set to zero and the next word stores the new PIN failure counter. --- firmware/protect.c | 48 ++++++------- firmware/storage.c | 166 ++++++++++++++++++++++++++++----------------- firmware/storage.h | 6 +- 3 files changed, 128 insertions(+), 92 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 1cac5edf53..0ff821dac9 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -142,31 +142,29 @@ const char *requestPin(PinMatrixRequestType type, const char *text) bool protectPin(bool use_cached) { - if (!storage.has_pin || strlen(storage.pin) == 0 || (use_cached && session_isPinCached())) { + if (!storage.has_pin || storage.pin[0] == 0 || (use_cached && session_isPinCached())) { return true; } - uint32_t fails = storage_getPinFails(); - if (fails) { - uint32_t wait; - wait = (fails < 32) ? (1u << fails) : 0xFFFFFFFF; - while (--wait > 0) { - // convert wait to secstr string - char secstrbuf[20]; - strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf)); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - while (secs > 0 && secstr >= secstrbuf) { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } - if (wait == 1) { - secstrbuf[16] = 0; - } - layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); - // wait one second - usbDelay(840000); + uint32_t *fails = storage_getPinFailsPtr(); + uint32_t wait = ~*fails; + while (wait > 0) { + // convert wait to secstr string + char secstrbuf[20]; + strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf)); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + while (secs > 0 && secstr >= secstrbuf) { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; } + if (wait == 1) { + secstrbuf[16] = 0; + } + layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); + // wait one second + usbDelay(840000); + wait--; } const char *pin; pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); @@ -174,11 +172,9 @@ bool protectPin(bool use_cached) fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); return false; } - storage_increasePinFails(); - bool increase_failed = (fails >= storage_getPinFails()); - if (storage_isPinCorrect(pin) && !increase_failed) { + if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) { session_cachePin(); - storage_resetPinFails(); + storage_resetPinFails(fails); return true; } else { fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); diff --git a/firmware/storage.c b/firmware/storage.c index 4f5fb9e71b..38c2aa53b9 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -40,13 +40,38 @@ #include "protect.h" #include "layout2.h" -_Static_assert(sizeof(Storage) <= FLASH_STORAGE_LEN, "Storage struct is too large for TREZOR flash"); Storage storage; uint8_t storage_uuid[12]; char storage_uuid_str[25]; +/* + storage layout: + + offset | type/length | description +--------+-------------+------------------------------- + 0x0000 | 4 bytes | magic = 'stor' + 0x0004 | 12 bytes | uuid + 0x0010 | ? | Storage structure + 0x4000 | 4 kbytes | area for pin failures + 0x5000 | 12 kbytes | reserved + +The area for pin failures looks like this: +0 ... 0 pinfail 0xffffffff .. 0xffffffff +The pinfail is a binary number of the form 1...10...0, +the number of zeros is the number of pin failures. +This layout is used because we can only clear bits without +erasing the flash. + + */ + +#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000) +#define FLASH_STORAGE_PINAREA_LEN (0x1000) +#define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage)) +_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); + static bool sessionSeedCached; + static uint8_t sessionSeed[64]; static bool sessionPinCached; @@ -54,36 +79,41 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char sessionPassphrase[51]; -/* - storage layout: +#define STORAGE_VERSION 6 - offset | type/length | description ---------+-------------+------------------------------- - 0x0000 | 4 bytes | magic = 'stor' - 0x0004 | 12 bytes | uuid - 0x0010 | ? | Storage structure - */ - -#define STORAGE_VERSION 5 +void storage_check_flash_errors(void) +{ + // flash operation failed + if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) { } + } +} void storage_from_flash(uint32_t version) { - switch (version) { - case 1: // copy (since 1.0.0) - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); - break; - case 2: // copy (since 1.2.1) - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); - break; - case 3: // copy (since 1.3.1) - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); - break; - case 4: // copy (since 1.3.2) - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); - break; - case 5: // copy (since 1.3.3) - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); - break; + // version 1: since 1.0.0 + // version 2: since 1.2.1 + // version 3: since 1.3.1 + // version 4: since 1.3.2 + // version 5: since 1.3.3 + // version 6: since 1.3.6 + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + if (version <= 5) { + // convert PIN failure counter from version 5 format + uint32_t pinctr = storage.has_pin_failed_attempts + ? storage.pin_failed_attempts : 0; + if (pinctr > 31) + pinctr = 31; + flash_clear_status_flags(); + flash_unlock(); + // erase extra storage sector + flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); + flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); + flash_lock(); + storage_check_flash_errors(); + storage.has_pin_failed_attempts = false; + storage.pin_failed_attempts = 0; } storage.version = STORAGE_VERSION; } @@ -136,35 +166,29 @@ void session_clear(bool clear_pin) } } -static uint8_t meta_backup[FLASH_META_LEN]; - void storage_commit(void) { int i; - uint32_t *w; + uint32_t meta_backup[(FLASH_STORAGE_PINAREA - FLASH_META_START) / 4]; + // backup meta - memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); + memcpy((uint8_t*)meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); + // modify storage + memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN, "stor", 4); + memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN + 4, storage_uuid, sizeof(storage_uuid)); + memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN + 4 + sizeof(storage_uuid), &storage, sizeof(Storage)); + memset((uint8_t*)meta_backup + FLASH_META_DESC_LEN + FLASH_STORAGE_REALLEN, 0, sizeof(meta_backup) - FLASH_META_DESC_LEN - FLASH_STORAGE_REALLEN); + flash_clear_status_flags(); flash_unlock(); // erase storage - for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // modify storage - memcpy(meta_backup + FLASH_META_DESC_LEN, "stor", 4); - memcpy(meta_backup + FLASH_META_DESC_LEN + 4, storage_uuid, sizeof(storage_uuid)); - memcpy(meta_backup + FLASH_META_DESC_LEN + 4 + sizeof(storage_uuid), &storage, sizeof(Storage)); + flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); // copy it back - for (i = 0; i < FLASH_META_LEN / 4; i++) { - w = (uint32_t *)(meta_backup + i * 4); - flash_program_word(FLASH_META_START + i * 4, *w); + for (i = 0; i < (signed) (sizeof(meta_backup) / 4); i++) { + flash_program_word(FLASH_META_START + i * 4, meta_backup[i]); } flash_lock(); - // flash operation failed - if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) { } - } + storage_check_flash_errors(); } void storage_loadDevice(LoadDevice *msg) @@ -344,7 +368,7 @@ bool storage_hasPin(void) void storage_setPin(const char *pin) { - if (pin && strlen(pin) > 0) { + if (pin && pin[0]) { storage.has_pin = true; strlcpy(storage.pin, pin, sizeof(storage.pin)); } else { @@ -376,28 +400,44 @@ bool session_isPinCached(void) return sessionPinCached; } -void storage_resetPinFails(void) +void storage_resetPinFails(uint32_t *pinfailsptr) { - storage.has_pin_failed_attempts = true; - storage.pin_failed_attempts = 0; - storage_commit(); -} - -void storage_increasePinFails(void) -{ - if (!storage.has_pin_failed_attempts) { - storage.has_pin_failed_attempts = true; - storage.pin_failed_attempts = 1; + flash_clear_status_flags(); + flash_unlock(); + if ((uint32_t) (pinfailsptr + 1) - FLASH_STORAGE_PINAREA + >= FLASH_STORAGE_PINAREA_LEN) { + // erase extra storage sector + flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); } else { - storage.pin_failed_attempts++; + flash_program_word((uint32_t) pinfailsptr, 0); } - storage_commit(); + flash_lock(); + storage_check_flash_errors(); } -uint32_t storage_getPinFails(void) +bool storage_increasePinFails(uint32_t *pinfailsptr) { - storage_from_flash(STORAGE_VERSION); // reload from flash - return storage.has_pin_failed_attempts ? storage.pin_failed_attempts : 0; + uint32_t newctr = *pinfailsptr << 1; + // counter already at maximum, we do not increase it any more + // return success so that a good pin is accepted + if (!newctr) + return true; + + flash_clear_status_flags(); + flash_unlock(); + flash_program_word((uint32_t) pinfailsptr, newctr); + flash_lock(); + storage_check_flash_errors(); + + return *pinfailsptr == newctr; +} + +uint32_t *storage_getPinFailsPtr(void) +{ + uint32_t *pinfailsptr = (uint32_t *) FLASH_STORAGE_PINAREA; + while (*pinfailsptr == 0) + pinfailsptr++; + return pinfailsptr; } bool storage_isInitialized(void) diff --git a/firmware/storage.h b/firmware/storage.h index fb7b6b779d..321f276aae 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -56,9 +56,9 @@ bool storage_hasPin(void); void storage_setPin(const char *pin); void session_cachePin(void); bool session_isPinCached(void); -void storage_resetPinFails(void); -void storage_increasePinFails(void); -uint32_t storage_getPinFails(void); +void storage_resetPinFails(uint32_t *pinfailptr); +bool storage_increasePinFails(uint32_t *pinfailptr); +uint32_t *storage_getPinFailsPtr(void); bool storage_isInitialized(void); From 630e26dd201795dc9f2028b7a95d5e835d0ee6d1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 19:23:02 +0200 Subject: [PATCH 0204/1154] use less stack memory in storage_commit --- firmware/storage.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 38c2aa53b9..478269446d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -69,6 +69,8 @@ erasing the flash. #define FLASH_STORAGE_PINAREA_LEN (0x1000) #define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage)) _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); +_Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); +_Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); static bool sessionSeedCached; @@ -166,26 +168,38 @@ void session_clear(bool clear_pin) } } +static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) { + int i; + for (i = 0; i < nwords; i++) { + flash_program_word(addr, *src++); + addr += 4; + } + return addr; +} + void storage_commit(void) { - int i; - uint32_t meta_backup[(FLASH_STORAGE_PINAREA - FLASH_META_START) / 4]; + uint8_t meta_backup[FLASH_META_DESC_LEN]; // backup meta - memcpy((uint8_t*)meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); - // modify storage - memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN, "stor", 4); - memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN + 4, storage_uuid, sizeof(storage_uuid)); - memcpy((uint8_t*)meta_backup + FLASH_META_DESC_LEN + 4 + sizeof(storage_uuid), &storage, sizeof(Storage)); - memset((uint8_t*)meta_backup + FLASH_META_DESC_LEN + FLASH_STORAGE_REALLEN, 0, sizeof(meta_backup) - FLASH_META_DESC_LEN - FLASH_STORAGE_REALLEN); + memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); flash_clear_status_flags(); flash_unlock(); // erase storage flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); - // copy it back - for (i = 0; i < (signed) (sizeof(meta_backup) / 4); i++) { - flash_program_word(FLASH_META_START + i * 4, meta_backup[i]); + // copy meta + uint32_t flash = FLASH_META_START; + flash = storage_flash_words(flash, (uint32_t *)meta_backup, FLASH_META_DESC_LEN/4); + // copy storage + flash_program_word(flash, *(uint32_t *) "stor"); + flash += 4; + flash = storage_flash_words(flash, (uint32_t *)&storage_uuid, sizeof(storage_uuid)/4); + flash = storage_flash_words(flash, (uint32_t *)&storage, sizeof(storage)/4); + // fill remainder with zero for future extensions + while (flash < FLASH_STORAGE_PINAREA) { + flash_program_word(flash, 0); + flash += 4; } flash_lock(); storage_check_flash_errors(); From b3aabec5651323918c3360d1fecd7c9457b90933 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Apr 2016 14:36:11 +0200 Subject: [PATCH 0205/1154] add -std=c99 to Makefile --- Makefile.include | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.include b/Makefile.include index 782d2d59c1..5e48ba04f6 100644 --- a/Makefile.include +++ b/Makefile.include @@ -14,6 +14,7 @@ DBGFLAGS ?= -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ + -std=c99 \ -W \ -Wall \ -Wextra \ From 1f3369788a9ec27686691f8b390d2a864ab77552 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Apr 2016 16:10:41 +0200 Subject: [PATCH 0206/1154] use __asm__ instead of asm --- bootloader/bootloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 48f3cba8d4..b6b389ad99 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -85,7 +85,7 @@ void load_app(void) { // jump to app SCB_VTOR = FLASH_APP_START; // & 0xFFFF; - asm volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); + __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); (*(void (**)())(FLASH_APP_START + 4))(); } From 1b8bd1852e1dd6fe26d11ebf143d28f5ee0eba5b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 26 Apr 2016 16:44:08 +0200 Subject: [PATCH 0207/1154] Adapted U2F to new hdnode API --- firmware/u2f.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index db55c88c0d..3c737cf197 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -28,6 +28,7 @@ #include "usb.h" #include "buttons.h" #include "trezor.h" +#include "curves.h" #include "nist256p1.h" #include "rng.h" @@ -427,7 +428,7 @@ void u2f_version(const APDU *a) const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static HDNode node; - if (!storage_getRootNode(&node)) { + if (!storage_getRootNode(&node, NIST256P1_NAME)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); return 0; @@ -467,9 +468,7 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) memcpy(&keybase[0], app_id, 32); memcpy(&keybase[32], key_handle, 32); uint8_t sig[64]; - ecdsa_sign(&nist256p1, node->private_key, - (uint8_t *)&keybase, sizeof(keybase), sig, - NULL); + hdnode_sign(node, (uint8_t *)&keybase, sizeof(keybase), sig, NULL); // Copy 32 bytes of signature into keyhandle memcpy(&key_handle[32], sig, 32); @@ -494,9 +493,7 @@ const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle uint8_t sig[64]; - ecdsa_sign(&nist256p1, node->private_key, - (uint8_t *)&keybase, sizeof(keybase), sig, - NULL); + hdnode_sign(node, (uint8_t *)&keybase, sizeof(keybase), sig, NULL); if (memcmp(&key_handle[32], sig, 32) !=0) return NULL; @@ -572,7 +569,7 @@ void u2f_register(const APDU *a) return; } - ecdsa_get_public_key65(&nist256p1, node->private_key, + ecdsa_get_public_key65(node->curve->params, node->private_key, (uint8_t *)&resp->pubKey); memcpy(resp->keyHandleCertSig + resp->keyHandleLen, From 01ddb3ff6673e6c74ef77de53ae6ff53a762617e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 26 Apr 2016 22:57:46 +0200 Subject: [PATCH 0208/1154] Reduced buffer sizes, moved static info to flash --- firmware/u2f.c | 6 +++--- firmware/u2f/u2f_hid.h | 2 ++ firmware/u2f/u2f_keys.h | 20 +++++++------------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 3c737cf197..91738340a9 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -41,7 +41,7 @@ // About 1/2 Second according to values used in protect.c #define U2F_TIMEOUT 840000/2 -#define U2F_OUT_PKT_BUFFER_LEN 128 +#define U2F_OUT_PKT_BUFFER_LEN 16 // Initialise without a cid static uint32_t cid = CID_BROADCAST; @@ -171,7 +171,7 @@ void u2fhid_read(const U2FHID_FRAME *f) static uint8_t seq, cmd; static uint32_t len; static uint8_t *buf_ptr; - static uint8_t buf[7609]; + static uint8_t buf[57+7*59]; if ((f->cid != CID_BROADCAST) && (f->cid != cid)) { return; // Not for us @@ -291,7 +291,7 @@ void u2fhid_init(const U2FHID_INIT_REQ *init_req) f.cid = CID_BROADCAST; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; - f.init.bcntl = sizeof(U2FHID_INIT_RESP); + f.init.bcntl = U2FHID_INIT_RESP_SIZE; memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); resp->cid = next_cid(); diff --git a/firmware/u2f/u2f_hid.h b/firmware/u2f/u2f_hid.h index d576d197c3..326a3fc223 100644 --- a/firmware/u2f/u2f_hid.h +++ b/firmware/u2f/u2f_hid.h @@ -120,6 +120,8 @@ extern "C" uint8_t capFlags; // Capabilities flags } U2FHID_INIT_RESP; +#define U2FHID_INIT_RESP_SIZE 17 + // Low-level error codes. Return as negatives. #define ERR_NONE 0x00 // No error diff --git a/firmware/u2f/u2f_keys.h b/firmware/u2f/u2f_keys.h index 73c8378f71..94b9302b1d 100644 --- a/firmware/u2f/u2f_keys.h +++ b/firmware/u2f/u2f_keys.h @@ -3,20 +3,14 @@ #include -uint8_t U2F_ATT_PRIV_KEY[] = {0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, - 0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, - 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, - 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b}; +const uint8_t U2F_ATT_PRIV_KEY[] = { + 0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, + 0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, + 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, + 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b +}; -uint8_t U2F_ATT_PUB_KEY[] = { - 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9, 0x0d, - 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36, - 0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, - 0x52, 0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, - 0xdb, 0x8a, 0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, - 0x43, 0xa5, 0x26, 0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1}; - -uint8_t U2F_ATT_CERT[] = { +const uint8_t U2F_ATT_CERT[] = { 0x30, 0x82, 0x01, 0x19, 0x30, 0x81, 0xC0, 0x02, 0x09, 0x00, 0x8B, 0x3F, 0xA6, 0x46, 0xDE, 0x01, 0xCB, 0xB8, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, From b3bfc64d2fff6ed85664b3dabfd6fde499e13b94 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 12:27:29 +0200 Subject: [PATCH 0209/1154] Use hmac for checking key integrity --- firmware/u2f.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 91738340a9..e2ba10f986 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -31,6 +31,7 @@ #include "curves.h" #include "nist256p1.h" #include "rng.h" +#include "hmac.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" @@ -467,11 +468,8 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) // Signature of app_id and random data memcpy(&keybase[0], app_id, 32); memcpy(&keybase[32], key_handle, 32); - uint8_t sig[64]; - hdnode_sign(node, (uint8_t *)&keybase, sizeof(keybase), sig, NULL); - - // Copy 32 bytes of signature into keyhandle - memcpy(&key_handle[32], sig, 32); + hmac_sha256(node->private_key, sizeof(node->private_key), + keybase, sizeof(keybase), &key_handle[32]); // Done! return node; @@ -492,10 +490,11 @@ const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle memcpy(&keybase[32], key_handle, 32); - uint8_t sig[64]; - hdnode_sign(node, (uint8_t *)&keybase, sizeof(keybase), sig, NULL); + uint8_t hmac[32]; + hmac_sha256(node->private_key, sizeof(node->private_key), + keybase, sizeof(keybase), hmac); - if (memcmp(&key_handle[32], sig, 32) !=0) + if (memcmp(&key_handle[32], hmac, 32) != 0) return NULL; // Done! From 5c13e78debaf439ec1690d9869cbf0f1acf6da85 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 12:54:49 +0200 Subject: [PATCH 0210/1154] Added support for known appid. --- firmware/u2f.c | 48 ++++++++++++++++----------------- firmware/u2f_knownapps.h | 57 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 firmware/u2f_knownapps.h diff --git a/firmware/u2f.c b/firmware/u2f.c index e2ba10f986..a9701f97a0 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -32,10 +32,12 @@ #include "nist256p1.h" #include "rng.h" #include "hmac.h" +#include "util.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" #include "u2f/u2f_keys.h" +#include "u2f_knownapps.h" #include "u2f.h" #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -96,31 +98,12 @@ uint8_t buttonState(void) return 0; } -void int2hex(uint8_t *dst, const uint32_t i) -{ - dst[0] = '0' + ((i >> 28) & 0x0F); - dst[1] = '0' + ((i >> 24) & 0x0F); - dst[2] = '0' + ((i >> 20) & 0x0F); - dst[3] = '0' + ((i >> 16) & 0x0F); - dst[4] = '0' + ((i >> 12) & 0x0F); - dst[5] = '0' + ((i >> 8) & 0x0F); - dst[6] = '0' + ((i >> 4) & 0x0F); - dst[7] = '0' + (i & 0x0F); - dst[8] = '\0'; - - int t = 0; - for (; t < 8; t++) { - if (dst[t] > '9') - dst[t] += 7; // 'A'-'9'+1 - } -} - char *debugInt(const uint32_t i) { static uint8_t n = 0; - static uint8_t id[8][9]; - int2hex(id[n], i); - debugLog(0, "", (const char *)id[n]); + static char id[8][9]; + uint32hex(i, id[n]); + debugLog(0, "", id[n]); char *ret = (char *)id[n]; n = (n + 1) % 8; return ret; @@ -426,6 +409,21 @@ void u2f_version(const APDU *a) send_u2f_msg(version_response, sizeof(version_response)); } +static const char *getReadableAppId(const uint8_t appid[32]) { + unsigned int i; + static char buf[6+2+6+1]; + + for (i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { + if (memcmp(appid, u2f_well_known[i].appid, 32) == 0) + return u2f_well_known[i].appname; + } + + data2hex(appid, 3, &buf[0]); + buf[6] = buf[7] = '.'; + data2hex(appid+(sizeof(appid)-3), 3, &buf[8]); + return buf; +} + const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static HDNode node; @@ -529,7 +527,8 @@ void u2f_register(const APDU *a) send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Register", - NULL, "Register U2F", "security key", "", "", "", NULL); + NULL, "Register U2F", "security key", + "", getReadableAppId(req->appId), "", NULL); dialog_timeout = U2F_TIMEOUT; last_req_state = REG; return; @@ -661,7 +660,8 @@ void u2f_authenticate(const APDU *a) send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Authenticate", NULL, - "Authenticate U2F", "security key", "", "", "", NULL); + "Authenticate U2F", "security key", + "", getReadableAppId(req->appId), "", NULL); dialog_timeout = U2F_TIMEOUT; last_req_state = AUTH; return; diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h new file mode 100644 index 0000000000..ca3d1732fb --- /dev/null +++ b/firmware/u2f_knownapps.h @@ -0,0 +1,57 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __U2F_KNOWNAPPS_H_INCLUDED__ +#define __U2F_KNOWNAPPS_H_INCLUDED__ + +#include + +typedef struct { + uint8_t appid[32]; + const char *appname; +} U2FWellKnown; + +static const U2FWellKnown u2f_well_known[3] = { + { + // didn't feel like tracing that one yet + { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, + 0xe1,0x51,0xed,0x8d,0x4d,0x3c,0x76,0x7a, + 0x6c,0xc3,0x49,0x43,0x59,0x43,0x79,0x4e, + 0x88,0x4f,0x3d,0x02,0x3a,0x82,0x29,0xfd }, + "Google" + }, + { + // https://github.com/u2f/trusted_facets + { 0x70,0x61,0x7d,0xfe,0xd0,0x65,0x86,0x3a, + 0xf4,0x7c,0x15,0x55,0x6c,0x91,0x79,0x88, + 0x80,0x82,0x8c,0xc4,0x07,0xfd,0xf7,0x0a, + 0xe8,0x50,0x11,0x56,0x94,0x65,0xa0,0x75 }, + "Github" + }, + { + // https://www.dropbox.com/u2f-app-id.json + { 0xc5,0x0f,0x8a,0x7b,0x70,0x8e,0x92,0xf8, + 0x2e,0x7a,0x50,0xe2,0xbd,0xc5,0x5d,0x8f, + 0xd9,0x1a,0x22,0xfe,0x6b,0x29,0xc0,0xcd, + 0xf7,0x80,0x55,0x30,0x84,0x2a,0xf5,0x81 }, + "Dropbox" + } +}; + +#endif // U2F_KNOWNAPPS_INCLUDED From 2abe5d477ee8070094ccd6e539a8766c882bef5b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 13:37:45 +0200 Subject: [PATCH 0211/1154] Clean-up. Better checks for buffer overflow. --- firmware/u2f.c | 54 +++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index a9701f97a0..acf4a0ac64 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -168,26 +168,34 @@ void u2fhid_read(const U2FHID_FRAME *f) cmd = f->type; memcpy(buf_ptr, f->init.data, sizeof(f->init.data)); buf_ptr += sizeof(f->init.data); + + // Broadcast is reserved for init + if (cid == CID_BROADCAST && cmd != U2FHID_INIT) + return; + + // Check length isnt bigger than spec max + if (len > sizeof(buf)) { + len = 0; + return send_u2fhid_error(ERR_INVALID_LEN); + } } else { + // Broadcast is reserved for init + if (cid == CID_BROADCAST) + return; + // check out of bounds + if ((buf_ptr - buf) >= (signed) len + || (buf_ptr + sizeof(f->cont.data) - buf) > (signed) sizeof(buf)) + return; if (f->cont.seq == seq) { seq++; memcpy(buf_ptr, f->cont.data, sizeof(f->cont.data)); buf_ptr += sizeof(f->cont.data); - } - else { + } else { return send_u2fhid_error(ERR_INVALID_SEQ); } } - // Broadcast is reserved for init - if (cid == CID_BROADCAST && cmd != U2FHID_INIT) - return; - - // Check length isnt bigger than spec max - if (len > sizeof(buf)) - return send_u2fhid_error(ERR_INVALID_LEN); - // Do we need to wait for more data if ((buf_ptr - buf) < (signed)len) { // debugLog(0, "", "u2fhid_read wait"); @@ -202,18 +210,12 @@ void u2fhid_read(const U2FHID_FRAME *f) case U2FHID_MSG: u2fhid_msg((APDU *)buf, len); break; - case U2FHID_LOCK: - u2fhid_lock(buf, len); - break; case U2FHID_INIT: u2fhid_init((const U2FHID_INIT_REQ *)buf); break; case U2FHID_WINK: u2fhid_wink(buf, len); break; - // case U2FHID_SYNC: - // u2fhid_sync(buf, len); - break; default: send_u2fhid_error(ERR_INVALID_CMD); break; @@ -245,26 +247,6 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) queue_u2f_pkt(&f); } -void u2fhid_sync(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_sync"); - (void)buf; - - if (len > 0) - return send_u2fhid_error(ERR_INVALID_LEN); - - // Abort things. - dialog_timeout = 0; -} - -void u2fhid_lock(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_lock"); - (void)buf; - (void)len; - send_u2fhid_error(ERR_INVALID_CMD); -} - void u2fhid_init(const U2FHID_INIT_REQ *init_req) { debugLog(0, "", "u2fhid_init"); From c1ff9e1ec70ca7b86152368cfdc69989bff48b94 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 28 Apr 2016 15:00:34 +0200 Subject: [PATCH 0212/1154] Use more sensible hid descriptor. --- firmware/usb.c | 75 +++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 59 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index e084742af7..df087594fa 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -52,66 +52,23 @@ static const struct usb_device_descriptor dev_descr = { .bNumConfigurations = 1, }; -/* got via usbhid-dump from CP2110 */ static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, - 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, - 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, - 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, - 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, - 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, - 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, - 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, - 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, - 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, - 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, - 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, - 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, - 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, - 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, - 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, - 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, - 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, - 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, - 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, - 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, - 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, + 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) + 0x09, 0x01, // USAGE + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75,0x08, // REPORT_SIZE (8) + 0x95,0x40, // REPORT_COUNT (64) + 0x81,0x02, // INPUT (Data,Var,Abs) + 0x09,0x21, // USAGE (Output Report Data) + 0x15,0x00, // LOGICAL_MINIMUM (0) + 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75,0x08, // REPORT_SIZE (8) + 0x95,0x40, // REPORT_COUNT (64) + 0x91,0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION }; static const uint8_t hid_report_descriptor_u2f[] = { From 6218770e2671028c167170e97d6152435b959552 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 15:32:18 +0200 Subject: [PATCH 0213/1154] Script to generate key and certificate --- firmware/u2f/genkeys.sh | 45 ++++++++++++++++++++++++++++++++ firmware/u2f/trezordevkey.pem | 5 ++++ firmware/u2f/u2f_keys.h | 48 +++++++++++++++++------------------ vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 5 files changed, 76 insertions(+), 26 deletions(-) create mode 100644 firmware/u2f/genkeys.sh create mode 100644 firmware/u2f/trezordevkey.pem diff --git a/firmware/u2f/genkeys.sh b/firmware/u2f/genkeys.sh new file mode 100644 index 0000000000..3bc7e5b10b --- /dev/null +++ b/firmware/u2f/genkeys.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +cat > u2f_keys.h < + +const uint8_t U2F_ATT_PRIV_KEY[] = { +EOF + +if [ \! -e trezordevkey.pem ]; then + openssl ecparam -genkey -out trezordevkey.pem -name prime256v1 +fi +openssl ec -in trezordevkey.pem -text | + perl -e '$key = "\t"; while (<>) { + if (/priv:/) { $priv = 1 } + elsif (/pub:/) { $priv = 0 } + elsif ($priv) { + while ($_ =~ s/.*?([0-9a-f]{2})//) { + $key .= "0x$1,"; + if ($num++ % 8 == 7) { $key .= "\n\t"; } + else {$key .= " ";} + } + } + } + $key =~ s/,\s*$/\n/s; + print $key;' >> u2f_keys.h +cat >> u2f_keys.h <> u2f_keys.h + +cat >> u2f_keys.h < Date: Fri, 29 Apr 2016 17:06:21 +0200 Subject: [PATCH 0214/1154] fix bugs in debug --- Makefile.include | 2 +- firmware/debug.c | 2 +- firmware/messages.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index 5e48ba04f6..f931984328 100644 --- a/Makefile.include +++ b/Makefile.include @@ -14,7 +14,7 @@ DBGFLAGS ?= -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ - -std=c99 \ + -std=gnu99 \ -W \ -Wall \ -Wextra \ diff --git a/firmware/debug.c b/firmware/debug.c index 0149b4d507..3bb5dcfec9 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -35,7 +35,7 @@ void oledDebug(const char *line) oledClear(); for (i = 0; i < 8; i++) { if (lines[i]) { - oledDrawChar(0, i * 8, '0' + (id + i) % 10); + oledDrawChar(0, i * 8, '0' + (id + i) % 10, 1); oledDrawString(8, i * 8, lines[i]); } } diff --git a/firmware/messages.c b/firmware/messages.c index 50d37da97e..9d50729179 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -184,7 +184,7 @@ static inline void msg_out_pad(void) #if DEBUG_LINK -inline void msg_debug_out_pad(void) +static inline void msg_debug_out_pad(void) { if (msg_debug_out_cur == 0) return; while (msg_debug_out_cur < 64) { From a5feab0175551032f774197da91600c81414aafb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Apr 2016 17:52:16 +0200 Subject: [PATCH 0215/1154] update submodules --- firmware/protob/types.pb.c | 6 +++++- firmware/protob/types.pb.h | 16 ++++++++++++---- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index c45448f314..e0fa2959f3 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -5,6 +5,8 @@ const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_p2sh_default = 5u; +const uint32_t CoinType_address_type_p2wpkh_default = 6u; +const uint32_t CoinType_address_type_p2wsh_default = 10u; const uint32_t TxInputType_sequence_default = 4294967295u; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const uint32_t IdentityType_index_default = 0u; @@ -26,12 +28,14 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[6] = { +const pb_field_t CoinType_fields[8] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), + PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wpkh, address_type_p2sh, &CoinType_address_type_p2wpkh_default), + PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wsh, address_type_p2wpkh, &CoinType_address_type_p2wsh_default), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 29e8e9ec92..a20ca4a025 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -75,6 +75,10 @@ typedef struct _CoinType { uint64_t maxfee_kb; bool has_address_type_p2sh; uint32_t address_type_p2sh; + bool has_address_type_p2wpkh; + uint32_t address_type_p2wpkh; + bool has_address_type_p2wsh; + uint32_t address_type_p2wsh; } CoinType; typedef struct { @@ -248,6 +252,8 @@ extern const pb_extension_type_t wire_debug_out; /* Default values for struct fields */ extern const uint32_t CoinType_address_type_default; extern const uint32_t CoinType_address_type_p2sh_default; +extern const uint32_t CoinType_address_type_p2wpkh_default; +extern const uint32_t CoinType_address_type_p2wsh_default; extern const uint32_t TxInputType_sequence_default; extern const InputScriptType TxInputType_script_type_default; extern const uint32_t IdentityType_index_default; @@ -255,7 +261,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -266,7 +272,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -282,6 +288,8 @@ extern const uint32_t IdentityType_index_default; #define CoinType_address_type_tag 3 #define CoinType_maxfee_kb_tag 4 #define CoinType_address_type_p2sh_tag 5 +#define CoinType_address_type_p2wpkh_tag 6 +#define CoinType_address_type_p2wsh_tag 7 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -334,7 +342,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[6]; +extern const pb_field_t CoinType_fields[8]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; extern const pb_field_t TxOutputType_fields[7]; @@ -347,7 +355,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 53 +#define CoinType_size 65 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5497 #define TxOutputType_size 3929 diff --git a/vendor/trezor-common b/vendor/trezor-common index 0567a429cf..8c6401bdef 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0567a429cfc8c6fdf9e08c79270750c102fc4f70 +Subproject commit 8c6401bdef92ebef7375a0e58a06af117618519d diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index ed6debf8c4..b8ec5567ba 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit ed6debf8c4ec5ef9c7ef31a1a7eddf76aa33ccd8 +Subproject commit b8ec5567ba701c77379f2111774456eb18b98790 From 8be6956ce921510752e6ff7be56797e06ce61f21 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 22:36:43 +0200 Subject: [PATCH 0216/1154] fix compilation updated coins datastructure to include the new fields --- firmware/coins.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 1200b118b6..4d25088244 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,12 +21,12 @@ #include "coins.h" const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22}, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16}, + {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0}, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0}, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0}, }; const CoinType *coinByShortcut(const char *shortcut) From 5430c82b2b1dbdd43c89de419ef92b754bed4c91 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 8 May 2016 14:25:17 +0200 Subject: [PATCH 0217/1154] use the latest ubuntu lts in docker build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 29efb93146..a7eb16ca8a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # initialize from the image -FROM ubuntu:14.04 +FROM ubuntu:16.04 # update repositories From e27dc48a3ab0af0ac73f31804a5bacb486f392a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 May 2016 14:38:04 +0200 Subject: [PATCH 0218/1154] add make vendor --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 4d13b6063e..f67ae0febc 100644 --- a/Makefile +++ b/Makefile @@ -13,3 +13,8 @@ libtrezor.a: $(OBJS) ar rcs libtrezor.a $(OBJS) include Makefile.include + +.PHONY: vendor + +vendor: + git submodule update --init From 87a451d9a4c23032500fcf641bf391a0d75eca39 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 May 2016 21:07:56 +0200 Subject: [PATCH 0219/1154] update readme --- README.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c52f67cb26..fc7ae64fc5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ -TREZOR Firmware -=============== +# TREZOR Firmware -[![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) +[![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) http://bitcointrezor.com/ -How to build TREZOR firmware? ------------------------------ +## How to build TREZOR firmware? 1. Install Docker 2. `git clone https://github.com/trezor/trezor-mcu.git` @@ -15,8 +13,7 @@ How to build TREZOR firmware? This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log. -How to build TREZOR bootloader? ------------------------------ +## How to build TREZOR bootloader? 1. Install Docker 2. `git clone https://github.com/trezor/trezor-mcu.git` @@ -25,8 +22,7 @@ How to build TREZOR bootloader? This creates file `output/bootloader.bin` and prints its fingerprint and size at the last line of the build log. -How to get fingerprint of firmware signed and distributed by SatoshiLabs? -------------------------------------------------------------------------- +## How to get fingerprint of firmware signed and distributed by SatoshiLabs? 1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json 2. Download it: `wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex` From 0e876bcec21db00b732a395b17ff0494db54abdd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 20:28:14 +0200 Subject: [PATCH 0220/1154] update submodules --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b8ec5567ba..75f2396624 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b8ec5567ba701c77379f2111774456eb18b98790 +Subproject commit 75f239662468edece3e076ad8f7f927b8c4722e0 From def4a9a02c260450f92fc9c4088fb7a8bef30c7f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 21:05:17 +0200 Subject: [PATCH 0221/1154] fix pbkdf2 usage in storage.c --- firmware/storage.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 478269446d..8d7f15a568 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -323,9 +323,14 @@ bool storage_getRootNode(HDNode *node, const char *curve) if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { // decrypt hd node uint8_t secret[64]; - uint8_t salt[12]; - memcpy(salt, "TREZORHD", 8); - pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); + PBKDF2_HMAC_SHA512_CTX pctx; + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8); + get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); + } + pbkdf2_hmac_sha512_Final(&pctx, secret); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); From 7201545cfc4efb532d031a9e098473ee6e352b5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 21:05:37 +0200 Subject: [PATCH 0222/1154] update submodule --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 75f2396624..51c0bb09d8 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 75f239662468edece3e076ad8f7f927b8c4722e0 +Subproject commit 51c0bb09d8f1066555d28ae3824988b318d2f39e From e1fa896d6c9e9027e95d0b8b31032fcd943dd5ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 12 May 2016 21:09:00 +0200 Subject: [PATCH 0223/1154] disable ECIES --- firmware/crypto.c | 10 ++++++---- firmware/crypto.h | 4 ++-- firmware/fsm.c | 2 ++ firmware/messages.c | 4 ++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index e49b4b27a0..eb986abde9 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -158,6 +158,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_ return 0; } +/* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) { if (privkey && address_raw) { // signing == true @@ -195,10 +196,10 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz bn_write_be(&R.x, shared_secret + 1); // generate keying bytes uint8_t keying_bytes[80]; - uint8_t salt[22 + 33 + 4]; + uint8_t salt[22 + 33]; memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt + 22, nonce, 33); - pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); // encrypt payload aes_encrypt_ctx ctx; aes_encrypt_key256(keying_bytes, &ctx); @@ -227,11 +228,11 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le bn_write_be(&R.x, shared_secret + 1); // generate keying bytes uint8_t keying_bytes[80]; - uint8_t salt[22 + 33 + 4]; + uint8_t salt[22 + 33]; memcpy(salt, "Bitcoin Secure Message", 22); salt[22] = 0x02 | (nonce->y.val[0] & 0x01); bn_write_be(&(nonce->x), salt + 23); - pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); // compute hmac uint8_t out[32]; hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); @@ -267,6 +268,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le *msg_len = o; return 0; } +*/ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { diff --git a/firmware/crypto.h b/firmware/crypto.h index efde2265dc..11adee1ccb 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -41,11 +41,11 @@ int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); -// ECIES: http://memwallet.info/btcmssgs.html - +/* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); +*/ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); diff --git a/firmware/fsm.c b/firmware/fsm.c index 930a761810..97cb933bed 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -771,6 +771,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutHome(); } +/* ECIES disabled void fsm_msgEncryptMessage(EncryptMessage *msg) { if (!storage_isInitialized()) { @@ -888,6 +889,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) msg_write(MessageType_MessageType_DecryptedMessage, resp); layoutHome(); } +*/ void fsm_msgEstimateTxSize(EstimateTxSize *msg) { diff --git a/firmware/messages.c b/firmware/messages.c index 9d50729179..1994f61a78 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -63,8 +63,10 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, {'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity}, {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, +/* ECIES disabled {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, +*/ // {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck}, {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, @@ -83,8 +85,10 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, {'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0}, +/* ECIES disabled {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, +*/ {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, From 55fe98ccd1eb155575ee965ba142353976a5996b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 15 May 2016 10:38:02 +0200 Subject: [PATCH 0224/1154] Fix USB HID descriptor --- firmware/usb.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index df087594fa..1895da2ea3 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -54,20 +54,17 @@ static const struct usb_device_descriptor dev_descr = { static const uint8_t hid_report_descriptor[] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) - 0x09, 0x01, // USAGE + 0x09, 0x01, // USAGE (1) 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75,0x08, // REPORT_SIZE (8) - 0x95,0x40, // REPORT_COUNT (64) - 0x81,0x02, // INPUT (Data,Var,Abs) - 0x09,0x21, // USAGE (Output Report Data) - 0x15,0x00, // LOGICAL_MINIMUM (0) - 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75,0x08, // REPORT_SIZE (8) - 0x95,0x40, // REPORT_COUNT (64) - 0x91,0x02, // OUTPUT (Data,Var,Abs) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x85, 0x3f, // REPORT_ID (63) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x3f, // REPORT_COUNT (63) + 0x09, 0x01, // USAGE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x01, // USAGE (1) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; From 117d261a3882cb094db1bb8b8ac352ae2b45abba Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 15:32:18 +0200 Subject: [PATCH 0225/1154] Script to generate key and certificate --- firmware/u2f/genkeys.sh | 45 ++++++++++++++++++++++++++++++++ firmware/u2f/trezordevkey.pem | 5 ++++ firmware/u2f/u2f_keys.h | 48 +++++++++++++++++------------------ vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 5 files changed, 76 insertions(+), 26 deletions(-) create mode 100644 firmware/u2f/genkeys.sh create mode 100644 firmware/u2f/trezordevkey.pem diff --git a/firmware/u2f/genkeys.sh b/firmware/u2f/genkeys.sh new file mode 100644 index 0000000000..3bc7e5b10b --- /dev/null +++ b/firmware/u2f/genkeys.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +cat > u2f_keys.h < + +const uint8_t U2F_ATT_PRIV_KEY[] = { +EOF + +if [ \! -e trezordevkey.pem ]; then + openssl ecparam -genkey -out trezordevkey.pem -name prime256v1 +fi +openssl ec -in trezordevkey.pem -text | + perl -e '$key = "\t"; while (<>) { + if (/priv:/) { $priv = 1 } + elsif (/pub:/) { $priv = 0 } + elsif ($priv) { + while ($_ =~ s/.*?([0-9a-f]{2})//) { + $key .= "0x$1,"; + if ($num++ % 8 == 7) { $key .= "\n\t"; } + else {$key .= " ";} + } + } + } + $key =~ s/,\s*$/\n/s; + print $key;' >> u2f_keys.h +cat >> u2f_keys.h <> u2f_keys.h + +cat >> u2f_keys.h < Date: Fri, 29 Apr 2016 16:35:23 +0200 Subject: [PATCH 0226/1154] Only compile debugInt when debugging --- firmware/u2f.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware/u2f.c b/firmware/u2f.c index acf4a0ac64..ce3de07cec 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -98,6 +98,7 @@ uint8_t buttonState(void) return 0; } +#if DEBUG_LOG char *debugInt(const uint32_t i) { static uint8_t n = 0; @@ -108,6 +109,9 @@ char *debugInt(const uint32_t i) n = (n + 1) % 8; return ret; } +#else +#define debugInt(I) do{}while(0) +#endif static uint32_t dialog_timeout = 0; From eb2ef2464c58ffe4c09a4b0c8e7068c9a34c4f64 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 19:54:59 +0200 Subject: [PATCH 0227/1154] CID hacks, not yet finished --- firmware/u2f.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index ce3de07cec..d5b9342997 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -174,8 +174,9 @@ void u2fhid_read(const U2FHID_FRAME *f) buf_ptr += sizeof(f->init.data); // Broadcast is reserved for init - if (cid == CID_BROADCAST && cmd != U2FHID_INIT) + if (f->cid == CID_BROADCAST && cmd != U2FHID_INIT) return; + cid = f->cid; // Check length isnt bigger than spec max if (len > sizeof(buf)) { @@ -184,9 +185,6 @@ void u2fhid_read(const U2FHID_FRAME *f) } } else { - // Broadcast is reserved for init - if (cid == CID_BROADCAST) - return; // check out of bounds if ((buf_ptr - buf) >= (signed) len || (buf_ptr + sizeof(f->cont.data) - buf) > (signed) sizeof(buf)) @@ -258,13 +256,13 @@ void u2fhid_init(const U2FHID_INIT_REQ *init_req) U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; bzero(&f, sizeof(f)); - f.cid = CID_BROADCAST; + f.cid = cid; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; f.init.bcntl = U2FHID_INIT_RESP_SIZE; memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); - resp->cid = next_cid(); + resp->cid = cid == CID_BROADCAST ? next_cid() : cid; resp->versionInterface = U2FHID_IF_VERSION; resp->versionMajor = VERSION_MAJOR; resp->versionMinor = VERSION_MINOR; From 2ab950555e4481e893430a674e49015cf865e094 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 7 May 2016 22:12:27 +0200 Subject: [PATCH 0228/1154] Fixed u2f reentry --- firmware/u2f.c | 167 +++++++++++++++++++++++++++++++++---------------- firmware/u2f.h | 10 +-- firmware/usb.c | 8 +-- 3 files changed, 122 insertions(+), 63 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index d5b9342997..efb7cee6b9 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -47,7 +47,7 @@ #define U2F_OUT_PKT_BUFFER_LEN 16 // Initialise without a cid -static uint32_t cid = CID_BROADCAST; +static uint32_t cid = 0; // Circular Output buffer static uint32_t u2f_out_start = 0; @@ -154,73 +154,130 @@ uint32_t next_cid(void) return cid; } -void u2fhid_read(const U2FHID_FRAME *f) +typedef struct { + uint8_t buf[57+127*59]; + uint8_t *buf_ptr; + uint32_t len; + uint8_t seq; + uint8_t cmd; +} U2F_ReadBuffer; + +U2F_ReadBuffer *reader; + +void u2fhid_read(char tiny, const U2FHID_FRAME *f) { - static uint8_t seq, cmd; - static uint32_t len; - static uint8_t *buf_ptr; - static uint8_t buf[57+7*59]; - - if ((f->cid != CID_BROADCAST) && (f->cid != cid)) { - return; // Not for us - } - - if (f->type & TYPE_INIT) { - seq = 0; - buf_ptr = buf; - len = MSG_LEN(*f); - cmd = f->type; - memcpy(buf_ptr, f->init.data, sizeof(f->init.data)); - buf_ptr += sizeof(f->init.data); - - // Broadcast is reserved for init - if (f->cid == CID_BROADCAST && cmd != U2FHID_INIT) + if (tiny) { + // read continue packet + if (reader == 0 || cid != f->cid) { + send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY); return; - cid = f->cid; - - // Check length isnt bigger than spec max - if (len > sizeof(buf)) { - len = 0; - return send_u2fhid_error(ERR_INVALID_LEN); } - } - else { + + if ((f->type & TYPE_INIT) || reader->seq != f->cont.seq) { + u2fhid_init_cmd(f); + return; + } + // check out of bounds - if ((buf_ptr - buf) >= (signed) len - || (buf_ptr + sizeof(f->cont.data) - buf) > (signed) sizeof(buf)) + if ((reader->buf_ptr - reader->buf) >= (signed) reader->len + || (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) return; - if (f->cont.seq == seq) { - seq++; - memcpy(buf_ptr, f->cont.data, sizeof(f->cont.data)); - buf_ptr += sizeof(f->cont.data); - } else { - return send_u2fhid_error(ERR_INVALID_SEQ); - } - } - - // Do we need to wait for more data - if ((buf_ptr - buf) < (signed)len) { - // debugLog(0, "", "u2fhid_read wait"); + reader->seq++; + memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); + reader->buf_ptr += sizeof(f->cont.data); return; } - // We have all the data - switch (cmd) { + u2fhid_read_start(f); +} + +void u2fhid_init_cmd(const U2FHID_FRAME *f) { + reader->seq = 0; + reader->buf_ptr = reader->buf; + reader->len = MSG_LEN(*f); + reader->cmd = f->type; + memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); + reader->buf_ptr += sizeof(f->init.data); + cid = f->cid; + // Check length isnt bigger than spec max + if (reader->len > sizeof(reader->buf)) { + reader->len = 0; + return send_u2fhid_error(cid, ERR_INVALID_LEN); + } +} + +void u2fhid_read_start(const U2FHID_FRAME *f) { + U2F_ReadBuffer readbuffer; + if (!(f->type & TYPE_INIT)) { + return; + } + + reader = &readbuffer; + u2fhid_init_cmd(f); + + // Broadcast is reserved for init + if (f->cid == CID_BROADCAST && reader->cmd != U2FHID_INIT) + return; + + usbTiny(1); + for(;;) { + // Do we need to wait for more data + while ((reader->buf_ptr - reader->buf) < (signed)reader->len) { + uint8_t lastseq = reader->seq; + uint8_t lastcmd = reader->cmd; + int counter = U2F_TIMEOUT; + while (reader->seq == lastseq && reader->cmd == lastcmd) { + if (counter-- == 0) { + // timeout + cid = 0; + send_u2fhid_error(f->cid, ERR_MSG_TIMEOUT); + usbTiny(0); + return; + } + usbPoll(); + } + } + + // We have all the data + switch (reader->cmd) { case U2FHID_PING: - u2fhid_ping(buf, len); + u2fhid_ping(reader->buf, reader->len); break; case U2FHID_MSG: - u2fhid_msg((APDU *)buf, len); + u2fhid_msg((APDU *)reader->buf, reader->len); break; case U2FHID_INIT: - u2fhid_init((const U2FHID_INIT_REQ *)buf); + u2fhid_init((const U2FHID_INIT_REQ *)reader->buf); break; case U2FHID_WINK: - u2fhid_wink(buf, len); + u2fhid_wink(reader->buf, reader->len); break; default: - send_u2fhid_error(ERR_INVALID_CMD); + send_u2fhid_error(cid, ERR_INVALID_CMD); break; + } + + // wait for next commmand/ button press + reader->cmd = 0; + uint8_t bs = 0; + while (dialog_timeout-- && bs == 0 && reader->cmd == 0) { + usbPoll(); // may trigger new request + bs = buttonState(); + } + + if (reader->cmd == 0) { + if (dialog_timeout == 0) { + last_req_state += BTN_NO; // Timeout is like button no + } + else { + last_req_state += bs; + dialog_timeout = 0; + } + cid = 0; + usbTiny(0); + layoutHome(); + return; + } } } @@ -236,7 +293,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) (void)buf; if (len > 0) - return send_u2fhid_error(ERR_INVALID_LEN); + return send_u2fhid_error(cid, ERR_INVALID_LEN); if (dialog_timeout > 0) dialog_timeout = U2F_TIMEOUT; @@ -308,7 +365,7 @@ void u2fhid_msg(const APDU *a, uint32_t len) // Very crude locking, incase another message comes in while we wait. This // actually can probably be removed as no code inside calls usbPoll anymore if (lock) - return send_u2fhid_error(ERR_CHANNEL_BUSY); + return send_u2fhid_error(cid, ERR_CHANNEL_BUSY); lock = true; @@ -329,7 +386,7 @@ void u2fhid_msg(const APDU *a, uint32_t len) lock = false; - LayoutHomeAfterTimeout(); + //LayoutHomeAfterTimeout(); } void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) @@ -371,12 +428,12 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) } } -void send_u2fhid_error(uint8_t err) +void send_u2fhid_error(uint32_t fcid, uint8_t err) { U2FHID_FRAME f; bzero(&f, sizeof(f)); - f.cid = cid; + f.cid = fcid; f.init.cmd = U2FHID_ERROR; f.init.bcntl = 1; f.init.data[0] = err; diff --git a/firmware/u2f.h b/firmware/u2f.h index 847710a4c6..6e4c0862c0 100644 --- a/firmware/u2f.h +++ b/firmware/u2f.h @@ -35,7 +35,9 @@ typedef struct { #define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3)) -void u2fhid_read(const U2FHID_FRAME *buf); +void u2fhid_read(char tiny, const U2FHID_FRAME *buf); +void u2fhid_init_cmd(const U2FHID_FRAME *f); +void u2fhid_read_start(const U2FHID_FRAME *f); bool u2fhid_write(uint8_t *buf); void u2fhid_init(const U2FHID_INIT_REQ *init_req); void u2fhid_ping(const uint8_t *buf, uint32_t len); @@ -50,11 +52,11 @@ void u2f_register(const APDU *a); void u2f_version(const APDU *a); void u2f_authenticate(const APDU *a); -void send_u2f_msg(const uint8_t *data, const uint32_t len); -void send_u2f_error(const uint16_t err); +void send_u2f_msg(const uint8_t *data, uint32_t len); +void send_u2f_error(uint16_t err); void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len); -void send_u2fhid_error(const uint8_t err); +void send_u2fhid_error(uint32_t fcid, uint8_t err); #endif diff --git a/firmware/usb.c b/firmware/usb.c index 1895da2ea3..91ed2b847d 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -230,14 +230,14 @@ static const struct usb_interface_descriptor hid_iface_debug[] = {{ static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, .altsetting = hid_iface, -}, { - .num_altsetting = 1, - .altsetting = hid_iface_u2f, #if DEBUG_LINK }, { .num_altsetting = 1, .altsetting = hid_iface_debug, #endif +}, { + .num_altsetting = 1, + .altsetting = hid_iface_u2f, }}; static const struct usb_config_descriptor config = { @@ -308,7 +308,7 @@ static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) debugLog(0, "", "hid_u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; - u2fhid_read((const U2FHID_FRAME *)buf); + u2fhid_read(tiny, (const U2FHID_FRAME *)buf); } #if DEBUG_LINK From 49691c2436aaf69af16d7ec72d4226379dbe58a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 16:41:09 +0200 Subject: [PATCH 0229/1154] fix demo --- demo/demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/demo.c b/demo/demo.c index 51242d650a..cfed6d6f68 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -273,7 +273,7 @@ int main(void) switch (state) { case 1: layoutProgress("WORKING", frame % 41 * 25); - pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64, NULL); + pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); break; } From 9006c90a59c761b509d1140e56bc86efae95d86f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 May 2016 14:02:06 +0200 Subject: [PATCH 0230/1154] use MEMSET_BZERO and U2F_APPID_SIZE macros --- Makefile.include | 2 +- firmware/u2f.c | 19 ++++++++++--------- firmware/u2f_knownapps.h | 2 +- vendor/trezor-crypto | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile.include b/Makefile.include index 5e48ba04f6..f931984328 100644 --- a/Makefile.include +++ b/Makefile.include @@ -14,7 +14,7 @@ DBGFLAGS ?= -g -DNDEBUG CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ - -std=c99 \ + -std=gnu99 \ -W \ -Wall \ -Wextra \ diff --git a/firmware/u2f.c b/firmware/u2f.c index acf4a0ac64..f01f2e956f 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -33,6 +33,7 @@ #include "rng.h" #include "hmac.h" #include "util.h" +#include "macros.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" @@ -240,7 +241,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) dialog_timeout = U2F_TIMEOUT; U2FHID_FRAME f; - bzero(&f, sizeof(f)); + MEMSET_BZERO(&f, sizeof(f)); f.cid = cid; f.init.cmd = U2FHID_WINK; f.init.bcntl = 0; @@ -253,7 +254,7 @@ void u2fhid_init(const U2FHID_INIT_REQ *init_req) U2FHID_FRAME f; U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; - bzero(&f, sizeof(f)); + MEMSET_BZERO(&f, sizeof(f)); f.cid = CID_BROADCAST; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; @@ -340,7 +341,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // debugLog(0, "", "send_u2fhid_msg"); - bzero(&f, sizeof(f)); + MEMSET_BZERO(&f, sizeof(f)); f.cid = cid; f.init.cmd = cmd; f.init.bcnth = len >> 8; @@ -356,7 +357,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // Cont packet(s) for (; l > 0; l -= psz, p += psz) { // debugLog(0, "", "send_u2fhid_msg con"); - bzero(&f.cont.data, sizeof(f.cont.data)); + MEMSET_BZERO(&f.cont.data, sizeof(f.cont.data)); f.cont.seq = seq++; psz = MIN(sizeof(f.cont.data), l); memcpy(f.cont.data, p, psz); @@ -373,7 +374,7 @@ void send_u2fhid_error(uint8_t err) { U2FHID_FRAME f; - bzero(&f, sizeof(f)); + MEMSET_BZERO(&f, sizeof(f)); f.cid = cid; f.init.cmd = U2FHID_ERROR; f.init.bcntl = 1; @@ -391,18 +392,18 @@ void u2f_version(const APDU *a) send_u2f_msg(version_response, sizeof(version_response)); } -static const char *getReadableAppId(const uint8_t appid[32]) { +static const char *getReadableAppId(const uint8_t appid[U2F_APPID_SIZE]) { unsigned int i; static char buf[6+2+6+1]; for (i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { - if (memcmp(appid, u2f_well_known[i].appid, 32) == 0) + if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) return u2f_well_known[i].appname; } data2hex(appid, 3, &buf[0]); buf[6] = buf[7] = '.'; - data2hex(appid+(sizeof(appid)-3), 3, &buf[8]); + data2hex(appid + (U2F_APPID_SIZE - 3), 3, &buf[8]); return buf; } @@ -534,7 +535,7 @@ void u2f_register(const APDU *a) if (last_req_state == REG_PASS) { uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; - bzero(data, sizeof(data)); + MEMSET_BZERO(data, sizeof(data)); resp->registerId = U2F_REGISTER_ID; diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index ca3d1732fb..c3b7142324 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -29,7 +29,7 @@ typedef struct { static const U2FWellKnown u2f_well_known[3] = { { - // didn't feel like tracing that one yet + // https://www.gstatic.com/securitykey/origins.json { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, 0xe1,0x51,0xed,0x8d,0x4d,0x3c,0x76,0x7a, 0x6c,0xc3,0x49,0x43,0x59,0x43,0x79,0x4e, diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 406022acb4..23590c05c6 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 406022acb4d43a48bb9d8afe392226f1fdeccec2 +Subproject commit 23590c05c652efccdfb7e837a048adbecab5b145 From 041eaa5e4b4c7b6001730de351ab44a10fff5a63 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 May 2016 18:58:13 +0200 Subject: [PATCH 0231/1154] refactor u2f dialogs into a separate function --- firmware/layout2.c | 4 ++++ firmware/layout2.h | 1 + firmware/u2f.c | 8 ++------ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 4d77c385ac..73b566c8e0 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -335,3 +335,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) NULL, NULL); } + +void layoutU2FDialog(const char *verb, const char *appid) { + layoutDialog(DIALOG_ICON_QUESTION, "Cancel", verb, NULL, verb, "U2F security key?", "", appid, "", NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 1b725d5c5c..6cbe30c436 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -40,5 +40,6 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) void layoutAddress(const char *address, const char *desc); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); +void layoutU2FDialog(const char *verb, const char *appid); #endif diff --git a/firmware/u2f.c b/firmware/u2f.c index a40c368c7f..330945c55b 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -568,9 +568,7 @@ void u2f_register(const APDU *a) // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state - layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Register", - NULL, "Register U2F", "security key", - "", getReadableAppId(req->appId), "", NULL); + layoutU2FDialog("Register", getReadableAppId(req->appId)); dialog_timeout = U2F_TIMEOUT; last_req_state = REG; return; @@ -701,9 +699,7 @@ void u2f_authenticate(const APDU *a) // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state - layoutDialog(DIALOG_ICON_QUESTION, "Cancel", "Authenticate", NULL, - "Authenticate U2F", "security key", - "", getReadableAppId(req->appId), "", NULL); + layoutU2FDialog("Authenticate", getReadableAppId(req->appId)); dialog_timeout = U2F_TIMEOUT; last_req_state = AUTH; return; From d20671b5179c7030fb32ce9ab85985141c09bba9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 17 May 2016 18:13:08 +0200 Subject: [PATCH 0232/1154] handle various signed_message_headers correctly --- firmware/coins.c | 12 ++++++------ firmware/crypto.c | 8 ++++---- firmware/crypto.h | 4 ++-- firmware/fsm.c | 8 +++++--- firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 4 +++- firmware/protob/messages.pb.h | 12 ++++++++---- firmware/protob/types.options | 1 + firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 11 +++++++---- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 12 files changed, 41 insertions(+), 27 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 4d25088244..b0a0b77649 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,12 +21,12 @@ #include "coins.h" const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0}, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0}, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0}, + {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n"}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n"}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n"}, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/crypto.c b/firmware/crypto.c index eb986abde9..8587f84b5c 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -100,11 +100,11 @@ int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_le return hdnode_sign_digest(node, message, signature + 1, NULL); } -int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); sha256_Update(&ctx, varint, l); @@ -120,14 +120,14 @@ int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message return result; } -int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) { SHA256_CTX ctx; uint8_t pubkey[65], addr_raw[21], hash[32]; // calculate hash sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); + sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); sha256_Update(&ctx, varint, l); diff --git a/firmware/crypto.h b/firmware/crypto.h index 11adee1ccb..13b97bbb9c 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -37,9 +37,9 @@ int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_le int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 97cb933bed..cf1d6c54ab 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -643,7 +643,7 @@ void fsm_msgSignMessage(SignMessage *msg) if (!node) return; layoutProgressSwipe("Signing", 0); - if (cryptoMessageSign(node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { + if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); @@ -667,12 +667,14 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) fsm_sendFailure(FailureType_Failure_Other, "No message provided"); return; } + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; layoutProgressSwipe("Verifying", 0); uint8_t addr_raw[21]; if (!ecdsa_address_decode(msg->address, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); } - if (msg->signature.size == 65 && cryptoMessageVerify(msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); @@ -747,7 +749,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(node, digest, 64, resp->signature.bytes); + result = cryptoMessageSign(&(coins[0]), node, digest, 64, resp->signature.bytes); } if (result == 0) { diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 50499abcfe..c707aac054 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -56,6 +56,7 @@ SignMessage.coin_name max_size:17 VerifyMessage.address max_size:36 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 +VerifyMessage.coin_name max_size:17 MessageSignature.address max_size:36 MessageSignature.signature max_size:65 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index b0eb77ff23..c1420d6048 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -9,6 +9,7 @@ const uint32_t ResetDevice_strength_default = 256u; const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; +const char VerifyMessage_coin_name_default[17] = "Bitcoin"; const char EncryptMessage_coin_name_default[17] = "Bitcoin"; const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; @@ -213,10 +214,11 @@ const pb_field_t SignMessage_fields[4] = { PB_LAST_FIELD }; -const pb_field_t VerifyMessage_fields[4] = { +const pb_field_t VerifyMessage_fields[5] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, VerifyMessage, coin_name, message, &VerifyMessage_coin_name_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 4049e7f9ed..f4cd33ff1a 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -634,6 +634,8 @@ typedef struct _VerifyMessage { VerifyMessage_signature_t signature; bool has_message; VerifyMessage_message_t message; + bool has_coin_name; + char coin_name[17]; } VerifyMessage; typedef struct _WordAck { @@ -647,6 +649,7 @@ extern const uint32_t ResetDevice_strength_default; extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; extern const char SignMessage_coin_name_default[17]; +extern const char VerifyMessage_coin_name_default[17]; extern const char EncryptMessage_coin_name_default[17]; extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; @@ -688,7 +691,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define WordRequest_init_default {0} #define WordAck_init_default {""} #define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} -#define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}} +#define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} #define MessageSignature_init_default {false, "", false, {0, {0}}} #define EncryptMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin"} #define EncryptedMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} @@ -742,7 +745,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define WordRequest_init_zero {0} #define WordAck_init_zero {""} #define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} -#define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} +#define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} #define MessageSignature_init_zero {false, "", false, {0, {0}}} #define EncryptMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} #define EncryptedMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} @@ -904,6 +907,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define VerifyMessage_address_tag 1 #define VerifyMessage_signature_tag 2 #define VerifyMessage_message_tag 3 +#define VerifyMessage_coin_name_tag 4 #define WordAck_word_tag 1 /* Struct field encoding specification for nanopb */ @@ -938,7 +942,7 @@ extern const pb_field_t RecoveryDevice_fields[7]; extern const pb_field_t WordRequest_fields[1]; extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; -extern const pb_field_t VerifyMessage_fields[4]; +extern const pb_field_t VerifyMessage_fields[5]; extern const pb_field_t MessageSignature_fields[3]; extern const pb_field_t EncryptMessage_fields[6]; extern const pb_field_t EncryptedMessage_fields[4]; @@ -994,7 +998,7 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define WordRequest_size 0 #define WordAck_size 14 #define SignMessage_size 1094 -#define VerifyMessage_size 1132 +#define VerifyMessage_size 1151 #define MessageSignature_size 105 #define EncryptMessage_size 1131 #define EncryptedMessage_size 1168 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 9fa6c9d860..422d9420d5 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -6,6 +6,7 @@ HDNodePathType.address_n max_count:8 CoinType.coin_name max_size:17 CoinType.coin_shortcut max_size:9 +CoinType.signed_message_header max_size:32 TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index e0fa2959f3..a00a97dab8 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -28,7 +28,7 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[8] = { +const pb_field_t CoinType_fields[9] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), @@ -36,6 +36,7 @@ const pb_field_t CoinType_fields[8] = { PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wpkh, address_type_p2sh, &CoinType_address_type_p2wpkh_default), PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wsh, address_type_p2wpkh, &CoinType_address_type_p2wsh_default), + PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2wsh, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index a20ca4a025..beff78c031 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -79,6 +79,8 @@ typedef struct _CoinType { uint32_t address_type_p2wpkh; bool has_address_type_p2wsh; uint32_t address_type_p2wsh; + bool has_signed_message_header; + char signed_message_header[32]; } CoinType; typedef struct { @@ -261,7 +263,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, ""} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -272,7 +274,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, ""} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -290,6 +292,7 @@ extern const uint32_t IdentityType_index_default; #define CoinType_address_type_p2sh_tag 5 #define CoinType_address_type_p2wpkh_tag 6 #define CoinType_address_type_p2wsh_tag 7 +#define CoinType_signed_message_header_tag 8 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -342,7 +345,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[8]; +extern const pb_field_t CoinType_fields[9]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[8]; extern const pb_field_t TxOutputType_fields[7]; @@ -355,7 +358,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 65 +#define CoinType_size 99 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5497 #define TxOutputType_size 3929 diff --git a/vendor/trezor-common b/vendor/trezor-common index 8c6401bdef..36a574056d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 8c6401bdef92ebef7375a0e58a06af117618519d +Subproject commit 36a574056deacad8943f1412c3db149750f8b163 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 51c0bb09d8..23590c05c6 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 51c0bb09d8f1066555d28ae3824988b318d2f39e +Subproject commit 23590c05c652efccdfb7e837a048adbecab5b145 From a0571e02a7eeb61bdd552b0d50b2a1e49d1766a7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 18 May 2016 01:09:13 +0200 Subject: [PATCH 0233/1154] Removed more magic numbers. `KEY_PATH_LEN`: length of the derivation path in the key handle `KEY_PATH_ENTRIES`: number of entries in derivation path including initial BIP-43 selector. `KEY_HANDLE_LEN`: length of key handle (derivation path + HMAC checksum) --- firmware/u2f.c | 42 +++++++++++++++++++++------------------- firmware/u2f_knownapps.h | 3 ++- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 330945c55b..2ba366a699 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -56,7 +56,11 @@ static uint32_t u2f_out_end = 0; static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; #define U2F_PUBKEY_LEN 65 -#define KEY_HANDLE_LEN 64 +#define KEY_PATH_LEN 32 +#define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH) + +// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' +#define KEY_PATH_ENTRIES (1 + KEY_PATH_LEN / sizeof(uint32_t)) // Auth/Register request state machine typedef enum { @@ -487,29 +491,28 @@ const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) { - uint8_t keybase[64]; + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - // Derivation path is m/'U2F/'r/'r/'r/'r/'r/'r/'r/'r - uint32_t i, key_path[9]; + // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' + uint32_t i, key_path[KEY_PATH_ENTRIES]; key_path[0] = U2F_KEY_PATH; - for (i = 1; i < 9; i++) { + for (i = 1; i < KEY_PATH_ENTRIES; i++) { // high bit for hardened keys key_path[i]= 0x80000000 | random32(); } // First half of keyhandle is key_path - memcpy(key_handle, &key_path[1], 32); + memcpy(key_handle, &key_path[1], KEY_PATH_LEN); // prepare keypair from /random data - const HDNode *node = - getDerivedNode(key_path, sizeof(key_path) / sizeof(uint32_t)); + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); // For second half of keyhandle // Signature of app_id and random data - memcpy(&keybase[0], app_id, 32); - memcpy(&keybase[32], key_handle, 32); + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); hmac_sha256(node->private_key, sizeof(node->private_key), - keybase, sizeof(keybase), &key_handle[32]); + keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]); // Done! return node; @@ -518,23 +521,22 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) { - uint32_t key_path[9]; + uint32_t key_path[KEY_PATH_ENTRIES]; key_path[0] = U2F_KEY_PATH; - memcpy(&key_path[1], key_handle, 32); + memcpy(&key_path[1], key_handle, KEY_PATH_LEN); - const HDNode *node = - getDerivedNode(key_path, sizeof(key_path) / sizeof(uint32_t)); + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - uint8_t keybase[64]; - memcpy(&keybase[0], app_id, 32); - memcpy(&keybase[32], key_handle, 32); + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - uint8_t hmac[32]; + uint8_t hmac[SHA256_DIGEST_LENGTH]; hmac_sha256(node->private_key, sizeof(node->private_key), keybase, sizeof(keybase), hmac); - if (memcmp(&key_handle[32], hmac, 32) != 0) + if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) return NULL; // Done! diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index c3b7142324..b57bbcb024 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -21,9 +21,10 @@ #define __U2F_KNOWNAPPS_H_INCLUDED__ #include +#include "u2f/u2f.h" typedef struct { - uint8_t appid[32]; + uint8_t appid[U2F_APPID_SIZE]; const char *appname; } U2FWellKnown; From 96f30a0ba708c2f077d536a3b9184355af1c8d9c Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 20 May 2016 01:49:20 +0200 Subject: [PATCH 0234/1154] Don't ask for passphrase with u2f. --- firmware/fsm.c | 2 +- firmware/storage.c | 16 +++++++++------- firmware/storage.h | 4 ++-- firmware/u2f.c | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 97cb933bed..8a99f0bcb3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -96,7 +96,7 @@ const CoinType *fsm_getCoin(const char *name) const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) { static HDNode node; - if (!storage_getRootNode(&node, curve)) { + if (!storage_getRootNode(&node, curve, true)) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve"); layoutHome(); return 0; diff --git a/firmware/storage.c b/firmware/storage.c index 1d8fb9730f..245ea83916 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -72,7 +72,7 @@ _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINA _Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); _Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); -static bool sessionSeedCached; +static bool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t sessionSeed[64]; @@ -290,27 +290,29 @@ void get_root_node_callback(uint32_t iter, uint32_t total) layoutProgress("Waking up", 1000 * iter / total); } -const uint8_t *storage_getSeed(void) +const uint8_t *storage_getSeed(bool usePassphrase) { // root node is properly cached - if (sessionSeedCached) { + if (usePassphrase == sessionSeedUsesPassphrase + && sessionSeedCached) { return sessionSeed; } // if storage has mnemonic, convert it to node and use it if (storage.has_mnemonic) { - if (!protectPassphrase()) { + if (usePassphrase && !protectPassphrase()) { return NULL; } - mnemonic_to_seed(storage.mnemonic, sessionPassphrase, sessionSeed, get_root_node_callback); // BIP-0039 + mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 sessionSeedCached = true; + sessionSeedUsesPassphrase = usePassphrase; return sessionSeed; } return NULL; } -bool storage_getRootNode(HDNode *node, const char *curve) +bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) { // if storage has node, decrypt and use it if (storage.has_node && strcmp(curve, SECP256K1_NAME) == 0) { @@ -339,7 +341,7 @@ bool storage_getRootNode(HDNode *node, const char *curve) return true; } - const uint8_t *seed = storage_getSeed(); + const uint8_t *seed = storage_getSeed(usePassphrase); if (seed == NULL) { return false; } diff --git a/firmware/storage.h b/firmware/storage.h index 304ebf842b..c69d7f0154 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -33,9 +33,9 @@ void session_clear(bool clear_pin); void storage_loadDevice(LoadDevice *msg); -const uint8_t *storage_getSeed(void); +const uint8_t *storage_getSeed(bool usePassphrase); -bool storage_getRootNode(HDNode *node, const char *curve); +bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase); const char *storage_getLabel(void); void storage_setLabel(const char *label); diff --git a/firmware/u2f.c b/firmware/u2f.c index 2ba366a699..b2216870c9 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -473,7 +473,7 @@ static const char *getReadableAppId(const uint8_t appid[U2F_APPID_SIZE]) { const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static HDNode node; - if (!storage_getRootNode(&node, NIST256P1_NAME)) { + if (!storage_getRootNode(&node, NIST256P1_NAME, false)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); return 0; From 46119bd007fb5e332fd8e8ab8b9a7d5a5f6f9780 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 20 May 2016 17:00:10 +0200 Subject: [PATCH 0235/1154] clear pin failures on wipe and when in debug mode --- firmware/fsm.c | 1 + firmware/storage.c | 9 +++++++++ firmware/storage.h | 1 + firmware/trezor.c | 1 + 4 files changed, 12 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index cf1d6c54ab..29463de7b2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -241,6 +241,7 @@ void fsm_msgWipeDevice(WipeDevice *msg) storage_reset(); storage_reset_uuid(); storage_commit(); + storage_clearPinArea(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change fsm_sendSuccess("Device wiped"); diff --git a/firmware/storage.c b/firmware/storage.c index 8d7f15a568..0b9b7b2588 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -419,6 +419,15 @@ bool session_isPinCached(void) return sessionPinCached; } +void storage_clearPinArea() +{ + flash_clear_status_flags(); + flash_unlock(); + flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); + flash_lock(); + storage_check_flash_errors(); +} + void storage_resetPinFails(uint32_t *pinfailsptr) { flash_clear_status_flags(); diff --git a/firmware/storage.h b/firmware/storage.h index 321f276aae..ef6978f12c 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -56,6 +56,7 @@ bool storage_hasPin(void); void storage_setPin(const char *pin); void session_cachePin(void); bool session_isPinCached(void); +void storage_clearPinArea(void); void storage_resetPinFails(uint32_t *pinfailptr); bool storage_increasePinFails(uint32_t *pinfailptr); uint32_t *storage_getPinFailsPtr(void); diff --git a/firmware/trezor.c b/firmware/trezor.c index bc9c1ba1b3..aa154d6e61 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -50,6 +50,7 @@ int main(void) storage_reset(); // wipe storage if debug link storage_reset_uuid(); storage_commit(); + storage_clearPinArea(); // reset PIN failures if debug link #endif oledDrawBitmap(40, 0, &bmp_logo64); From bc92fb95a5825e50cf254fa26ab59f326fe25255 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 20 May 2016 20:06:14 +0200 Subject: [PATCH 0236/1154] Clear pinarea on storage_init if upgrade fails This also cleans up the code a bit and resets storage_uuid if upgrade fails. --- firmware/storage.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 0b9b7b2588..1c539aee86 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -92,14 +92,29 @@ void storage_check_flash_errors(void) } } -void storage_from_flash(uint32_t version) +bool storage_from_flash(void) { + if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) == 0) { + // wrong magic + return false; + } + + uint32_t version = ((Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)))->version; // version 1: since 1.0.0 // version 2: since 1.2.1 // version 3: since 1.3.1 // version 4: since 1.3.2 // version 5: since 1.3.3 // version 6: since 1.3.6 + if (version > STORAGE_VERSION) { + // downgrade -> clear storage + return false; + } + + // load uuid + memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + 4), sizeof(storage_uuid)); + data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); + // copy storage memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); if (version <= 5) { // convert PIN failure counter from version 5 format @@ -117,28 +132,21 @@ void storage_from_flash(uint32_t version) storage.has_pin_failed_attempts = false; storage.pin_failed_attempts = 0; } - storage.version = STORAGE_VERSION; + // upgrade storage version + if (version != STORAGE_VERSION) { + storage.version = STORAGE_VERSION; + storage_commit(); + } + return true; } void storage_init(void) { - storage_reset(); - // if magic is ok - if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) == 0) { - // load uuid - memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + 4), sizeof(storage_uuid)); - data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); - // load storage struct - uint32_t version = ((Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)))->version; - if (version && version <= STORAGE_VERSION) { - storage_from_flash(version); - } - if (version != STORAGE_VERSION) { - storage_commit(); - } - } else { + if (!storage_from_flash()) { + storage_reset(); storage_reset_uuid(); storage_commit(); + storage_clearPinArea(); } } From a1ba431d943e21a32b71ff45dea6b53815d2eca4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 28 Apr 2016 15:00:34 +0200 Subject: [PATCH 0237/1154] Use more sensible HID descriptor --- firmware/usb.c | 72 +++++++++----------------------------------------- 1 file changed, 13 insertions(+), 59 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 102b573da3..040a1bcef1 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -49,66 +49,20 @@ static const struct usb_device_descriptor dev_descr = { .bNumConfigurations = 1, }; -/* got via usbhid-dump from CP2110 */ static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, - 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, - 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, - 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, - 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, - 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, - 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, - 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, - 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, - 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, - 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, - 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, - 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, - 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, - 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, - 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, - 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, - 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, - 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, - 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, - 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, - 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, + 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x85, 0x3f, // REPORT_ID (63) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x3f, // REPORT_COUNT (63) + 0x09, 0x01, // USAGE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x01, // USAGE (1) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION }; static const struct { From 27b3c63d8520d5e6d50eba80237d7e626e46a464 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 23 May 2016 19:42:25 +0200 Subject: [PATCH 0238/1154] cleanup usb in bootloader --- bootloader/usb.c | 97 ++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 69 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 0f17df6a0c..48e6692a71 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -34,6 +34,9 @@ #include "signatures.h" #include "sha2.h" +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) + static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -51,66 +54,20 @@ static const struct usb_device_descriptor dev_descr = { .bNumConfigurations = 1, }; -/* got via usbhid-dump from CP2110 */ static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, - 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, - 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, - 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, - 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, - 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, - 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, - 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, - 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, - 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, - 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, - 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, - 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, - 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, - 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, - 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, - 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, - 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, - 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, - 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, - 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, - 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, + 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x85, 0x3f, // REPORT_ID (63) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x3f, // REPORT_COUNT (63) + 0x09, 0x01, // USAGE (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x01, // USAGE (1) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION }; static const struct { @@ -136,14 +93,14 @@ static const struct { static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x81, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x02, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, .bInterval = 1, @@ -194,8 +151,10 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin if ((req->bmRequestType != 0x81) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) return 0; + (req->wValue != 0x2200)) + return 0; + /* Handle the HID report descriptor. */ *buf = (uint8_t *)hid_report_descriptor; *len = sizeof(hid_report_descriptor); @@ -222,7 +181,7 @@ static uint8_t meta_backup[FLASH_META_LEN]; static void send_msg_success(usbd_device *dev) { // send response: Success message (id 2), payload len 0 - while ( usbd_ep_write_packet(dev, 0x81, + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, "?##" // header "\x00\x02" // msg_id "\x00\x00\x00\x00" // payload_len @@ -234,7 +193,7 @@ static void send_msg_failure(usbd_device *dev) { // send response: Failure message (id 3), payload len 2 // code = 99 (Failure_FirmwareError) - while ( usbd_ep_write_packet(dev, 0x81, + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, "?##" // header "\x00\x03" // msg_id "\x00\x00\x00\x02" // payload_len @@ -251,7 +210,7 @@ static void send_msg_features(usbd_device *dev) // minor_version = VERSION_MINOR // patch_version = VERSION_PATCH // bootloader_mode = True - while ( usbd_ep_write_packet(dev, 0x81, + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, "?##" // header "\x00\x11" // msg_id "\x00\x00\x00\x1b" // payload_len @@ -264,7 +223,7 @@ static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) { // send response: ButtonRequest message (id 26), payload len 2 // code = ButtonRequest_FirmwareCheck (9) - while ( usbd_ep_write_packet(dev, 0x81, + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, "?##" // header "\x00\x1a" // msg_id "\x00\x00\x00\x02" // payload_len @@ -284,7 +243,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) uint32_t *w; static SHA256_CTX ctx; - if ( usbd_ep_read_packet(dev, 0x02, buf, 64) != 64) return; + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; if (flash_state == STATE_END) { return; @@ -485,8 +444,8 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); usbd_register_control_callback( dev, From 68b34af19e8f9c22bdd4bc11facce1fd0088529c Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 24 May 2016 00:24:14 +0200 Subject: [PATCH 0239/1154] More standard conform behaviour Tested with u2f-ref-code/u2f-tests. Known incompatibility: - changed challenge invalidates button press. --- firmware/protect.c | 4 +- firmware/u2f.c | 141 ++++++++++++++++++++++----------------------- firmware/u2f.h | 2 +- firmware/u2f/u2f.h | 4 +- firmware/usb.c | 4 +- 5 files changed, 77 insertions(+), 78 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 0ff821dac9..a39ee07870 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -57,7 +57,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // button acked - check buttons if (acked) { - usbDelay(3500); + usbDelay(3300); buttonUpdate(); if (button.YesUp) { result = true; @@ -163,7 +163,7 @@ bool protectPin(bool use_cached) } layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second - usbDelay(840000); + usbDelay(800000); wait--; } const char *pin; diff --git a/firmware/u2f.c b/firmware/u2f.c index b2216870c9..46660cae77 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -44,8 +44,8 @@ #define MIN(a, b) (((a) < (b)) ? (a) : (b)) // About 1/2 Second according to values used in protect.c -#define U2F_TIMEOUT 840000/2 -#define U2F_OUT_PKT_BUFFER_LEN 16 +#define U2F_TIMEOUT (800000/2) +#define U2F_OUT_PKT_BUFFER_LEN 128 // Initialise without a cid static uint32_t cid = 0; @@ -120,36 +120,6 @@ char *debugInt(const uint32_t i) static uint32_t dialog_timeout = 0; -void LayoutHomeAfterTimeout(void) -{ - static bool timeoutLock = false; - - if (timeoutLock || dialog_timeout == 0) - return; // Dialog has cleared or already in loop - - timeoutLock = true; - U2F_STATE rs = last_req_state; - U2F_STATE bs = INIT; - while (dialog_timeout-- && rs == last_req_state && bs == 0) { - usbPoll(); // may trigger new request - bs = buttonState(); - } - timeoutLock = false; - - if (rs != last_req_state) - return; // Reset by new request don't clear screen - - if (dialog_timeout == 0) { - last_req_state += BTN_NO; // Timeout is like button no - } - else { - last_req_state += bs; - dialog_timeout = 0; - } - - layoutHome(); -} - uint32_t next_cid(void) { // extremely unlikely but hey @@ -171,6 +141,18 @@ U2F_ReadBuffer *reader; void u2fhid_read(char tiny, const U2FHID_FRAME *f) { + // Always handle init packets directly + if (f->init.cmd == U2FHID_INIT) { + u2fhid_init(f); + if (tiny && reader && f->cid == cid) { + // abort current channel + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + } + return; + } + if (tiny) { // read continue packet if (reader == 0 || cid != f->cid) { @@ -178,11 +160,19 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *f) return; } - if ((f->type & TYPE_INIT) || reader->seq != f->cont.seq) { + if ((f->type & TYPE_INIT) && reader->seq == 255) { u2fhid_init_cmd(f); return; } + if (reader->seq != f->cont.seq) { + send_u2fhid_error(f->cid, ERR_INVALID_SEQ); + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + return; + } + // check out of bounds if ((reader->buf_ptr - reader->buf) >= (signed) reader->len || (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) @@ -204,11 +194,6 @@ void u2fhid_init_cmd(const U2FHID_FRAME *f) { memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); reader->buf_ptr += sizeof(f->init.data); cid = f->cid; - // Check length isnt bigger than spec max - if (reader->len > sizeof(reader->buf)) { - reader->len = 0; - return send_u2fhid_error(cid, ERR_INVALID_LEN); - } } void u2fhid_read_start(const U2FHID_FRAME *f) { @@ -217,13 +202,20 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { return; } + // Broadcast is reserved for init + if (f->cid == CID_BROADCAST || f->cid == 0) { + send_u2fhid_error(f->cid, ERR_INVALID_CID); + return; + } + + if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) { + send_u2fhid_error(f->cid, ERR_INVALID_LEN); + return; + } + reader = &readbuffer; u2fhid_init_cmd(f); - // Broadcast is reserved for init - if (f->cid == CID_BROADCAST && reader->cmd != U2FHID_INIT) - return; - usbTiny(1); for(;;) { // Do we need to wait for more data @@ -234,8 +226,9 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { while (reader->seq == lastseq && reader->cmd == lastcmd) { if (counter-- == 0) { // timeout + send_u2fhid_error(cid, ERR_MSG_TIMEOUT); cid = 0; - send_u2fhid_error(f->cid, ERR_MSG_TIMEOUT); + reader = 0; usbTiny(0); return; } @@ -245,15 +238,15 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { // We have all the data switch (reader->cmd) { + case 0: + // message was aborted by init + break; case U2FHID_PING: u2fhid_ping(reader->buf, reader->len); break; case U2FHID_MSG: u2fhid_msg((APDU *)reader->buf, reader->len); break; - case U2FHID_INIT: - u2fhid_init((const U2FHID_INIT_REQ *)reader->buf); - break; case U2FHID_WINK: u2fhid_wink(reader->buf, reader->len); break; @@ -264,6 +257,7 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { // wait for next commmand/ button press reader->cmd = 0; + reader->seq = 255; uint8_t bs = 0; while (dialog_timeout-- && bs == 0 && reader->cmd == 0) { usbPoll(); // may trigger new request @@ -279,6 +273,7 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { dialog_timeout = 0; } cid = 0; + reader = 0; usbTiny(0); layoutHome(); return; @@ -311,20 +306,27 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) queue_u2f_pkt(&f); } -void u2fhid_init(const U2FHID_INIT_REQ *init_req) +void u2fhid_init(const U2FHID_FRAME *in) { - debugLog(0, "", "u2fhid_init"); + const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; U2FHID_FRAME f; U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; + debugLog(0, "", "u2fhid_init"); + + if (in->cid == 0) { + send_u2fhid_error(in->cid, ERR_INVALID_CID); + return; + } + MEMSET_BZERO(&f, sizeof(f)); - f.cid = cid; + f.cid = in->cid; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; f.init.bcntl = U2FHID_INIT_RESP_SIZE; memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); - resp->cid = cid == CID_BROADCAST ? next_cid() : cid; + resp->cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; resp->versionInterface = U2FHID_IF_VERSION; resp->versionMajor = VERSION_MAJOR; resp->versionMinor = VERSION_MINOR; @@ -358,8 +360,6 @@ uint8_t *u2f_out_data(void) void u2fhid_msg(const APDU *a, uint32_t len) { - static bool lock = false; - if ((APDU_LEN(*a) + sizeof(APDU)) > len) { debugLog(0, "", "BAD APDU LENGTH"); debugInt(APDU_LEN(*a)); @@ -367,12 +367,10 @@ void u2fhid_msg(const APDU *a, uint32_t len) return; } - // Very crude locking, incase another message comes in while we wait. This - // actually can probably be removed as no code inside calls usbPoll anymore - if (lock) - return send_u2fhid_error(cid, ERR_CHANNEL_BUSY); - - lock = true; + if (a->cla != 0) { + send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED); + return; + } switch (a->ins) { case U2F_REGISTER: @@ -388,10 +386,6 @@ void u2fhid_msg(const APDU *a, uint32_t len) debugLog(0, "", "u2f unknown cmd"); send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); } - - lock = false; - - //LayoutHomeAfterTimeout(); } void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) @@ -447,10 +441,15 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err) void u2f_version(const APDU *a) { + if (APDU_LEN(*a) != 0) { + debugLog(0, "", "u2f version - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } + // INCLUDES SW_NO_ERROR static const uint8_t version_response[] = {'U', '2', 'F', '_', 'V', '2', 0x90, 0x00}; - (void)a; debugLog(0, "", "u2f version"); send_u2f_msg(version_response, sizeof(version_response)); } @@ -553,7 +552,7 @@ void u2f_register(const APDU *a) debugLog(0, "", "u2f register"); if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { debugLog(0, "", "u2f register - badlen"); - send_u2f_error(U2F_SW_WRONG_DATA); + send_u2f_error(U2F_SW_WRONG_LENGTH); return; } @@ -571,7 +570,7 @@ void u2f_register(const APDU *a) send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state layoutU2FDialog("Register", getReadableAppId(req->appId)); - dialog_timeout = U2F_TIMEOUT; + dialog_timeout = 10*U2F_TIMEOUT; last_req_state = REG; return; } @@ -580,7 +579,7 @@ void u2f_register(const APDU *a) if (last_req_state == REG) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; + dialog_timeout = 10*U2F_TIMEOUT; return; } @@ -640,6 +639,7 @@ void u2f_register(const APDU *a) 1 /* keyhandleLen */ + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2; + last_req_state = INIT; send_u2f_msg(data, l); return; } @@ -655,7 +655,7 @@ void u2f_authenticate(const APDU *a) if (APDU_LEN(*a) < 64) { /// FIXME: decent value debugLog(0, "", "u2f authenticate - badlen"); - send_u2f_error(U2F_SW_WRONG_DATA); + send_u2f_error(U2F_SW_WRONG_LENGTH); return; } @@ -699,19 +699,16 @@ void u2f_authenticate(const APDU *a) if (last_req_state == INIT) { // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state layoutU2FDialog("Authenticate", getReadableAppId(req->appId)); - dialog_timeout = U2F_TIMEOUT; last_req_state = AUTH; - return; } // Awaiting Keypress if (last_req_state == AUTH) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; + dialog_timeout = 10*U2F_TIMEOUT; return; } @@ -753,10 +750,10 @@ void u2f_authenticate(const APDU *a) memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len, "\x90\x00", 2); + last_req_state = INIT; send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); - last_req_state = INIT; } } diff --git a/firmware/u2f.h b/firmware/u2f.h index 6e4c0862c0..6ed7f02f06 100644 --- a/firmware/u2f.h +++ b/firmware/u2f.h @@ -39,7 +39,7 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *buf); void u2fhid_init_cmd(const U2FHID_FRAME *f); void u2fhid_read_start(const U2FHID_FRAME *f); bool u2fhid_write(uint8_t *buf); -void u2fhid_init(const U2FHID_INIT_REQ *init_req); +void u2fhid_init(const U2FHID_FRAME *in); void u2fhid_ping(const uint8_t *buf, uint32_t len); void u2fhid_wink(const uint8_t *buf, uint32_t len); void u2fhid_sync(const uint8_t *buf, uint32_t len); diff --git a/firmware/u2f/u2f.h b/firmware/u2f/u2f.h index 4291c594b2..62979a3160 100644 --- a/firmware/u2f/u2f.h +++ b/firmware/u2f/u2f.h @@ -129,8 +129,10 @@ extern "C" // Command status responses #define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR -#define U2F_SW_WRONG_DATA 0x6984 // SW_WRONG_DATA +#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH +#define U2F_SW_DATA_INVALID 0x6984 // SW_WRONG_DATA #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED +#define U2F_SW_WRONG_DATA 0x6a80 // SW_WRONG_DATA #define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED #define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED diff --git a/firmware/usb.c b/firmware/usb.c index 91ed2b847d..d1dadd71b3 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -165,14 +165,14 @@ static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 1, + .bInterval = 2, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 1, + .bInterval = 2, }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ From 053fe7cb66d0588127b09365567896e9d6ce0435 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 24 May 2016 01:54:08 +0200 Subject: [PATCH 0240/1154] Remove Cancel Option U2F doesn't allow cancellation on device. Also fix button state in protect. This fixes the following bug: 1. wipe device 2. press and hold right button, click left button to cancel. 3. release all buttons. 4. wipe device again, now automatic. --- firmware/layout2.c | 2 +- firmware/protect.c | 1 + firmware/u2f.c | 55 ++++++++++++---------------------------------- 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 73b566c8e0..7805258b66 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -337,5 +337,5 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) } void layoutU2FDialog(const char *verb, const char *appid) { - layoutDialog(DIALOG_ICON_QUESTION, "Cancel", verb, NULL, verb, "U2F security key?", "", appid, "", NULL); + layoutDialog(DIALOG_ICON_QUESTION, NULL, verb, NULL, verb, "U2F security key?", "", appid, "", NULL); } diff --git a/firmware/protect.c b/firmware/protect.c index a39ee07870..a1b127ffbb 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -44,6 +44,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) resp.has_code = true; resp.code = type; usbTiny(1); + buttonUpdate(); // Clear button state msg_write(MessageType_MessageType_ButtonRequest, &resp); for (;;) { diff --git a/firmware/u2f.c b/firmware/u2f.c index 46660cae77..5ce8b75be7 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -65,14 +65,10 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; // Auth/Register request state machine typedef enum { INIT = 0, - BTN_NO = 1, - BTN_YES = 2, AUTH = 10, - AUTH_FAIL = 11, - AUTH_PASS = 12, + AUTH_PASS = 11, REG = 20, - REG_FAIL = 21, - REG_PASS = 22 + REG_PASS = 21 } U2F_STATE; static U2F_STATE last_req_state = INIT; @@ -92,16 +88,6 @@ typedef struct { uint8_t chal[U2F_CHAL_SIZE]; } U2F_AUTHENTICATE_SIG_STR; -uint8_t buttonState(void) -{ - buttonUpdate(); - - if ((button.NoDown > 10) || button.NoUp) - return BTN_NO; - if ((button.YesDown > 10) || button.YesUp) - return BTN_YES; - return 0; -} #if DEBUG_LOG char *debugInt(const uint32_t i) @@ -259,18 +245,19 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { reader->cmd = 0; reader->seq = 255; uint8_t bs = 0; - while (dialog_timeout-- && bs == 0 && reader->cmd == 0) { + while (dialog_timeout && bs == 0 && reader->cmd == 0) { + dialog_timeout--; usbPoll(); // may trigger new request - bs = buttonState(); + buttonUpdate(); + if (button.YesUp && + (last_req_state == AUTH || last_req_state == REG)) { + last_req_state++; + } } if (reader->cmd == 0) { if (dialog_timeout == 0) { - last_req_state += BTN_NO; // Timeout is like button no - } - else { - last_req_state += bs; - dialog_timeout = 0; + last_req_state = INIT; } cid = 0; reader = 0; @@ -296,7 +283,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) return send_u2fhid_error(cid, ERR_INVALID_LEN); if (dialog_timeout > 0) - dialog_timeout = U2F_TIMEOUT; + dialog_timeout = 10*U2F_TIMEOUT; U2FHID_FRAME f; MEMSET_BZERO(&f, sizeof(f)); @@ -563,16 +550,13 @@ void u2f_register(const APDU *a) } // First Time request, return not present and display request dialog - if (last_req_state == 0) { + if (last_req_state == INIT) { // wake up crypto system to be ready for signing getDerivedNode(NULL, 0); // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); buttonUpdate(); // Clear button state layoutU2FDialog("Register", getReadableAppId(req->appId)); - dialog_timeout = 10*U2F_TIMEOUT; last_req_state = REG; - return; } // Still awaiting Keypress @@ -583,12 +567,6 @@ void u2f_register(const APDU *a) return; } - // Buttons said no! - if (last_req_state == REG_FAIL) { - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } - // Buttons said yes if (last_req_state == REG_PASS) { uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; @@ -640,6 +618,7 @@ void u2f_register(const APDU *a) sizeof(U2F_ATT_CERT) + sig_len + 2; last_req_state = INIT; + dialog_timeout = 0; send_u2f_msg(data, l); return; } @@ -712,13 +691,6 @@ void u2f_authenticate(const APDU *a) return; } - // Buttons said no! - if (last_req_state == AUTH_FAIL) { - send_u2f_error( - U2F_SW_WRONG_DATA); // error:bad key handle - return; - } - // Buttons said yes if (last_req_state == AUTH_PASS) { uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; @@ -751,6 +723,7 @@ void u2f_authenticate(const APDU *a) U2F_MAX_EC_SIG_SIZE + sig_len, "\x90\x00", 2); last_req_state = INIT; + dialog_timeout = 0; send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); From 94b6733a6e7262f7bae237c7d3d0a87ab58e3018 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 May 2016 20:27:45 +0200 Subject: [PATCH 0241/1154] fix ar usage --- Makefile | 2 +- Makefile.include | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f67ae0febc..bbb79ccd01 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OBJS += gen/bitmaps.o OBJS += gen/fonts.o libtrezor.a: $(OBJS) - ar rcs libtrezor.a $(OBJS) + $(AR) rcs libtrezor.a $(OBJS) include Makefile.include diff --git a/Makefile.include b/Makefile.include index f931984328..0f46d7d828 100644 --- a/Makefile.include +++ b/Makefile.include @@ -6,6 +6,7 @@ CC = $(PREFIX)gcc LD = $(PREFIX)gcc OBJCOPY = $(PREFIX)objcopy OBJDUMP = $(PREFIX)objdump +AR = $(PREFIX)ar FLASH = st-flash OPENOCD = openocd From c691f9b5e99d89095580aeacdd30ff2c28e9ba8c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 May 2016 20:31:01 +0200 Subject: [PATCH 0242/1154] fix python shebangs --- bootloader/combine/prepare.py | 2 +- bootloader/firmware_align.py | 2 +- bootloader/firmware_sign.py | 2 +- bootloader/firmware_sign_split.py | 3 +-- gen/bitmaps/generate.py | 3 +-- gen/fonts/generate.py | 2 +- gen/handlers/handlers.py | 3 +-- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/bootloader/combine/prepare.py b/bootloader/combine/prepare.py index 491c3000f5..0d463117c2 100755 --- a/bootloader/combine/prepare.py +++ b/bootloader/combine/prepare.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 bl = open('bl.bin').read() fw = open('fw.bin').read() combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:] diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index 6a2788c9dd..d0376784fa 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 import sys import os diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 152f92ed57..7ccd8e99a3 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 import argparse import hashlib import struct diff --git a/bootloader/firmware_sign_split.py b/bootloader/firmware_sign_split.py index 3d72b968ba..7e6195a238 100755 --- a/bootloader/firmware_sign_split.py +++ b/bootloader/firmware_sign_split.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +#!/usr/bin/env python2 import hashlib import os import subprocess diff --git a/gen/bitmaps/generate.py b/gen/bitmaps/generate.py index 54b3ac2cbe..bc987dd59f 100755 --- a/gen/bitmaps/generate.py +++ b/gen/bitmaps/generate.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +#!/usr/bin/env python2 import glob import os from PIL import Image diff --git a/gen/fonts/generate.py b/gen/fonts/generate.py index 3bd5b8e7c1..8f166f82a7 100755 --- a/gen/fonts/generate.py +++ b/gen/fonts/generate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 from PIL import Image class Img(object): diff --git a/gen/handlers/handlers.py b/gen/handlers/handlers.py index d74a64afe6..ae1635b5f5 100755 --- a/gen/handlers/handlers.py +++ b/gen/handlers/handlers.py @@ -1,5 +1,4 @@ -#!/usr/bin/python - +#!/usr/bin/env python2 handlers = [ 'hard_fault_handler', 'mem_manage_handler', From af442d17e038114d0f25ab31588e82db1a0f11c9 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 25 May 2016 00:41:13 +0200 Subject: [PATCH 0243/1154] Faster flashing, smoother animation. Compute sha256 hahsum at the end. Display progress bar for flash erase. --- bootloader/bootloader.h | 4 ++-- bootloader/usb.c | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 3a37d60443..abe80786ff 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 -#define VERSION_PATCH 6 +#define VERSION_PATCH 7 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x02" -#define VERSION_PATCH_CHAR "\x06" +#define VERSION_PATCH_CHAR "\x07" #include "memory.h" diff --git a/bootloader/usb.c b/bootloader/usb.c index 48e6692a71..f4a73533e5 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -278,18 +278,20 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) buttonUpdate(); } while (!button.YesUp && !button.NoUp); if (button.YesUp) { - layoutProgress("INSTALLING ... Please wait", 0); // backup metadata memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); flash_unlock(); // erase metadata area for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000*(i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } // erase code area for (i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000*(i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } + layoutProgress("INSTALLING ... Please wait", 0); flash_lock(); send_msg_success(dev); flash_state = STATE_FLASHSTART; @@ -350,7 +352,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } p = buf + 1; - if (flash_anim % 8 == 4) { + if (flash_anim % 32 == 4) { layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); } flash_anim++; @@ -364,7 +366,6 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_program_word(FLASH_META_START + flash_pos, *w); // the first 256 bytes of firmware is metadata descriptor } else { flash_program_word(FLASH_APP_START + (flash_pos - FLASH_META_DESC_LEN), *w); // the rest is code - sha256_Update(&ctx, towrite, 4); } flash_pos += 4; wi = 0; @@ -374,6 +375,8 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_lock(); // flashing done if (flash_pos == flash_len) { + sha256_Update(&ctx, (unsigned char*) FLASH_APP_START, + flash_len - FLASH_META_DESC_LEN); flash_state = STATE_CHECK; send_msg_buttonrequest_firmwarecheck(dev); } From 87bfd5a8295136dc9cdcc0715ccbcfc370b7271f Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 25 May 2016 01:14:32 +0200 Subject: [PATCH 0244/1154] Bugfix: restore storage. Storage restore was broken due to my previous patch. --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 1c539aee86..4423592c6d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -94,7 +94,7 @@ void storage_check_flash_errors(void) bool storage_from_flash(void) { - if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) == 0) { + if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) != 0) { // wrong magic return false; } From e119656c299632914dd2646c3ec28d39221205c2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 26 May 2016 13:33:10 +0200 Subject: [PATCH 0245/1154] use descriptor that matches fido one (except usage_page) --- firmware/usb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 040a1bcef1..d8ba6d9b71 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -50,17 +50,20 @@ static const struct usb_device_descriptor dev_descr = { }; static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (1) 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x85, 0x3f, // REPORT_ID (63) 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x3f, // REPORT_COUNT (63) - 0x09, 0x01, // USAGE (1) + 0x95, 0x40, // REPORT_COUNT (64) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x01, // USAGE (1) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; From e09337112943d46f854cca64eeb523b67883b760 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 24 May 2016 23:44:40 +0200 Subject: [PATCH 0246/1154] Added storage area for u2f counter. To prevent flashing for every u2f operation just clear one bit in the u2f area to indicate an increased counter. --- firmware/storage.c | 98 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index f3d8fbb183..32e269b8be 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -48,13 +48,15 @@ char storage_uuid_str[25]; /* storage layout: - offset | type/length | description ---------+-------------+------------------------------- - 0x0000 | 4 bytes | magic = 'stor' - 0x0004 | 12 bytes | uuid - 0x0010 | ? | Storage structure - 0x4000 | 4 kbytes | area for pin failures - 0x5000 | 12 kbytes | reserved + offset | type/length | description +--------+--------------+------------------------------- + 0x0000 | 4 bytes | magic = 'stor' + 0x0004 | 12 bytes | uuid + 0x0010 | ? bytes | Storage structure +--------+--------------+------------------------------- + 0x4000 | 4 kbytes | area for pin failures + 0x5000 | 256 bytes | area for u2f counter updates + 0x5100 | 11.75 kbytes | reserved The area for pin failures looks like this: 0 ... 0 pinfail 0xffffffff .. 0xffffffff @@ -63,15 +65,28 @@ the number of zeros is the number of pin failures. This layout is used because we can only clear bits without erasing the flash. +The area for u2f counter updates is just a sequence of zero-bits +followed by a sequence of one-bits. The bits in a byte are numbered +from LSB to MSB. The number of zero bits is the offset that should +be added to the storage u2f_counter to get the real counter value. + */ #define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000) #define FLASH_STORAGE_PINAREA_LEN (0x1000) +#define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) +#define FLASH_STORAGE_U2FAREA_LEN (0x100) #define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage)) _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); _Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); _Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); +/* Current u2f offset, i.e. u2f counter is + * storage.u2f_counter + storage_u2f_offset. + * This corresponds to the number of cleared bits in the U2FAREA. + */ +static uint32_t storage_u2f_offset; + static bool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t sessionSeed[64]; @@ -132,6 +147,15 @@ bool storage_from_flash(void) storage.has_pin_failed_attempts = false; storage.pin_failed_attempts = 0; } + uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA; + while (*u2fptr == 0) + u2fptr++; + storage_u2f_offset = 32 * (u2fptr - (uint32_t*) FLASH_STORAGE_U2FAREA); + uint32_t u2fword = *u2fptr; + while ((u2fword & 1) == 0) { + storage_u2f_offset++; + u2fword >>= 1; + } // upgrade storage version if (version != STORAGE_VERSION) { storage.version = STORAGE_VERSION; @@ -185,15 +209,13 @@ static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) { return addr; } -void storage_commit(void) +static void storage_commit_locked(void) { uint8_t meta_backup[FLASH_META_DESC_LEN]; // backup meta memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); - flash_clear_status_flags(); - flash_unlock(); // erase storage flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); // copy meta @@ -209,6 +231,13 @@ void storage_commit(void) flash_program_word(flash, 0); flash += 4; } +} + +void storage_commit(void) +{ + flash_clear_status_flags(); + flash_unlock(); + storage_commit_locked(); flash_lock(); storage_check_flash_errors(); } @@ -429,23 +458,38 @@ bool session_isPinCached(void) return sessionPinCached; } -void storage_clearPinArea() +void storage_clearPinArea(void) { flash_clear_status_flags(); flash_unlock(); flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_lock(); storage_check_flash_errors(); + storage_u2f_offset = 0; +} + +// called when u2f area or pin area overflows +static void storage_area_recycle(uint32_t new_pinfails) +{ + // erase storage sector + flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); + flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails); + if (storage_u2f_offset > 0) { + storage.has_u2f_counter = true; + storage.u2f_counter += storage_u2f_offset; + storage_commit_locked(); + storage_u2f_offset = 0; + } } void storage_resetPinFails(uint32_t *pinfailsptr) { flash_clear_status_flags(); flash_unlock(); - if ((uint32_t) (pinfailsptr + 1) - FLASH_STORAGE_PINAREA - >= FLASH_STORAGE_PINAREA_LEN) { - // erase extra storage sector - flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); + if ((uint32_t) (pinfailsptr + 1) + >= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) { + // recycle extra storage sector + storage_area_recycle(0xffffffff); } else { flash_program_word((uint32_t) pinfailsptr, 0); } @@ -483,14 +527,24 @@ bool storage_isInitialized(void) return storage.has_node || storage.has_mnemonic; } +uint32_t storage_getU2FCounter(void) +{ + return storage.u2f_counter + storage_u2f_offset; +} + uint32_t storage_nextU2FCounter(void) { - if(!storage.has_u2f_counter) { - storage.has_u2f_counter = true; - storage.u2f_counter = 1; - } else { - storage.u2f_counter++; + uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); + uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31); + + flash_clear_status_flags(); + flash_unlock(); + flash_program_word((uint32_t) ptr, newval); + storage_u2f_offset++; + if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) { + storage_area_recycle(*storage_getPinFailsPtr()); } - storage_commit(); - return storage.u2f_counter; + flash_lock(); + storage_check_flash_errors(); + return storage.u2f_counter + storage_u2f_offset; } From 18d549c83d6bea8fe9ab52ee2482755fc0ddb15e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 26 May 2016 20:02:54 +0200 Subject: [PATCH 0247/1154] Fix U2F hid interface index for debug link --- firmware/usb.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 0264491b21..ad3bcb4ff1 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -28,6 +28,12 @@ #include "storage.h" #include "util.h" +#if DEBUG_LINK +#define USB_INTERFACE_INDEX_U2F 2 +#else +#define USB_INTERFACE_INDEX_U2F 1 +#endif + #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) @@ -181,11 +187,7 @@ static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, -#if DEBUG_LINK - .bInterfaceNumber = 2, -#else - .bInterfaceNumber = 1, -#endif + .bInterfaceNumber = USB_INTERFACE_INDEX_U2F, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_HID, @@ -275,18 +277,18 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (req->wValue != 0x2200)) return 0; - if (req->wIndex==1) { - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = sizeof(hid_report_descriptor_u2f); - return 1; - } + if (req->wIndex == USB_INTERFACE_INDEX_U2F) { + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = sizeof(hid_report_descriptor_u2f); + return 1; + } - debugLog(0, "", "hid_control_request trezor"); - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); - return 1; + debugLog(0, "", "hid_control_request trezor"); + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + return 1; } static volatile char tiny = 0; From be0858b7d724a5efa3f57c2e4c097791e04e2951 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 26 May 2016 20:27:40 +0200 Subject: [PATCH 0248/1154] Updated protobuf --- firmware/protob/messages.options | 3 + firmware/protob/messages.pb.c | 61 +++++++++++++- firmware/protob/messages.pb.h | 136 ++++++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 2 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c707aac054..34ed1e21d0 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -116,3 +116,6 @@ DebugLinkState.recovery_fake_word max_size:12 DebugLinkLog.bucket max_size:33 DebugLinkLog.text max_size:256 + +DebugLinkMemory.memory max_size:1024 +DebugLinkMemoryWrite.memory max_size:1024 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index c1420d6048..a527f31224 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -149,11 +149,22 @@ const pb_field_t GetAddress_fields[5] = { PB_LAST_FIELD }; +const pb_field_t EthereumGetAddress_fields[3] = { + PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumGetAddress, address_n, address_n, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, EthereumGetAddress, show_display, address_n, 0), + PB_LAST_FIELD +}; + const pb_field_t Address_fields[2] = { PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), PB_LAST_FIELD }; +const pb_field_t EthereumAddress_fields[2] = { + PB_FIELD2( 1, BYTES , REQUIRED, CALLBACK, FIRST, EthereumAddress, address, address, 0), + PB_LAST_FIELD +}; + const pb_field_t WipeDevice_fields[1] = { PB_LAST_FIELD }; @@ -317,6 +328,31 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; +const pb_field_t EthereumSignTx_fields[9] = { + PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumSignTx, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, nonce, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_price, nonce, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_limit, gas_price, 0), + PB_FIELD2( 5, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, to, gas_limit, 0), + PB_FIELD2( 6, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, value, to, 0), + PB_FIELD2( 7, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, data_initial_chunk, value, 0), + PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxRequest_fields[5] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, EthereumTxRequest, data_length, data_length, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_v, data_length, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_r, signature_v, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_s, signature_r, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxAck_fields[2] = { + PB_FIELD2( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EthereumTxAck, data_chunk, data_chunk, 0), + PB_LAST_FIELD +}; + const pb_field_t SignIdentity_fields[5] = { PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), @@ -375,6 +411,29 @@ const pb_field_t DebugLinkLog_fields[4] = { PB_LAST_FIELD }; +const pb_field_t DebugLinkMemoryRead_fields[3] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryRead, address, address, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkMemoryRead, length, address, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkMemory_fields[2] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkMemory, memory, memory, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkMemoryWrite_fields[4] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryWrite, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, memory, address, 0), + PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, flash, memory, 0), + PB_LAST_FIELD +}; + +const pb_field_t DebugLinkFlashErase_fields[2] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkFlashErase, sector, sector, 0), + PB_LAST_FIELD +}; + /* Check that field information fits in pb_field_t */ #if !defined(PB_FIELD_32BIT) @@ -385,7 +444,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index f4cd33ff1a..e3c8485e05 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -61,11 +61,20 @@ typedef enum _MessageType { MessageType_MessageType_SignIdentity = 53, MessageType_MessageType_SignedIdentity = 54, MessageType_MessageType_GetFeatures = 55, + MessageType_MessageType_EthereumGetAddress = 56, + MessageType_MessageType_EthereumAddress = 57, + MessageType_MessageType_EthereumSignTx = 58, + MessageType_MessageType_EthereumTxRequest = 59, + MessageType_MessageType_EthereumTxAck = 60, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, MessageType_MessageType_DebugLinkStop = 103, - MessageType_MessageType_DebugLinkLog = 104 + MessageType_MessageType_DebugLinkLog = 104, + MessageType_MessageType_DebugLinkMemoryRead = 110, + MessageType_MessageType_DebugLinkMemory = 111, + MessageType_MessageType_DebugLinkMemoryWrite = 112, + MessageType_MessageType_DebugLinkFlashErase = 113 } MessageType; /* Struct definitions */ @@ -190,6 +199,11 @@ typedef struct _DebugLinkDecision { bool yes_no; } DebugLinkDecision; +typedef struct _DebugLinkFlashErase { + bool has_sector; + uint32_t sector; +} DebugLinkFlashErase; + typedef struct _DebugLinkLog { bool has_level; uint32_t level; @@ -199,6 +213,37 @@ typedef struct _DebugLinkLog { char text[256]; } DebugLinkLog; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DebugLinkMemory_memory_t; + +typedef struct _DebugLinkMemory { + bool has_memory; + DebugLinkMemory_memory_t memory; +} DebugLinkMemory; + +typedef struct _DebugLinkMemoryRead { + bool has_address; + uint32_t address; + bool has_length; + uint32_t length; +} DebugLinkMemoryRead; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} DebugLinkMemoryWrite_memory_t; + +typedef struct _DebugLinkMemoryWrite { + bool has_address; + uint32_t address; + bool has_memory; + DebugLinkMemoryWrite_memory_t memory; + bool has_flash; + bool flash; +} DebugLinkMemoryWrite; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -343,6 +388,41 @@ typedef struct _EstimateTxSize { char coin_name[17]; } EstimateTxSize; +typedef struct _EthereumAddress { + pb_callback_t address; +} EthereumAddress; + +typedef struct _EthereumGetAddress { + pb_callback_t address_n; + bool has_show_display; + bool show_display; +} EthereumGetAddress; + +typedef struct _EthereumSignTx { + pb_callback_t address_n; + pb_callback_t nonce; + pb_callback_t gas_price; + pb_callback_t gas_limit; + pb_callback_t to; + pb_callback_t value; + pb_callback_t data_initial_chunk; + bool has_data_length; + uint32_t data_length; +} EthereumSignTx; + +typedef struct _EthereumTxAck { + pb_callback_t data_chunk; +} EthereumTxAck; + +typedef struct _EthereumTxRequest { + bool has_data_length; + uint32_t data_length; + bool has_signature_v; + uint32_t signature_v; + pb_callback_t signature_r; + pb_callback_t signature_s; +} EthereumTxRequest; + typedef struct _Failure { bool has_code; FailureType code; @@ -681,7 +761,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_default {HDNodeType_init_default, false, ""} #define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} +#define EthereumGetAddress_init_default {{{NULL}, NULL}, false, 0} #define Address_init_default {""} +#define EthereumAddress_init_default {{{NULL}, NULL}} #define WipeDevice_init_default {0} #define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} #define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, ""} @@ -705,6 +787,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} +#define EthereumSignTx_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EthereumTxRequest_init_default {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_default {{{NULL}, NULL}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_default {0} @@ -714,6 +799,10 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0} #define DebugLinkStop_init_default {0} #define DebugLinkLog_init_default {false, 0, false, "", false, ""} +#define DebugLinkMemoryRead_init_default {false, 0, false, 0} +#define DebugLinkMemory_init_default {false, {0, {0}}} +#define DebugLinkMemoryWrite_init_default {false, 0, false, {0, {0}}, false, 0} +#define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} #define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} @@ -735,7 +824,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} #define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} +#define EthereumGetAddress_init_zero {{{NULL}, NULL}, false, 0} #define Address_init_zero {""} +#define EthereumAddress_init_zero {{{NULL}, NULL}} #define WipeDevice_init_zero {0} #define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0} #define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, ""} @@ -759,6 +850,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} +#define EthereumSignTx_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EthereumTxRequest_init_zero {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_zero {{{NULL}, NULL}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} #define FirmwareErase_init_zero {0} @@ -768,6 +862,10 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0} #define DebugLinkStop_init_zero {0} #define DebugLinkLog_init_zero {false, 0, false, "", false, ""} +#define DebugLinkMemoryRead_init_zero {false, 0, false, 0} +#define DebugLinkMemory_init_zero {false, {0, {0}}} +#define DebugLinkMemoryWrite_init_zero {false, 0, false, {0, {0}}, false, 0} +#define DebugLinkFlashErase_init_zero {false, 0} /* Field tags (for use in manual encoding/decoding) */ #define Address_address_tag 1 @@ -787,9 +885,16 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define CipherKeyValue_iv_tag 7 #define CipheredKeyValue_value_tag 1 #define DebugLinkDecision_yes_no_tag 1 +#define DebugLinkFlashErase_sector_tag 1 #define DebugLinkLog_level_tag 1 #define DebugLinkLog_bucket_tag 2 #define DebugLinkLog_text_tag 3 +#define DebugLinkMemory_memory_tag 1 +#define DebugLinkMemoryRead_address_tag 1 +#define DebugLinkMemoryRead_length_tag 2 +#define DebugLinkMemoryWrite_address_tag 1 +#define DebugLinkMemoryWrite_memory_tag 2 +#define DebugLinkMemoryWrite_flash_tag 3 #define DebugLinkState_layout_tag 1 #define DebugLinkState_pin_tag 2 #define DebugLinkState_matrix_tag 3 @@ -819,6 +924,22 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define EstimateTxSize_outputs_count_tag 1 #define EstimateTxSize_inputs_count_tag 2 #define EstimateTxSize_coin_name_tag 3 +#define EthereumAddress_address_tag 1 +#define EthereumGetAddress_address_n_tag 1 +#define EthereumGetAddress_show_display_tag 2 +#define EthereumSignTx_address_n_tag 1 +#define EthereumSignTx_nonce_tag 2 +#define EthereumSignTx_gas_price_tag 3 +#define EthereumSignTx_gas_limit_tag 4 +#define EthereumSignTx_to_tag 5 +#define EthereumSignTx_value_tag 6 +#define EthereumSignTx_data_initial_chunk_tag 7 +#define EthereumSignTx_data_length_tag 8 +#define EthereumTxAck_data_chunk_tag 1 +#define EthereumTxRequest_data_length_tag 1 +#define EthereumTxRequest_signature_v_tag 2 +#define EthereumTxRequest_signature_r_tag 3 +#define EthereumTxRequest_signature_s_tag 4 #define Failure_code_tag 1 #define Failure_message_tag 2 #define Features_vendor_tag 1 @@ -932,7 +1053,9 @@ extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[4]; extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[5]; +extern const pb_field_t EthereumGetAddress_fields[3]; extern const pb_field_t Address_fields[2]; +extern const pb_field_t EthereumAddress_fields[2]; extern const pb_field_t WipeDevice_fields[1]; extern const pb_field_t LoadDevice_fields[8]; extern const pb_field_t ResetDevice_fields[7]; @@ -956,6 +1079,9 @@ extern const pb_field_t SignTx_fields[6]; extern const pb_field_t SimpleSignTx_fields[7]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; +extern const pb_field_t EthereumSignTx_fields[9]; +extern const pb_field_t EthereumTxRequest_fields[5]; +extern const pb_field_t EthereumTxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t FirmwareErase_fields[1]; @@ -965,6 +1091,10 @@ extern const pb_field_t DebugLinkGetState_fields[1]; extern const pb_field_t DebugLinkState_fields[11]; extern const pb_field_t DebugLinkStop_fields[1]; extern const pb_field_t DebugLinkLog_fields[4]; +extern const pb_field_t DebugLinkMemoryRead_fields[3]; +extern const pb_field_t DebugLinkMemory_fields[2]; +extern const pb_field_t DebugLinkMemoryWrite_fields[4]; +extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 @@ -1021,6 +1151,10 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define DebugLinkState_size (1468 + HDNodeType_size) #define DebugLinkStop_size 0 #define DebugLinkLog_size 300 +#define DebugLinkMemoryRead_size 12 +#define DebugLinkMemory_size 1027 +#define DebugLinkMemoryWrite_size 1035 +#define DebugLinkFlashErase_size 6 #ifdef __cplusplus } /* extern "C" */ From 78d11cf06029360e49d4663ccf2c019655f5af74 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 26 May 2016 20:28:11 +0200 Subject: [PATCH 0249/1154] New memory access over debug link --- firmware/fsm.c | 38 ++++++++++++++++++++++++++++++++++++++ firmware/fsm.h | 3 +++ firmware/messages.c | 4 ++++ 3 files changed, 45 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 7d9b72d440..0b08e1d18b 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -46,6 +46,7 @@ #include "ripemd160.h" #include "curves.h" #include "secp256k1.h" +#include // message methods @@ -975,4 +976,41 @@ void fsm_msgDebugLinkStop(DebugLinkStop *msg) (void)msg; } +void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) +{ + RESP_INIT(DebugLinkMemory); + + uint32_t length = 1024; + if (msg->has_length && msg->length < length) + length = msg->length; + resp->has_memory = true; + memcpy(resp->memory.bytes, (void*) msg->address, length); + resp->memory.size = length; + msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); +} + +void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) +{ + uint32_t length = msg->memory.size; + if (msg->flash) { + flash_clear_status_flags(); + flash_unlock(); + uint32_t* src = (uint32_t *) msg->memory.bytes; + for (unsigned int i = 0; i < length; i += 4) { + flash_program_word(msg->address + i, *src); + src++; + } + flash_lock(); + } else { + memcpy((void *) msg->address, msg->memory.bytes, length); + } +} + +void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) +{ + flash_clear_status_flags(); + flash_unlock(); + flash_erase_sector(msg->sector, FLASH_CR_PROGRAM_X32); + flash_lock(); +} #endif diff --git a/firmware/fsm.h b/firmware/fsm.h index 1a3fcf8f1e..5b6eef971e 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -63,6 +63,9 @@ void fsm_msgWordAck(WordAck *msg); //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); void fsm_msgDebugLinkGetState(DebugLinkGetState *msg); void fsm_msgDebugLinkStop(DebugLinkStop *msg); +void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg); +void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg); +void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg); #endif #endif diff --git a/firmware/messages.c b/firmware/messages.c index 1994f61a78..57c311151d 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -97,9 +97,13 @@ static const struct MessagesMap_t MessagesMap[] = { // {'d', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *))fsm_msgDebugLinkDecision}, {'d', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *))fsm_msgDebugLinkGetState}, {'d', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *))fsm_msgDebugLinkStop}, + {'d', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *))fsm_msgDebugLinkMemoryRead}, + {'d', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *))fsm_msgDebugLinkMemoryWrite}, + {'d', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *))fsm_msgDebugLinkFlashErase}, // debug out messages {'d', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0}, {'d', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0}, + {'d', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0}, #endif // end {0, 0, 0, 0, 0} From a366700332802108e814825a6d189069fc01bcd1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 26 May 2016 21:21:08 +0200 Subject: [PATCH 0250/1154] fix indentation --- firmware/u2f.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 5ce8b75be7..c910ae5a48 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -477,31 +477,31 @@ const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) { - uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' - uint32_t i, key_path[KEY_PATH_ENTRIES]; - key_path[0] = U2F_KEY_PATH; - for (i = 1; i < KEY_PATH_ENTRIES; i++) { - // high bit for hardened keys - key_path[i]= 0x80000000 | random32(); - } + // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' + uint32_t i, key_path[KEY_PATH_ENTRIES]; + key_path[0] = U2F_KEY_PATH; + for (i = 1; i < KEY_PATH_ENTRIES; i++) { + // high bit for hardened keys + key_path[i]= 0x80000000 | random32(); + } - // First half of keyhandle is key_path - memcpy(key_handle, &key_path[1], KEY_PATH_LEN); + // First half of keyhandle is key_path + memcpy(key_handle, &key_path[1], KEY_PATH_LEN); - // prepare keypair from /random data - const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + // prepare keypair from /random data + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - // For second half of keyhandle - // Signature of app_id and random data - memcpy(&keybase[0], app_id, U2F_APPID_SIZE); - memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - hmac_sha256(node->private_key, sizeof(node->private_key), + // For second half of keyhandle + // Signature of app_id and random data + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); + hmac_sha256(node->private_key, sizeof(node->private_key), keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]); - // Done! - return node; + // Done! + return node; } From c4e8bd0d0ef0e9fbd0e46566c34236bc3bde0b1f Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 27 May 2016 14:03:20 +0200 Subject: [PATCH 0251/1154] More robust storage recycle sector Clear storage marker first before clearing the second sector to prevent leaving a state where only PIN failures have been cleared but storage is still present. --- firmware/storage.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 32e269b8be..e7bb56182d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -98,12 +98,17 @@ static char sessionPassphrase[51]; #define STORAGE_VERSION 6 +void storage_show_error(void) +{ + layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) { } +} + void storage_check_flash_errors(void) { // flash operation failed if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) { } + storage_show_error(); } } @@ -471,15 +476,26 @@ void storage_clearPinArea(void) // called when u2f area or pin area overflows static void storage_area_recycle(uint32_t new_pinfails) { + // first clear storage marker. In case of a failure below it is better + // to clear the storage than to allow restarting with zero PIN failures + flash_program_word(FLASH_STORAGE_START, 0); + if (*(uint32_t *)FLASH_STORAGE_START != 0) { + storage_show_error(); + } + // erase storage sector flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails); + if (*(uint32_t *)FLASH_STORAGE_PINAREA != new_pinfails) { + storage_show_error(); + } + if (storage_u2f_offset > 0) { storage.has_u2f_counter = true; storage.u2f_counter += storage_u2f_offset; - storage_commit_locked(); storage_u2f_offset = 0; } + storage_commit_locked(); } void storage_resetPinFails(uint32_t *pinfailsptr) @@ -527,11 +543,6 @@ bool storage_isInitialized(void) return storage.has_node || storage.has_mnemonic; } -uint32_t storage_getU2FCounter(void) -{ - return storage.u2f_counter + storage_u2f_offset; -} - uint32_t storage_nextU2FCounter(void) { uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); From 11072320a9f0797350ad6a2bfcf850bef36fb632 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 27 May 2016 15:27:41 +0200 Subject: [PATCH 0252/1154] use ff01 usage page for debuglink --- firmware/usb.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index d8ba6d9b71..a9af880ce7 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -68,6 +68,26 @@ static const uint8_t hid_report_descriptor[] = { 0xc0 // END_COLLECTION }; +static const uint8_t hid_report_descriptor_debug[] = { + 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + + static const struct { struct usb_hid_descriptor hid_descriptor; struct { @@ -195,8 +215,13 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin return 0; /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + if (req->wIndex == 1) { + *buf = (uint8_t *)hid_report_descriptor_debug; + *len = sizeof(hid_report_descriptor_debug); + } else { + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + } return 1; } From 73e7d82e3fe7d0e5f789c97693573a59327e5864 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 28 May 2016 16:24:14 +0200 Subject: [PATCH 0253/1154] Allow initialize() to abort PIN wait --- firmware/protect.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/firmware/protect.c b/firmware/protect.c index 0ff821dac9..f893261c71 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -147,6 +147,7 @@ bool protectPin(bool use_cached) } uint32_t *fails = storage_getPinFailsPtr(); uint32_t wait = ~*fails; + usbTiny(1); while (wait > 0) { // convert wait to secstr string char secstrbuf[20]; @@ -164,8 +165,16 @@ bool protectPin(bool use_cached) layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second usbDelay(840000); + if (msg_tiny_id == MessageType_MessageType_Initialize) { + protectAbortedByInitialize = true; + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + return false; + } wait--; } + usbTiny(0); const char *pin; pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); if (!pin) { From e6a8204b1eead7bb98425194bb8c07a6fde65a25 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 28 May 2016 19:43:47 +0200 Subject: [PATCH 0254/1154] fix travis build failure --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8bb34ee731..5c4eaba755 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: c install: - - sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y + - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo apt-get update - - sudo apt-get install -y build-essential git gcc-arm-none-eabi + - sudo apt-get install -y build-essential git gcc-arm-embedded script: - make -C vendor/libopencm3 From 36b9d80120348700264bba518a533d4f82d79cbd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 7 Jun 2016 15:27:05 +0200 Subject: [PATCH 0255/1154] bump version (to 1.3.6) --- firmware/trezor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index a3ea5f4b48..79eee420b1 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 5 +#define VERSION_PATCH 6 #define STR(X) #X #define VERSTR(X) STR(X) From 2929bfbd48e8171c9444f194745746a1dcbc9ee3 Mon Sep 17 00:00:00 2001 From: Ondrej Sika Date: Mon, 6 Jun 2016 14:34:35 +0200 Subject: [PATCH 0256/1154] u2f - add Slush Pool to WellKnown --- firmware/u2f_knownapps.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index b57bbcb024..4320910afc 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -28,7 +28,7 @@ typedef struct { const char *appname; } U2FWellKnown; -static const U2FWellKnown u2f_well_known[3] = { +static const U2FWellKnown u2f_well_known[4] = { { // https://www.gstatic.com/securitykey/origins.json { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, @@ -52,6 +52,14 @@ static const U2FWellKnown u2f_well_known[3] = { 0xd9,0x1a,0x22,0xfe,0x6b,0x29,0xc0,0xcd, 0xf7,0x80,0x55,0x30,0x84,0x2a,0xf5,0x81 }, "Dropbox" + }, + { + // https://slushpool.com/static/security/u2f.json + { 0x08,0xb2,0xa3,0xd4,0x19,0x39,0xaa,0x31, + 0x66,0x84,0x93,0xcb,0x36,0xcd,0xcc,0x4f, + 0x16,0xc4,0xd9,0xb4,0xc8,0x23,0x8b,0x73, + 0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 }, + "Slush Pool" } }; From 9aaf0d37baf9f516fb25e7d239a408e0b0bc49cc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 8 Jun 2016 17:21:16 +0200 Subject: [PATCH 0257/1154] add u2f icons --- firmware/u2f_knownapps.h | 54 +++++++++++++++++++--------------- gen/bitmaps.c | 8 +++++ gen/bitmaps.h | 4 +++ gen/bitmaps/u2f_dropbox.png | Bin 0 -> 263 bytes gen/bitmaps/u2f_github.png | Bin 0 -> 236 bytes gen/bitmaps/u2f_google.png | Bin 0 -> 240 bytes gen/bitmaps/u2f_slushpool.png | Bin 0 -> 214 bytes 7 files changed, 42 insertions(+), 24 deletions(-) create mode 100644 gen/bitmaps/u2f_dropbox.png create mode 100644 gen/bitmaps/u2f_github.png create mode 100644 gen/bitmaps/u2f_google.png create mode 100644 gen/bitmaps/u2f_slushpool.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 4320910afc..32386c73b1 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -22,45 +22,51 @@ #include #include "u2f/u2f.h" +#include "bitmaps.h" typedef struct { - uint8_t appid[U2F_APPID_SIZE]; + const uint8_t appid[U2F_APPID_SIZE]; const char *appname; + const BITMAP *icon; } U2FWellKnown; static const U2FWellKnown u2f_well_known[4] = { - { - // https://www.gstatic.com/securitykey/origins.json - { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, + { + // https://www.gstatic.com/securitykey/origins.json + { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, 0xe1,0x51,0xed,0x8d,0x4d,0x3c,0x76,0x7a, 0x6c,0xc3,0x49,0x43,0x59,0x43,0x79,0x4e, 0x88,0x4f,0x3d,0x02,0x3a,0x82,0x29,0xfd }, - "Google" - }, - { - // https://github.com/u2f/trusted_facets - { 0x70,0x61,0x7d,0xfe,0xd0,0x65,0x86,0x3a, + "Google", + &bmp_u2f_google + }, + { + // https://github.com/u2f/trusted_facets + { 0x70,0x61,0x7d,0xfe,0xd0,0x65,0x86,0x3a, 0xf4,0x7c,0x15,0x55,0x6c,0x91,0x79,0x88, 0x80,0x82,0x8c,0xc4,0x07,0xfd,0xf7,0x0a, 0xe8,0x50,0x11,0x56,0x94,0x65,0xa0,0x75 }, - "Github" - }, - { - // https://www.dropbox.com/u2f-app-id.json - { 0xc5,0x0f,0x8a,0x7b,0x70,0x8e,0x92,0xf8, + "Github", + &bmp_u2f_github + }, + { + // https://www.dropbox.com/u2f-app-id.json + { 0xc5,0x0f,0x8a,0x7b,0x70,0x8e,0x92,0xf8, 0x2e,0x7a,0x50,0xe2,0xbd,0xc5,0x5d,0x8f, 0xd9,0x1a,0x22,0xfe,0x6b,0x29,0xc0,0xcd, 0xf7,0x80,0x55,0x30,0x84,0x2a,0xf5,0x81 }, - "Dropbox" - }, - { - // https://slushpool.com/static/security/u2f.json - { 0x08,0xb2,0xa3,0xd4,0x19,0x39,0xaa,0x31, - 0x66,0x84,0x93,0xcb,0x36,0xcd,0xcc,0x4f, - 0x16,0xc4,0xd9,0xb4,0xc8,0x23,0x8b,0x73, - 0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 }, - "Slush Pool" - } + "Dropbox", + &bmp_u2f_dropbox + }, + { + // https://slushpool.com/static/security/u2f.json + { 0x08,0xb2,0xa3,0xd4,0x19,0x39,0xaa,0x31, + 0x66,0x84,0x93,0xcb,0x36,0xcd,0xcc,0x4f, + 0x16,0xc4,0xd9,0xb4,0xc8,0x23,0x8b,0x73, + 0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 }, + "Slush Pool", + &bmp_u2f_slushpool + } }; #endif // U2F_KNOWNAPPS_INCLUDED diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 64808987fa..264064dc8c 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -23,6 +23,10 @@ const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x81, 0x80, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x7e, 0x08, 0x00, 0x00, 0x21, 0x81, 0x84, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x22, 0x00, 0x00, 0x48, 0x00, 0x12, 0x00, 0x00, 0x88, 0x00, 0x11, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x03, 0x9f, 0xff, 0xf9, 0xc0, 0x04, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x3f, 0xff, 0xfc, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x60, 0x00, 0x06, 0x10, 0x08, 0x1c, 0x00, 0x38, 0x10, 0x08, 0x03, 0x81, 0xc0, 0x10, 0x07, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; +const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data}; const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data}; @@ -47,3 +51,7 @@ const BITMAP bmp_logo48 = {40, 48, bmp_logo48_data}; const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data}; const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; +const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; +const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; +const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; +const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index 9eff4cd592..9c3db2bff2 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -31,5 +31,9 @@ extern const BITMAP bmp_logo48; extern const BITMAP bmp_logo48_empty; extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; +extern const BITMAP bmp_u2f_dropbox; +extern const BITMAP bmp_u2f_github; +extern const BITMAP bmp_u2f_google; +extern const BITMAP bmp_u2f_slushpool; #endif diff --git a/gen/bitmaps/u2f_dropbox.png b/gen/bitmaps/u2f_dropbox.png new file mode 100644 index 0000000000000000000000000000000000000000..9d78cadb004addcb8344a54cd62690849256c0cb GIT binary patch literal 263 zcmV+i0r>ujP)*Bi47H{Zla*jJXXUhY zYcWW{RwfmHc!A-Oego-^_%8hk?*_|yOZ N002ovPDHLkV1l8qa>4)r literal 0 HcmV?d00001 diff --git a/gen/bitmaps/u2f_github.png b/gen/bitmaps/u2f_github.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9be253e30c34e220ea3cac2145152b0189a3f7 GIT binary patch literal 236 zcmVo5iB zVHX|v@n&##lix2uQx+Oi6Fuc1qx{`OzJt8-je~Zd6Z)`{3Iz_vCY>b16WJl0gM-LS zU`2leD-9CL996ouil7PSdzpLq*buDeM=4xCVsx m4V+jBA_UP z8z^byR*3WzXoUmk=$ylI)vebB6!&?fF?3)o-6!@+L3{e`YG+&_w%ixRA9df%M#;b- zZn-@y?2s|1P>Rbt9UMtAY=VT>is-kjq45^o5a0000RmFP;X;f6Ka+7>t=K<}%hC+Am>L`_^2;*j|5iR4LG* N44$rjF6*2UngASlQk?(* literal 0 HcmV?d00001 From b1e3c52b0874b52f0aa819a01df074bad4cd98e6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 8 Jun 2016 17:55:25 +0200 Subject: [PATCH 0258/1154] remove DialogIcon enum, use bitmap structure directly --- bootloader/bootloader.c | 10 +++++----- bootloader/usb.c | 14 +++++++------- demo/demo.c | 2 +- firmware/fsm.c | 22 +++++++++++----------- firmware/layout2.c | 26 +++++++++++++------------- firmware/layout2.h | 3 ++- firmware/protect.c | 4 ++-- firmware/recovery.c | 4 ++-- firmware/reset.c | 10 +++++----- firmware/storage.c | 2 +- firmware/trezor.c | 2 +- layout.c | 28 ++++------------------------ layout.h | 12 ++---------- 13 files changed, 56 insertions(+), 83 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index b6b389ad99..30abc4bc54 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -45,18 +45,18 @@ void layoutFirmwareHash(uint8_t *hash) for (i = 0; i < 4; i++) { data2hex(hash + i * 8, 8, str[i]); } - layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); + layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); } void show_halt(void) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); system_halt(); } void show_unofficial_warning(uint8_t *hash) { - layoutDialog(DIALOG_ICON_WARNING, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); + layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); do { delay(100000); @@ -124,7 +124,7 @@ void check_firmware_sanity(void) broken++; } if (broken) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); system_halt(); } } @@ -133,7 +133,7 @@ uint32_t __stack_chk_guard; void __attribute__((noreturn)) __stack_chk_fail(void) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever } diff --git a/bootloader/usb.c b/bootloader/usb.c index f4a73533e5..3745b0cacd 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -272,7 +272,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_OPEN) { if (msg_id == 0x0006) { // FirmwareErase message (id 6) - layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); + layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); do { delay(100000); buttonUpdate(); @@ -299,7 +299,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); return; } return; @@ -310,7 +310,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (buf[9] != 0x0a) { // invalid contents send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); return; } // read payload length @@ -319,7 +319,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL); return; } sha256_Init(&ctx); @@ -348,7 +348,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (buf[0] != '?') { // invalid contents send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); return; } p = buf + 1; @@ -432,10 +432,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } flash_state = STATE_END; if (hash_check_ok) { - layoutDialog(DIALOG_ICON_OK, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); + layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); send_msg_success(dev); } else { - layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); send_msg_failure(dev); } return; diff --git a/demo/demo.c b/demo/demo.c index cfed6d6f68..f4ee18ac22 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -242,7 +242,7 @@ uint32_t __stack_chk_guard; void __attribute__((noreturn)) __stack_chk_fail(void) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever } diff --git a/firmware/fsm.c b/firmware/fsm.c index 0b08e1d18b..b7c6e5025a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -161,7 +161,7 @@ void fsm_msgPing(Ping *msg) RESP_INIT(Success); if (msg->has_button_protection && msg->button_protection) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); layoutHome(); @@ -196,16 +196,16 @@ void fsm_msgChangePin(ChangePin *msg) bool removal = msg->has_remove && msg->remove; if (removal) { if (storage_hasPin()) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL); } else { fsm_sendSuccess("PIN removed"); return; } } else { if (storage_hasPin()) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -233,7 +233,7 @@ void fsm_msgChangePin(ChangePin *msg) void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); layoutHome(); @@ -263,7 +263,7 @@ void fsm_msgFirmwareUpload(FirmwareUpload *msg) void fsm_msgGetEntropy(GetEntropy *msg) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); layoutHome(); @@ -332,7 +332,7 @@ void fsm_msgLoadDevice(LoadDevice *msg) return; } - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); layoutHome(); @@ -489,7 +489,7 @@ void fsm_msgClearSession(ClearSession *msg) void fsm_msgApplySettings(ApplySettings *msg) { if (msg->has_label) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); layoutHome(); @@ -497,7 +497,7 @@ void fsm_msgApplySettings(ApplySettings *msg) } } if (msg->has_language) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); layoutHome(); @@ -505,7 +505,7 @@ void fsm_msgApplySettings(ApplySettings *msg) } } if (msg->has_use_passphrase) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); layoutHome(); @@ -513,7 +513,7 @@ void fsm_msgApplySettings(ApplySettings *msg) } } if (msg->has_homescreen) { - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); layoutHome(); diff --git a/firmware/layout2.c b/firmware/layout2.c index 7805258b66..16b867441a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -31,7 +31,7 @@ void *layoutLast = layoutHome; -void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) +void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { layoutLast = layoutDialogSwipe; oledSwipeLeft(); @@ -119,7 +119,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, @@ -136,7 +136,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ { const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, @@ -153,7 +153,7 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) { (void)kb; const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, @@ -191,7 +191,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) void layoutSignMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", "Sign message?", str[0], str[1], str[2], str[3], NULL, NULL); } @@ -199,7 +199,7 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) void layoutVerifyAddress(const char *address) { const char **str = split_message((const uint8_t *)address, strlen(address), 17); - layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm", "Confirm address?", "Message signed by:", NULL, str[0], str[1], str[2], NULL); @@ -208,7 +208,7 @@ void layoutVerifyAddress(const char *address) void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm", "Verified message", str[0], str[1], str[2], str[3], NULL, NULL); } @@ -216,7 +216,7 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len) void layoutCipherKeyValue(bool encrypt, const char *key) { const char **str = split_message((const uint8_t *)key, strlen(key), 16); - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", encrypt ? "Encode value of this key?" : "Decode value of this key?", str[0], str[1], str[2], str[3], NULL, NULL); } @@ -224,7 +224,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key) void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", signing ? "Encrypt+Sign message?" : "Encrypt message?", str[0], str[1], str[2], str[3], NULL, NULL); } @@ -232,7 +232,7 @@ void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", + layoutDialogSwipe(&bmp_icon_info, NULL, "OK", address ? "Decrypted signed message" : "Decrypted message", str[0], str[1], str[2], str[3], NULL, NULL); } @@ -286,7 +286,7 @@ void layoutPublicKey(const uint8_t *pubkey) data2hex(pubkey, 1, desc + 12); data2hex(pubkey + 1, 32, hex); const char **str = split_message((const uint8_t *)hex, 32*2, 16); - layoutDialogSwipe(DIALOG_ICON_QUESTION, NULL, "Continue", NULL, + layoutDialogSwipe(&bmp_icon_question, NULL, "Continue", NULL, desc, str[0], str[1], str[2], str[3], NULL); } @@ -326,7 +326,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) row_user[0] = 0; } - layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", "Do you want to sign in?", row_proto[0] ? row_proto : NULL, row_hostport[0] ? row_hostport : NULL, @@ -337,5 +337,5 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) } void layoutU2FDialog(const char *verb, const char *appid) { - layoutDialog(DIALOG_ICON_QUESTION, NULL, verb, NULL, verb, "U2F security key?", "", appid, "", NULL); + layoutDialog(&bmp_icon_question, NULL, verb, NULL, verb, "U2F security key?", "", appid, "", NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index 6cbe30c436..d17ec7faaf 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -22,8 +22,9 @@ #include "layout.h" #include "types.pb.h" +#include "bitmaps.h" -void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); diff --git a/firmware/protect.c b/firmware/protect.c index a1b127ffbb..f92010915d 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -162,7 +162,7 @@ bool protectPin(bool use_cached) if (wait == 1) { secstrbuf[16] = 0; } - layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second usbDelay(800000); wait--; @@ -216,7 +216,7 @@ bool protectPassphrase(void) usbTiny(1); msg_write(MessageType_MessageType_PassphraseRequest, &resp); - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL); bool result; for (;;) { diff --git a/firmware/recovery.c b/firmware/recovery.c index bd5bda70f7..7ddceed63a 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -41,7 +41,7 @@ void next_word(void) { if (word_pos == 0) { const char * const *wl = mnemonic_wordlist(); strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); } else { fake_word[0] = 0; char desc[] = "##th word"; @@ -60,7 +60,7 @@ void next_word(void) { if (word_pos == 3 || word_pos == 23) { desc[2] = 'r'; desc[3] = 'd'; } - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); } WordRequest resp; memset(&resp, 0, sizeof(WordRequest)); diff --git a/firmware/reset.c b/firmware/reset.c index 1ecad15f4d..7b2fa72232 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -52,7 +52,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect data2hex(int_entropy + 24, 8, ent_str[3]); if (display_random) { - layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); + layoutDialogSwipe(&bmp_icon_info, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled"); layoutHome(); @@ -129,15 +129,15 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) current_word_display[j + 1] = 0; if (word_pos == (int)strength/32*3) { // last word if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } else { if (pass == 1) { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { diff --git a/firmware/storage.c b/firmware/storage.c index e7bb56182d..f1a21196aa 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -100,7 +100,7 @@ static char sessionPassphrase[51]; void storage_show_error(void) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) { } } diff --git a/firmware/trezor.c b/firmware/trezor.c index aa154d6e61..e54d81c7cc 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -32,7 +32,7 @@ uint32_t __stack_chk_guard; void __attribute__((noreturn)) __stack_chk_fail(void) { - layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever } diff --git a/layout.c b/layout.c index ecb97210b6..28a71ac9f5 100644 --- a/layout.c +++ b/layout.c @@ -22,33 +22,13 @@ #include "layout.h" #include "oled.h" -void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) +void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { int left = 0; oledClear(); - switch (icon) { - case DIALOG_NOICON: - break; - case DIALOG_ICON_ERROR: - oledDrawBitmap(0, 0, &bmp_icon_error); - left = 20; - break; - case DIALOG_ICON_INFO: - oledDrawBitmap(0, 0, &bmp_icon_info); - left = 20; - break; - case DIALOG_ICON_QUESTION: - oledDrawBitmap(0, 0, &bmp_icon_question); - left = 20; - break; - case DIALOG_ICON_WARNING: - oledDrawBitmap(0, 0, &bmp_icon_warning); - left = 20; - break; - case DIALOG_ICON_OK: - oledDrawBitmap(0, 0, &bmp_icon_ok); - left = 20; - break; + if (icon) { + oledDrawBitmap(0, 0, icon); + left = icon->width + 4; } if (line1) oledDrawString(left, 0 * 9, line1); if (line2) oledDrawString(left, 1 * 9, line2); diff --git a/layout.h b/layout.h index c7f127a92d..27f81d49e6 100644 --- a/layout.h +++ b/layout.h @@ -22,17 +22,9 @@ #include #include +#include "bitmaps.h" -typedef enum { - DIALOG_NOICON = 0, - DIALOG_ICON_ERROR, - DIALOG_ICON_INFO, - DIALOG_ICON_QUESTION, - DIALOG_ICON_WARNING, - DIALOG_ICON_OK, -} LayoutDialogIcon; - -void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressUpdate(bool refresh); void layoutProgress(const char *desc, int permil); From da067913c2b1177898588ad87acbd08a727a2386 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 9 Jun 2016 18:11:19 +0200 Subject: [PATCH 0259/1154] show app icons in u2f dialog --- firmware/layout2.c | 7 +++++-- firmware/layout2.h | 2 +- firmware/u2f.c | 30 ++++++++++++++++++++---------- firmware/u2f_knownapps.h | 2 +- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 16b867441a..4c0a3a3cae 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -336,6 +336,9 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) NULL); } -void layoutU2FDialog(const char *verb, const char *appid) { - layoutDialog(&bmp_icon_question, NULL, verb, NULL, verb, "U2F security key?", "", appid, "", NULL); +void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon) { + if (!appicon) { + appicon = &bmp_icon_question; + } + layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", "", appname, "", NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index d17ec7faaf..975d530bc2 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -41,6 +41,6 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) void layoutAddress(const char *address, const char *desc); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); -void layoutU2FDialog(const char *verb, const char *appid); +void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); #endif diff --git a/firmware/u2f.c b/firmware/u2f.c index c910ae5a48..cb05370c70 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -441,19 +441,23 @@ void u2f_version(const APDU *a) send_u2f_msg(version_response, sizeof(version_response)); } -static const char *getReadableAppId(const uint8_t appid[U2F_APPID_SIZE]) { +void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) { unsigned int i; - static char buf[6+2+6+1]; + static char buf[8+2+8+1]; for (i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { - if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) - return u2f_well_known[i].appname; + if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { + *appname = u2f_well_known[i].appname; + *appicon = u2f_well_known[i].appicon; + return; + } } - data2hex(appid, 3, &buf[0]); - buf[6] = buf[7] = '.'; - data2hex(appid + (U2F_APPID_SIZE - 3), 3, &buf[8]); - return buf; + data2hex(appid, 4, &buf[0]); + buf[8] = buf[9] = '.'; + data2hex(appid + (U2F_APPID_SIZE - 4), 4, &buf[10]); + *appname = buf; + *appicon = NULL; } const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) @@ -555,7 +559,10 @@ void u2f_register(const APDU *a) getDerivedNode(NULL, 0); // error: testof-user-presence is required buttonUpdate(); // Clear button state - layoutU2FDialog("Register", getReadableAppId(req->appId)); + const char *appname; + const BITMAP *appicon; + getReadableAppId(req->appId, &appname, &appicon); + layoutU2FDialog("Register", appname, appicon); last_req_state = REG; } @@ -679,7 +686,10 @@ void u2f_authenticate(const APDU *a) if (last_req_state == INIT) { // error: testof-user-presence is required buttonUpdate(); // Clear button state - layoutU2FDialog("Authenticate", getReadableAppId(req->appId)); + const char *appname; + const BITMAP *appicon; + getReadableAppId(req->appId, &appname, &appicon); + layoutU2FDialog("Authenticate", appname, appicon); last_req_state = AUTH; } diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 32386c73b1..947594012c 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -27,7 +27,7 @@ typedef struct { const uint8_t appid[U2F_APPID_SIZE]; const char *appname; - const BITMAP *icon; + const BITMAP *appicon; } U2FWellKnown; static const U2FWellKnown u2f_well_known[4] = { From 63696dc474d3bd410e056abdf5729d9481896774 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 10 Jun 2016 22:17:02 +0300 Subject: [PATCH 0260/1154] crypto: add ECDH session key generation --- firmware/crypto.c | 20 ++++++++++++++++++++ firmware/crypto.h | 3 +++ 2 files changed, 23 insertions(+) diff --git a/firmware/crypto.c b/firmware/crypto.c index 8587f84b5c..b9cd878146 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -27,6 +27,7 @@ #include "layout.h" #include "curves.h" #include "secp256k1.h" +#include "macros.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -100,6 +101,25 @@ int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_le return hdnode_sign_digest(node, message, signature + 1, NULL); } +int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key) +{ + curve_point point; + const ecdsa_curve *curve = node->curve->params; + if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { + return 1; + } + bignum256 k; + bn_read_be(node->private_key, &k); + point_multiply(curve, &k, &point, &point); + MEMSET_BZERO(&k, sizeof(k)); + + session_key[0] = 0x04; + bn_write_be(&point.x, session_key + 1); + bn_write_be(&point.y, session_key + 33); + MEMSET_BZERO(&point, sizeof(point)); + return 0; +} + int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; diff --git a/firmware/crypto.h b/firmware/crypto.h index 13b97bbb9c..8425046360 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -37,6 +37,9 @@ int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_le int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); + + int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); From e2064337c6fe45fcb5053ea53a87eb266c761aab Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 11 Jun 2016 22:20:38 +0300 Subject: [PATCH 0261/1154] Update protobuf definitions --- firmware/protob/messages.options | 5 ++ firmware/protob/messages.pb.c | 50 +++++++++++++- firmware/protob/messages.pb.h | 109 +++++++++++++++++++++++++++++++ vendor/trezor-common | 2 +- 4 files changed, 164 insertions(+), 2 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c707aac054..f13b1c740d 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -97,6 +97,11 @@ SignedIdentity.address max_size:36 SignedIdentity.public_key max_size:33 SignedIdentity.signature max_size:65 +GetECDHSessionKey.peer_public_key max_size:65 +GetECDHSessionKey.ecdsa_curve_name max_size:32 + +ECDHSessionKey.session_key max_size:65 + # not used in firmware SimpleSignTx.inputs max_count:0 SimpleSignTx.outputs max_count:0 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index c1420d6048..bee2f736d1 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -149,11 +149,22 @@ const pb_field_t GetAddress_fields[5] = { PB_LAST_FIELD }; +const pb_field_t EthereumGetAddress_fields[3] = { + PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumGetAddress, address_n, address_n, 0), + PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, EthereumGetAddress, show_display, address_n, 0), + PB_LAST_FIELD +}; + const pb_field_t Address_fields[2] = { PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), PB_LAST_FIELD }; +const pb_field_t EthereumAddress_fields[2] = { + PB_FIELD2( 1, BYTES , REQUIRED, CALLBACK, FIRST, EthereumAddress, address, address, 0), + PB_LAST_FIELD +}; + const pb_field_t WipeDevice_fields[1] = { PB_LAST_FIELD }; @@ -317,6 +328,31 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; +const pb_field_t EthereumSignTx_fields[9] = { + PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumSignTx, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, nonce, address_n, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_price, nonce, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_limit, gas_price, 0), + PB_FIELD2( 5, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, to, gas_limit, 0), + PB_FIELD2( 6, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, value, to, 0), + PB_FIELD2( 7, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, data_initial_chunk, value, 0), + PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxRequest_fields[5] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, EthereumTxRequest, data_length, data_length, 0), + PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_v, data_length, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_r, signature_v, 0), + PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_s, signature_r, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumTxAck_fields[2] = { + PB_FIELD2( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EthereumTxAck, data_chunk, data_chunk, 0), + PB_LAST_FIELD +}; + const pb_field_t SignIdentity_fields[5] = { PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), @@ -332,6 +368,18 @@ const pb_field_t SignedIdentity_fields[4] = { PB_LAST_FIELD }; +const pb_field_t GetECDHSessionKey_fields[4] = { + PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, GetECDHSessionKey, identity, identity, &IdentityType_fields), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, GetECDHSessionKey, peer_public_key, identity, 0), + PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, GetECDHSessionKey, ecdsa_curve_name, peer_public_key, 0), + PB_LAST_FIELD +}; + +const pb_field_t ECDHSessionKey_fields[2] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, ECDHSessionKey, session_key, session_key, 0), + PB_LAST_FIELD +}; + const pb_field_t FirmwareErase_fields[1] = { PB_LAST_FIELD }; @@ -385,7 +433,7 @@ const pb_field_t DebugLinkLog_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_Address_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_SignIdentity_SignedIdentity_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index f4cd33ff1a..f0ec555ee4 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -61,6 +61,13 @@ typedef enum _MessageType { MessageType_MessageType_SignIdentity = 53, MessageType_MessageType_SignedIdentity = 54, MessageType_MessageType_GetFeatures = 55, + MessageType_MessageType_EthereumGetAddress = 56, + MessageType_MessageType_EthereumAddress = 57, + MessageType_MessageType_EthereumSignTx = 58, + MessageType_MessageType_EthereumTxRequest = 59, + MessageType_MessageType_EthereumTxAck = 60, + MessageType_MessageType_GetECDHSessionKey = 61, + MessageType_MessageType_ECDHSessionKey = 62, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, @@ -270,6 +277,16 @@ typedef struct _DecryptedMessage { char address[36]; } DecryptedMessage; +typedef struct { + size_t size; + uint8_t bytes[65]; +} ECDHSessionKey_session_key_t; + +typedef struct _ECDHSessionKey { + bool has_session_key; + ECDHSessionKey_session_key_t session_key; +} ECDHSessionKey; + typedef struct { size_t size; uint8_t bytes[33]; @@ -343,6 +360,41 @@ typedef struct _EstimateTxSize { char coin_name[17]; } EstimateTxSize; +typedef struct _EthereumAddress { + pb_callback_t address; +} EthereumAddress; + +typedef struct _EthereumGetAddress { + pb_callback_t address_n; + bool has_show_display; + bool show_display; +} EthereumGetAddress; + +typedef struct _EthereumSignTx { + pb_callback_t address_n; + pb_callback_t nonce; + pb_callback_t gas_price; + pb_callback_t gas_limit; + pb_callback_t to; + pb_callback_t value; + pb_callback_t data_initial_chunk; + bool has_data_length; + uint32_t data_length; +} EthereumSignTx; + +typedef struct _EthereumTxAck { + pb_callback_t data_chunk; +} EthereumTxAck; + +typedef struct _EthereumTxRequest { + bool has_data_length; + uint32_t data_length; + bool has_signature_v; + uint32_t signature_v; + pb_callback_t signature_r; + pb_callback_t signature_s; +} EthereumTxRequest; + typedef struct _Failure { bool has_code; FailureType code; @@ -417,6 +469,20 @@ typedef struct _GetAddress { MultisigRedeemScriptType multisig; } GetAddress; +typedef struct { + size_t size; + uint8_t bytes[65]; +} GetECDHSessionKey_peer_public_key_t; + +typedef struct _GetECDHSessionKey { + bool has_identity; + IdentityType identity; + bool has_peer_public_key; + GetECDHSessionKey_peer_public_key_t peer_public_key; + bool has_ecdsa_curve_name; + char ecdsa_curve_name[32]; +} GetECDHSessionKey; + typedef struct _GetEntropy { uint32_t size; } GetEntropy; @@ -681,7 +747,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_default {HDNodeType_init_default, false, ""} #define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} +#define EthereumGetAddress_init_default {{{NULL}, NULL}, false, 0} #define Address_init_default {""} +#define EthereumAddress_init_default {{{NULL}, NULL}} #define WipeDevice_init_default {0} #define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} #define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, ""} @@ -705,8 +773,13 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} +#define EthereumSignTx_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EthereumTxRequest_init_default {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_default {{{NULL}, NULL}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} +#define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} +#define ECDHSessionKey_init_default {false, {0, {0}}} #define FirmwareErase_init_default {0} #define FirmwareUpload_init_default {{0, {0}}} #define DebugLinkDecision_init_default {0} @@ -735,7 +808,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} #define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} +#define EthereumGetAddress_init_zero {{{NULL}, NULL}, false, 0} #define Address_init_zero {""} +#define EthereumAddress_init_zero {{{NULL}, NULL}} #define WipeDevice_init_zero {0} #define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0} #define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, ""} @@ -759,8 +834,13 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} +#define EthereumSignTx_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0} +#define EthereumTxRequest_init_zero {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}} +#define EthereumTxAck_init_zero {{{NULL}, NULL}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} +#define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} +#define ECDHSessionKey_init_zero {false, {0, {0}}} #define FirmwareErase_init_zero {0} #define FirmwareUpload_init_zero {{0, {0}}} #define DebugLinkDecision_init_zero {0} @@ -806,6 +886,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DecryptMessage_hmac_tag 4 #define DecryptedMessage_message_tag 1 #define DecryptedMessage_address_tag 2 +#define ECDHSessionKey_session_key_tag 1 #define EncryptMessage_pubkey_tag 1 #define EncryptMessage_message_tag 2 #define EncryptMessage_display_only_tag 3 @@ -819,6 +900,22 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define EstimateTxSize_outputs_count_tag 1 #define EstimateTxSize_inputs_count_tag 2 #define EstimateTxSize_coin_name_tag 3 +#define EthereumAddress_address_tag 1 +#define EthereumGetAddress_address_n_tag 1 +#define EthereumGetAddress_show_display_tag 2 +#define EthereumSignTx_address_n_tag 1 +#define EthereumSignTx_nonce_tag 2 +#define EthereumSignTx_gas_price_tag 3 +#define EthereumSignTx_gas_limit_tag 4 +#define EthereumSignTx_to_tag 5 +#define EthereumSignTx_value_tag 6 +#define EthereumSignTx_data_initial_chunk_tag 7 +#define EthereumSignTx_data_length_tag 8 +#define EthereumTxAck_data_chunk_tag 1 +#define EthereumTxRequest_data_length_tag 1 +#define EthereumTxRequest_signature_v_tag 2 +#define EthereumTxRequest_signature_r_tag 3 +#define EthereumTxRequest_signature_s_tag 4 #define Failure_code_tag 1 #define Failure_message_tag 2 #define Features_vendor_tag 1 @@ -843,6 +940,9 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 #define GetAddress_multisig_tag 4 +#define GetECDHSessionKey_identity_tag 1 +#define GetECDHSessionKey_peer_public_key_tag 2 +#define GetECDHSessionKey_ecdsa_curve_name_tag 3 #define GetEntropy_size_tag 1 #define GetPublicKey_address_n_tag 1 #define GetPublicKey_ecdsa_curve_name_tag 2 @@ -932,7 +1032,9 @@ extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[4]; extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[5]; +extern const pb_field_t EthereumGetAddress_fields[3]; extern const pb_field_t Address_fields[2]; +extern const pb_field_t EthereumAddress_fields[2]; extern const pb_field_t WipeDevice_fields[1]; extern const pb_field_t LoadDevice_fields[8]; extern const pb_field_t ResetDevice_fields[7]; @@ -956,8 +1058,13 @@ extern const pb_field_t SignTx_fields[6]; extern const pb_field_t SimpleSignTx_fields[7]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; +extern const pb_field_t EthereumSignTx_fields[9]; +extern const pb_field_t EthereumTxRequest_fields[5]; +extern const pb_field_t EthereumTxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; extern const pb_field_t SignedIdentity_fields[4]; +extern const pb_field_t GetECDHSessionKey_fields[4]; +extern const pb_field_t ECDHSessionKey_fields[2]; extern const pb_field_t FirmwareErase_fields[1]; extern const pb_field_t FirmwareUpload_fields[2]; extern const pb_field_t DebugLinkDecision_fields[2]; @@ -1014,6 +1121,8 @@ extern const pb_field_t DebugLinkLog_fields[4]; #define TxAck_size (6 + TransactionType_size) #define SignIdentity_size (558 + IdentityType_size) #define SignedIdentity_size 140 +#define GetECDHSessionKey_size (107 + IdentityType_size) +#define ECDHSessionKey_size 67 #define FirmwareErase_size 0 #define FirmwareUpload_size 2 #define DebugLinkDecision_size 2 diff --git a/vendor/trezor-common b/vendor/trezor-common index 36a574056d..e6295a33cd 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 36a574056deacad8943f1412c3db149750f8b163 +Subproject commit e6295a33cda4f0541311c9098569531c2d84220b From caafefc0fbb8955786d9c84b8fdfb47d5e081535 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 12 Jun 2016 21:25:35 +0200 Subject: [PATCH 0262/1154] Tweaked timeouts, handle null nodes. --- firmware/u2f.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index cb05370c70..76eb80f511 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -216,12 +216,13 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { cid = 0; reader = 0; usbTiny(0); + layoutHome(); return; } usbPoll(); } } - + // We have all the data switch (reader->cmd) { case 0: @@ -244,21 +245,20 @@ void u2fhid_read_start(const U2FHID_FRAME *f) { // wait for next commmand/ button press reader->cmd = 0; reader->seq = 255; - uint8_t bs = 0; - while (dialog_timeout && bs == 0 && reader->cmd == 0) { + while (dialog_timeout > 0 && reader->cmd == 0) { dialog_timeout--; usbPoll(); // may trigger new request buttonUpdate(); if (button.YesUp && (last_req_state == AUTH || last_req_state == REG)) { last_req_state++; + // standard requires to remember button press for 10 seconds. + dialog_timeout = 10 * U2F_TIMEOUT; } } if (reader->cmd == 0) { - if (dialog_timeout == 0) { - last_req_state = INIT; - } + last_req_state = INIT; cid = 0; reader = 0; usbTiny(0); @@ -283,7 +283,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) return send_u2fhid_error(cid, ERR_INVALID_LEN); if (dialog_timeout > 0) - dialog_timeout = 10*U2F_TIMEOUT; + dialog_timeout = U2F_TIMEOUT; U2FHID_FRAME f; MEMSET_BZERO(&f, sizeof(f)); @@ -496,6 +496,8 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) // prepare keypair from /random data const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) + return NULL; // For second half of keyhandle // Signature of app_id and random data @@ -516,6 +518,8 @@ const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle memcpy(&key_path[1], key_handle, KEY_PATH_LEN); const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) + return NULL; uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; memcpy(&keybase[0], app_id, U2F_APPID_SIZE); @@ -539,6 +543,11 @@ void u2f_register(const APDU *a) static U2F_REGISTER_REQ last_req; const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; + if (!storage_isInitialized()) { + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } + // Validate basic request parameters debugLog(0, "", "u2f register"); if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { @@ -570,7 +579,7 @@ void u2f_register(const APDU *a) if (last_req_state == REG) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = 10*U2F_TIMEOUT; + dialog_timeout = U2F_TIMEOUT; return; } @@ -639,6 +648,11 @@ void u2f_authenticate(const APDU *a) const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; static U2F_AUTHENTICATE_REQ last_req; + if (!storage_isInitialized()) { + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } + if (APDU_LEN(*a) < 64) { /// FIXME: decent value debugLog(0, "", "u2f authenticate - badlen"); send_u2f_error(U2F_SW_WRONG_LENGTH); @@ -697,7 +711,7 @@ void u2f_authenticate(const APDU *a) if (last_req_state == AUTH) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = 10*U2F_TIMEOUT; + dialog_timeout = U2F_TIMEOUT; return; } From 080dcf462ff4fb2818b663db29b5e525e0eda9a5 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 23 May 2016 21:23:50 +0100 Subject: [PATCH 0263/1154] Define field size limits for the Ethereum protocol --- firmware/protob/messages.options | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index f13b1c740d..ee9b474ba3 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -34,6 +34,9 @@ GetAddress.coin_name max_size:17 Address.address max_size:36 +EthereumGetAddress.address_n max_count:8 +EthereumAddress.address max_size:20 + LoadDevice.mnemonic max_size:241 LoadDevice.pin max_size:10 LoadDevice.language max_size:17 @@ -89,6 +92,19 @@ EstimateTxSize.coin_name max_size:17 SignTx.coin_name max_size:17 +EthereumSignTx.address_n max_count:8 +EthereumSignTx.nonce max_size:32 +EthereumSignTx.gas_price max_size:32 +EthereumSignTx.gas_limit max_size:32 +EthereumSignTx.to max_size:20 +EthereumSignTx.value max_size:32 +EthereumSignTx.data_initial_chunk max_size:1024 + +EthereumTxRequest.signature_r max_size:32 +EthereumTxRequest.signature_s max_size:32 + +EthereumTxAck.data_chunk max_size:1024 + SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 SignIdentity.ecdsa_curve_name max_size:32 From 57197e146346d1c99539f1fdf9d051426bf4976d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 12 Jun 2016 23:10:52 +0200 Subject: [PATCH 0264/1154] use macros for usb interface numbers --- firmware/usb.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 90b3c241ce..55dc1348c2 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -28,7 +28,9 @@ #include "storage.h" #include "util.h" +#define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK +#define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_U2F 2 #else #define USB_INTERFACE_INDEX_U2F 1 @@ -175,7 +177,7 @@ static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ static const struct usb_interface_descriptor hid_iface[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_HID, @@ -238,7 +240,7 @@ static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ static const struct usb_interface_descriptor hid_iface_debug[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 1, + .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_HID, @@ -304,21 +306,17 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin } #if DEBUG_LINK - if (req->wIndex == 1) { + if (req->wIndex == USB_INTERFACE_INDEX_DEBUG) { debugLog(0, "", "hid_control_request debug"); *buf = (uint8_t *)hid_report_descriptor_debug; *len = sizeof(hid_report_descriptor_debug); - } else { - debugLog(0, "", "hid_control_request trezor"); - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); } return 1; -#else - debugLog(0, "", "hid_control_request trezor"); +#endif + + debugLog(0, "", "hid_control_request main"); *buf = (uint8_t *)hid_report_descriptor; *len = sizeof(hid_report_descriptor); -#endif return 1; } From 120cfc148f0cadc23819fb20444b8de24e1c625a Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 12 Jun 2016 23:39:28 +0200 Subject: [PATCH 0265/1154] new message SetU2FCounter --- firmware/fsm.c | 6 ++++++ firmware/fsm.h | 1 + firmware/messages.c | 1 + firmware/protob/messages.pb.c | 7 ++++++- firmware/protob/messages.pb.h | 11 +++++++++++ firmware/storage.c | 7 +++++++ firmware/storage.h | 1 + vendor/trezor-common | 2 +- 8 files changed, 34 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b7c6e5025a..2ca2f514ec 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -924,6 +924,12 @@ void fsm_msgWordAck(WordAck *msg) recovery_word(msg->word); } +void fsm_msgSetU2FCounter(SetU2FCounter *msg) +{ + storage_setU2FCounter(msg->u2f_counter); + fsm_sendSuccess("U2F counter set"); +} + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm.h b/firmware/fsm.h index 5b6eef971e..a106b39a96 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -57,6 +57,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg); void fsm_msgEstimateTxSize(EstimateTxSize *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); void fsm_msgWordAck(WordAck *msg); +void fsm_msgSetU2FCounter(SetU2FCounter *msg); // debug message functions #if DEBUG_LINK diff --git a/firmware/messages.c b/firmware/messages.c index 57c311151d..a12911a84c 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -71,6 +71,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, {'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *))fsm_msgWordAck}, + {'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *))fsm_msgSetU2FCounter}, // out messages {'n', 'o', MessageType_MessageType_Success, Success_fields, 0}, {'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0}, diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 4abfcc07f7..c72e3073c3 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -380,6 +380,11 @@ const pb_field_t ECDHSessionKey_fields[2] = { PB_LAST_FIELD }; +const pb_field_t SetU2FCounter_fields[2] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, SetU2FCounter, u2f_counter, u2f_counter, 0), + PB_LAST_FIELD +}; + const pb_field_t FirmwareErase_fields[1] = { PB_LAST_FIELD }; @@ -456,7 +461,7 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index d0f6eb68c5..2b814ba8fe 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -68,6 +68,7 @@ typedef enum _MessageType { MessageType_MessageType_EthereumTxAck = 60, MessageType_MessageType_GetECDHSessionKey = 61, MessageType_MessageType_ECDHSessionKey = 62, + MessageType_MessageType_SetU2FCounter = 63, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, @@ -686,6 +687,11 @@ typedef struct _ResetDevice { char label[33]; } ResetDevice; +typedef struct _SetU2FCounter { + bool has_u2f_counter; + uint32_t u2f_counter; +} SetU2FCounter; + typedef struct { size_t size; uint8_t bytes[256]; @@ -881,6 +887,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} #define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} #define ECDHSessionKey_init_default {false, {0, {0}}} +#define SetU2FCounter_init_default {false, 0} #define FirmwareErase_init_default {0} #define FirmwareUpload_init_default {{0, {0}}} #define DebugLinkDecision_init_default {0} @@ -946,6 +953,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} #define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} #define ECDHSessionKey_init_zero {false, {0, {0}}} +#define SetU2FCounter_init_zero {false, 0} #define FirmwareErase_init_zero {0} #define FirmwareUpload_init_zero {{0, {0}}} #define DebugLinkDecision_init_zero {0} @@ -1093,6 +1101,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ResetDevice_pin_protection_tag 4 #define ResetDevice_language_tag 5 #define ResetDevice_label_tag 6 +#define SetU2FCounter_u2f_counter_tag 1 #define SignIdentity_identity_tag 1 #define SignIdentity_challenge_hidden_tag 2 #define SignIdentity_challenge_visual_tag 3 @@ -1181,6 +1190,7 @@ extern const pb_field_t SignIdentity_fields[5]; extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t GetECDHSessionKey_fields[4]; extern const pb_field_t ECDHSessionKey_fields[2]; +extern const pb_field_t SetU2FCounter_fields[2]; extern const pb_field_t FirmwareErase_fields[1]; extern const pb_field_t FirmwareUpload_fields[2]; extern const pb_field_t DebugLinkDecision_fields[2]; @@ -1248,6 +1258,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define SignedIdentity_size 140 #define GetECDHSessionKey_size (107 + IdentityType_size) #define ECDHSessionKey_size 67 +#define SetU2FCounter_size 6 #define FirmwareErase_size 0 #define FirmwareUpload_size 2 #define DebugLinkDecision_size 2 diff --git a/firmware/storage.c b/firmware/storage.c index f1a21196aa..519443ac38 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -559,3 +559,10 @@ uint32_t storage_nextU2FCounter(void) storage_check_flash_errors(); return storage.u2f_counter + storage_u2f_offset; } + +void storage_setU2FCounter(uint32_t u2fcounter) +{ + storage.has_u2f_counter = true; + storage.u2f_counter = u2fcounter - storage_u2f_offset; + storage_commit(); +} diff --git a/firmware/storage.h b/firmware/storage.h index ed5a674ab3..b3680a2bb4 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -62,6 +62,7 @@ bool storage_increasePinFails(uint32_t *pinfailptr); uint32_t *storage_getPinFailsPtr(void); uint32_t storage_nextU2FCounter(void); +void storage_setU2FCounter(uint32_t u2fcounter); bool storage_isInitialized(void); diff --git a/vendor/trezor-common b/vendor/trezor-common index 70d8ac8f85..203d95b913 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 70d8ac8f85f16a0a16019749402f26dcc635d841 +Subproject commit 203d95b913903debbaab3333ea2416a7c37e0b95 From f07556f0dbba148c1e8258fb7c156056caa3a116 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 13 Jun 2016 00:31:59 +0200 Subject: [PATCH 0266/1154] update common submodule --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 203d95b913..603d3c18e1 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 203d95b913903debbaab3333ea2416a7c37e0b95 +Subproject commit 603d3c18e1a90d0825b2ef2093c5e8b1540c1f0a From c86086e2b90e0a2e547d661766e05585d2cf54f5 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 16 Jun 2016 22:40:21 +0300 Subject: [PATCH 0267/1154] Add ECDH support --- firmware/fsm.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ firmware/fsm.h | 1 + firmware/messages.c | 2 ++ 3 files changed, 51 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 2ca2f514ec..21f698236d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -775,6 +775,54 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutHome(); } +void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) +{ + RESP_INIT(ECDHSessionKey); + + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + + // TODO: consider adding appropriate UI for manual confirmation? + + if (!protectPin(true)) { + layoutHome(); + return; + } + + uint8_t hash[32]; + if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); + layoutHome(); + return; + } + + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 17; + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); + + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + + const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); + if (!node) return; + + if (cryptoGetECDHSessionKey(node, msg->peer_public_key.bytes, resp->session_key.bytes) == 0) { + resp->has_session_key = true; + resp->session_key.size = 65; + msg_write(MessageType_MessageType_ECDHSessionKey, resp); + } else { + fsm_sendFailure(FailureType_Failure_Other, "Error getting ECDH session key"); + } + layoutHome(); +} + /* ECIES disabled void fsm_msgEncryptMessage(EncryptMessage *msg) { diff --git a/firmware/fsm.h b/firmware/fsm.h index a106b39a96..b361ad79de 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -51,6 +51,7 @@ void fsm_msgEntropyAck(EntropyAck *msg); void fsm_msgSignMessage(SignMessage *msg); void fsm_msgVerifyMessage(VerifyMessage *msg); void fsm_msgSignIdentity(SignIdentity *msg); +void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg); void fsm_msgEncryptMessage(EncryptMessage *msg); void fsm_msgDecryptMessage(DecryptMessage *msg); //void fsm_msgPassphraseAck(PassphraseAck *msg); diff --git a/firmware/messages.c b/firmware/messages.c index a12911a84c..ee323b82e5 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -63,6 +63,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, {'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity}, {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, + {'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *))fsm_msgGetECDHSessionKey}, /* ECIES disabled {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, @@ -86,6 +87,7 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, {'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0}, + {'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0}, /* ECIES disabled {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, From 1abc0b23d2c132cf186868e3a165ae347930bc1f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 20 Jun 2016 19:35:09 +0200 Subject: [PATCH 0268/1154] update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 23590c05c6..16f477787d 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 23590c05c652efccdfb7e837a048adbecab5b145 +Subproject commit 16f477787d7e59a37e0f05807182cef8aeb1e2d5 From c6309ff93cfa8a12daeda07205aee3b063995759 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 23 Jun 2016 19:09:24 +0200 Subject: [PATCH 0269/1154] no UI for ECDHSessionKey for now (just ask for PIN) --- firmware/fsm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 21f698236d..01049df982 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -784,8 +784,6 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) return; } - // TODO: consider adding appropriate UI for manual confirmation? - if (!protectPin(true)) { layoutHome(); return; From 97466519b0c5c3bfff395d642d5e13e43610d944 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 26 Jun 2016 21:46:59 +0200 Subject: [PATCH 0270/1154] Bitbucket U2F support --- firmware/u2f_knownapps.h | 11 ++++++++++- gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_bitbucket.png | Bin 0 -> 292 bytes 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 gen/bitmaps/u2f_bitbucket.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 947594012c..396db66154 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -30,7 +30,7 @@ typedef struct { const BITMAP *appicon; } U2FWellKnown; -static const U2FWellKnown u2f_well_known[4] = { +static const U2FWellKnown u2f_well_known[] = { { // https://www.gstatic.com/securitykey/origins.json { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, @@ -66,6 +66,15 @@ static const U2FWellKnown u2f_well_known[4] = { 0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 }, "Slush Pool", &bmp_u2f_slushpool + }, + { + // https://bitbucket.org + { 0x12,0x74,0x3b,0x92,0x12,0x97,0xb7,0x7f, + 0x11,0x35,0xe4,0x1f,0xde,0xdd,0x4a,0x84, + 0x6a,0xfe,0x82,0xe1,0xf3,0x69,0x32,0xa9, + 0x91,0x2f,0x3b,0x0d,0x8d,0xfb,0x7d,0x0e }, + "Bitbucket", + &bmp_u2f_bitbucket } }; diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 264064dc8c..2d78497aa3 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -23,6 +23,7 @@ const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x81, 0x80, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x7e, 0x08, 0x00, 0x00, 0x21, 0x81, 0x84, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x22, 0x00, 0x00, 0x48, 0x00, 0x12, 0x00, 0x00, 0x88, 0x00, 0x11, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x03, 0x9f, 0xff, 0xf9, 0xc0, 0x04, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x3f, 0xff, 0xfc, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x60, 0x00, 0x06, 0x10, 0x08, 0x1c, 0x00, 0x38, 0x10, 0x08, 0x03, 0x81, 0xc0, 0x10, 0x07, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; @@ -51,6 +52,7 @@ const BITMAP bmp_logo48 = {40, 48, bmp_logo48_data}; const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data}; const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; +const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index 9c3db2bff2..099943ce46 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -31,6 +31,7 @@ extern const BITMAP bmp_logo48; extern const BITMAP bmp_logo48_empty; extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; +extern const BITMAP bmp_u2f_bitbucket; extern const BITMAP bmp_u2f_dropbox; extern const BITMAP bmp_u2f_github; extern const BITMAP bmp_u2f_google; diff --git a/gen/bitmaps/u2f_bitbucket.png b/gen/bitmaps/u2f_bitbucket.png new file mode 100644 index 0000000000000000000000000000000000000000..895f1399056fd7bb7fb60b6822395639e1c7bb97 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W*pj^6T^Rm@;DWu&Cj&(|3p^r= z85p>QL70(Y)*K0-AbW|YuPgflHYs5t%iyPC-9Vv@o-U3d9>?E?dGZ}l;1D_Vf4`4^ zZq(^@$ChZOCnO}eWGpk>{FZ^C&)FzLde;`ND7$zs@SJOL;vKO}gS!2b5|gef&9}CSSluku iwlOE5y8DrnCBw)0nZ}crbj1K2&*16m=d#Wzp$Pyje{vuI literal 0 HcmV?d00001 From ae4dff6e5fae248b3b75d6c86fd8da7098aba837 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 26 Jun 2016 16:27:29 +0200 Subject: [PATCH 0271/1154] Only compute pubkey on demand. Changed all hdnode callers to call hdnode_fill_public_key if they need the public key. --- firmware/crypto.c | 8 +++---- firmware/crypto.h | 6 +++--- firmware/fsm.c | 47 ++++++++++++++++++++++++++++++------------ firmware/signing.c | 1 + firmware/storage.c | 2 +- firmware/transaction.c | 2 +- vendor/trezor-crypto | 2 +- 7 files changed, 45 insertions(+), 23 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index b9cd878146..45e96c822c 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -85,13 +85,13 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 8; } -int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes return hdnode_sign(node, message, message_len, signature + 1, NULL); } -int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { // GPG should sign a SHA256 digest of the original message. if (message_len != 32) { @@ -120,7 +120,7 @@ int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, return 0; } -int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -294,7 +294,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { return 0; } layoutProgressUpdate(true); diff --git a/firmware/crypto.h b/firmware/crypto.h index 8425046360..e6d3c00faf 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -33,14 +33,14 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); -int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); -int cryptoMessageSign(const CoinType *coin, const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 01049df982..70525c17aa 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -94,7 +94,7 @@ const CoinType *fsm_getCoin(const char *name) return coin; } -const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) +HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) { static HDNode node; if (!storage_getRootNode(&node, curve, true)) { @@ -298,8 +298,21 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } - const HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count); - if (!node) return; + uint32_t fpr; + HDNode *node; + if (msg->address_n_count == 0) { + /* get master node */ + fpr = 0; + node = fsm_getDerivedNode(curve, msg->address_n, 0); + } else { + /* get parent node */ + node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count - 1); + if (!node) return; + fpr = hdnode_fingerprint(node); + /* get child */ + hdnode_private_ckd(node, msg->address_n[msg->address_n_count - 1]); + } + hdnode_fill_public_key(node); if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); @@ -311,7 +324,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) } resp->node.depth = node->depth; - resp->node.fingerprint = node->fingerprint; + resp->node.fingerprint = fpr; resp->node.child_num = node->child_num; resp->node.chain_code.size = 32; memcpy(resp->node.chain_code.bytes, node->chain_code, 32); @@ -319,8 +332,12 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } resp->has_xpub = true; - hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); + hdnode_serialize_public(node, fpr, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } @@ -561,8 +578,9 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; + hdnode_fill_public_key(node); if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); @@ -641,14 +659,14 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe("Signing", 0); if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; - ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); + hdnode_get_address_raw(node, coin->address_type, addr_raw); base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; @@ -735,7 +753,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } - const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); + HDNode *node = fsm_getDerivedNode(curve, address_n, 5); if (!node) return; bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); @@ -755,17 +773,22 @@ void fsm_msgSignIdentity(SignIdentity *msg) } if (result == 0) { + hdnode_fill_public_key(node); if (strcmp(curve, SECP256K1_NAME) != 0) { resp->has_address = false; } else { resp->has_address = true; uint8_t addr_raw[21]; - ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type + hdnode_get_address_raw(node, 0x00, addr_raw); // hardcoded Bitcoin address type base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); } resp->has_public_key = true; resp->public_key.size = 33; memcpy(resp->public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->public_key.bytes[0] = 0; + } resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); @@ -859,9 +882,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) } node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; - uint8_t public_key[33]; - ecdsa_get_public_key33(&secp256k1, node->private_key, public_key); - ecdsa_get_address_raw(public_key, coin->address_type, address_raw); + hdnode_get_address_raw(node, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { diff --git a/firmware/signing.c b/firmware/signing.c index cfc28d6984..e78eec628b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -471,6 +471,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + hdnode_fill_public_key(&node); if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { if (!tx->inputs[0].has_multisig) { fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); diff --git a/firmware/storage.c b/firmware/storage.c index 519443ac38..2cc9204ae5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -361,7 +361,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) if (!protectPassphrase()) { return false; } - if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { + if (hdnode_from_xprv(storage.node.depth, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { return false; } if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 45b70da2d0..6b0ec88e6c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -71,7 +71,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 0; } layoutProgressUpdate(true); - ecdsa_get_address_raw(node.public_key, coin->address_type, addr_raw); + hdnode_get_address_raw(&node, coin->address_type, addr_raw); } else if (in->has_address) { // address provided -> regular output if (needs_confirm) { diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 16f477787d..3390fcf89e 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 16f477787d7e59a37e0f05807182cef8aeb1e2d5 +Subproject commit 3390fcf89e5502d6087a8b0d182fc9db05bbd759 From fdbae0b0e0e9519c5eec5a2d05a91f59fe18c86c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Jun 2016 14:04:11 +0200 Subject: [PATCH 0272/1154] fix hid_control_request for debug link --- firmware/usb.c | 2 +- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 55dc1348c2..4224761c71 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -310,8 +310,8 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin debugLog(0, "", "hid_control_request debug"); *buf = (uint8_t *)hid_report_descriptor_debug; *len = sizeof(hid_report_descriptor_debug); + return 1; } - return 1; #endif debugLog(0, "", "hid_control_request main"); diff --git a/vendor/trezor-common b/vendor/trezor-common index 603d3c18e1..4c2b12b0c5 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 603d3c18e1a90d0825b2ef2093c5e8b1540c1f0a +Subproject commit 4c2b12b0c51e293fe08f04554cdd55a081250653 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 16f477787d..d61a151900 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 16f477787d7e59a37e0f05807182cef8aeb1e2d5 +Subproject commit d61a151900a08022f2243808fd28b8b076979d3e From 3ce756b6923d2a8c8784879c60ce0b31364c2c64 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 3 Jul 2016 13:53:20 +0200 Subject: [PATCH 0273/1154] add set -e to shell scripts --- bootloader-docker-build.sh | 2 ++ firmware-docker-build.sh | 2 ++ firmware-fingerprint.sh | 1 + firmware/u2f/genkeys.sh | 9 +++++---- 4 files changed, 10 insertions(+), 4 deletions(-) mode change 100644 => 100755 firmware/u2f/genkeys.sh diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index 636a095aa0..d25e7e0234 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -1,4 +1,6 @@ #!/bin/bash +set -e + IMAGETAG=trezor-mcu-build FIRMWARETAG=${1:-master} diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index cd95ac5b7e..2b32c6c7b5 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -1,4 +1,6 @@ #!/bin/bash +set -e + IMAGETAG=trezor-mcu-build FIRMWARETAG=${1:-master} diff --git a/firmware-fingerprint.sh b/firmware-fingerprint.sh index 0157467ccf..3e48bcdb08 100755 --- a/firmware-fingerprint.sh +++ b/firmware-fingerprint.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e if [ -z "$1" ]; then echo "Please provide filename as argument" diff --git a/firmware/u2f/genkeys.sh b/firmware/u2f/genkeys.sh old mode 100644 new mode 100755 index 3bc7e5b10b..33371d5be9 --- a/firmware/u2f/genkeys.sh +++ b/firmware/u2f/genkeys.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e cat > u2f_keys.h <) { + perl -e '$key = "\t"; while (<>) { if (/priv:/) { $priv = 1 } elsif (/pub:/) { $priv = 0 } elsif ($priv) { while ($_ =~ s/.*?([0-9a-f]{2})//) { - $key .= "0x$1,"; - if ($num++ % 8 == 7) { $key .= "\n\t"; } + $key .= "0x$1,"; + if ($num++ % 8 == 7) { $key .= "\n\t"; } else {$key .= " ";} } } @@ -32,7 +33,7 @@ cat >> u2f_keys.h <> u2f_keys.h From 633024a9933c2f6b672ac6ec3e7e69c384ec90be Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 15:02:24 +0200 Subject: [PATCH 0274/1154] send failure when reset workflow is aborted (this sends features when it was aborted by initialize message) --- firmware/reset.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/reset.c b/firmware/reset.c index 7b2fa72232..b6b337fcf5 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -143,6 +143,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { storage_reset(); layoutHome(); + fsm_sendFailure(FailureType_Failure_Other, "Reset device aborted"); return; } } From 40ca2c9210f7422389bcc840501288e2b4e6d60a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 15:44:47 +0200 Subject: [PATCH 0275/1154] add gitlab to u2f_knownapps --- firmware/u2f_knownapps.h | 49 ++++++++++++++++++++++--------------- gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_gitlab.png | Bin 0 -> 229 bytes 4 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 gen/bitmaps/u2f_gitlab.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 396db66154..8612270289 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -33,48 +33,57 @@ typedef struct { static const U2FWellKnown u2f_well_known[] = { { // https://www.gstatic.com/securitykey/origins.json - { 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95, - 0xe1,0x51,0xed,0x8d,0x4d,0x3c,0x76,0x7a, - 0x6c,0xc3,0x49,0x43,0x59,0x43,0x79,0x4e, - 0x88,0x4f,0x3d,0x02,0x3a,0x82,0x29,0xfd }, + { 0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, + 0xe1, 0x51, 0xed, 0x8d, 0x4d, 0x3c, 0x76, 0x7a, + 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, 0x79, 0x4e, + 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd }, "Google", &bmp_u2f_google }, { // https://github.com/u2f/trusted_facets - { 0x70,0x61,0x7d,0xfe,0xd0,0x65,0x86,0x3a, - 0xf4,0x7c,0x15,0x55,0x6c,0x91,0x79,0x88, - 0x80,0x82,0x8c,0xc4,0x07,0xfd,0xf7,0x0a, - 0xe8,0x50,0x11,0x56,0x94,0x65,0xa0,0x75 }, + { 0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, + 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, + 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, + 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 }, "Github", &bmp_u2f_github }, { // https://www.dropbox.com/u2f-app-id.json - { 0xc5,0x0f,0x8a,0x7b,0x70,0x8e,0x92,0xf8, - 0x2e,0x7a,0x50,0xe2,0xbd,0xc5,0x5d,0x8f, - 0xd9,0x1a,0x22,0xfe,0x6b,0x29,0xc0,0xcd, - 0xf7,0x80,0x55,0x30,0x84,0x2a,0xf5,0x81 }, + { 0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, + 0x2e, 0x7a, 0x50, 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, + 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, 0xc0, 0xcd, + 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81 }, "Dropbox", &bmp_u2f_dropbox }, { // https://slushpool.com/static/security/u2f.json - { 0x08,0xb2,0xa3,0xd4,0x19,0x39,0xaa,0x31, - 0x66,0x84,0x93,0xcb,0x36,0xcd,0xcc,0x4f, - 0x16,0xc4,0xd9,0xb4,0xc8,0x23,0x8b,0x73, - 0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 }, + { 0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, + 0x66, 0x84, 0x93, 0xcb, 0x36, 0xcd, 0xcc, 0x4f, + 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, 0x8b, 0x73, + 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97 }, "Slush Pool", &bmp_u2f_slushpool }, { // https://bitbucket.org - { 0x12,0x74,0x3b,0x92,0x12,0x97,0xb7,0x7f, - 0x11,0x35,0xe4,0x1f,0xde,0xdd,0x4a,0x84, - 0x6a,0xfe,0x82,0xe1,0xf3,0x69,0x32,0xa9, - 0x91,0x2f,0x3b,0x0d,0x8d,0xfb,0x7d,0x0e }, + { 0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, + 0x11, 0x35, 0xe4, 0x1f, 0xde, 0xdd, 0x4a, 0x84, + 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, 0x32, 0xa9, + 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e }, "Bitbucket", &bmp_u2f_bitbucket + }, + { + // https://gitlab.com + { 0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, + 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, + 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, + 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, + "Gitlab", + &bmp_u2f_gitlab } }; diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 2d78497aa3..13faa549e9 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -26,6 +26,7 @@ const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -55,5 +56,6 @@ const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; +const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index 099943ce46..e109fd637d 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -34,6 +34,7 @@ extern const BITMAP bmp_logo64_empty; extern const BITMAP bmp_u2f_bitbucket; extern const BITMAP bmp_u2f_dropbox; extern const BITMAP bmp_u2f_github; +extern const BITMAP bmp_u2f_gitlab; extern const BITMAP bmp_u2f_google; extern const BITMAP bmp_u2f_slushpool; diff --git a/gen/bitmaps/u2f_gitlab.png b/gen/bitmaps/u2f_gitlab.png new file mode 100644 index 0000000000000000000000000000000000000000..65c594905b9a776f42f18b1962bdb15f0187a273 GIT binary patch literal 229 zcmV^P)lnh~P}IH05!RFv&zDRA?A|5Q)ueRRzisWGR74`S(Y# z!g@vUB-acQ%h~TC7$%^}<-uU}SFXSjd7<10Ryns6^mhSEh5lR30cNg6(EbUtNwmVz zFJuP4D3CF9?uvwUy&mh|2>%E@0;RuOGDMYdLURs0< flZlRTA&9gS9LG;4emS$N00000NkvXXu0mjfu5n@$ literal 0 HcmV?d00001 From 79e4d4d8c2cfc84d3ad5591510935fdf55cfc5bc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 16:58:57 +0200 Subject: [PATCH 0276/1154] fix uppercase letters in GitHub/GitLab --- firmware/u2f_knownapps.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 8612270289..4b49046440 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -46,7 +46,7 @@ static const U2FWellKnown u2f_well_known[] = { 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 }, - "Github", + "GitHub", &bmp_u2f_github }, { @@ -82,7 +82,7 @@ static const U2FWellKnown u2f_well_known[] = { 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, - "Gitlab", + "GitLab", &bmp_u2f_gitlab } }; From b95f7857013d554c147ae56762c8abc31f4475d7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Jul 2016 19:03:27 +0200 Subject: [PATCH 0277/1154] update readme to reflect new mytrezor location --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fc7ae64fc5..e198cd421e 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,10 @@ This creates file `output/bootloader.bin` and prints its fingerprint and size at ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? -1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json -2. Download it: `wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex` -3. `xxd -r -p trezor.signed.bin.hex trezor.signed.bin` -4. `./firmware-fingerprint.sh trezor.signed.bin` +1. Pick version of firmware binary listed on https://wallet.mytrezor.com/data/firmware/releases.json +2. Download it: `wget -O trezor.signed.bin https://wallet.mytrezor.com/data/firmware/trezor-1.3.6.bin` +3. `./firmware-fingerprint.sh trezor.signed.bin` -Step 4 should produce the same sha256 fingerprint like your local build (for the same version tag). +Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). The reasoning for `firmware-fingerprint.sh` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. From 7d8cb9018e567d5d1f6d45cf86c570efab449fbd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 14 Jul 2016 18:11:20 +0200 Subject: [PATCH 0278/1154] Ask for confirmation on ECDH Session (gpg decrypt) Also fix abort to send a reply (a cancel failure) --- firmware/fsm.c | 8 ++++++++ firmware/layout2.c | 42 ++++++++++++++++++++++++++++++++++++++++++ firmware/layout2.h | 1 + 3 files changed, 51 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 428371abfe..ea7b1c3142 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -424,6 +424,7 @@ void fsm_msgCancel(Cancel *msg) (void)msg; recovery_abort(); signing_abort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); } void fsm_msgTxAck(TxAck *msg) @@ -807,6 +808,13 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) return; } + layoutDecryptIdentity(&msg->identity); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "ECDH Session cancelled"); + layoutHome(); + return; + } + if (!protectPin(true)) { layoutHome(); return; diff --git a/firmware/layout2.c b/firmware/layout2.c index 4c0a3a3cae..fdb3626923 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -336,6 +336,48 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) NULL); } +void layoutDecryptIdentity(const IdentityType *identity) +{ + char row_proto[8 + 11 + 1]; + char row_hostport[64 + 6 + 1]; + char row_user[64 + 8 + 1]; + + if (identity->has_proto && identity->proto[0]) { + strlcpy(row_proto, identity->proto, sizeof(row_proto)); + char *p = row_proto; + while (*p) { *p = toupper((int)*p); p++; } + strlcat(row_proto, " decrypt for:", sizeof(row_proto)); + } else { + strlcpy(row_proto, "Decrypt for:", sizeof(row_proto)); + } + + if (identity->has_host && identity->host[0]) { + strlcpy(row_hostport, identity->host, sizeof(row_hostport)); + if (identity->has_port && identity->port[0]) { + strlcat(row_hostport, ":", sizeof(row_hostport)); + strlcat(row_hostport, identity->port, sizeof(row_hostport)); + } + } else { + row_hostport[0] = 0; + } + + if (identity->has_user && identity->user[0]) { + strlcpy(row_user, "user: ", sizeof(row_user)); + strlcat(row_user, identity->user, sizeof(row_user)); + } else { + row_user[0] = 0; + } + + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", + "Do you want to decrypt?", + row_proto[0] ? row_proto : NULL, + row_hostport[0] ? row_hostport : NULL, + row_user[0] ? row_user : NULL, + NULL, + NULL, + NULL); +} + void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon) { if (!appicon) { appicon = &bmp_icon_question; diff --git a/firmware/layout2.h b/firmware/layout2.h index 975d530bc2..237207cb44 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -41,6 +41,7 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) void layoutAddress(const char *address, const char *desc); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); +void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); #endif From 1dfca212f1e9f83b1bf4a1f45930814ac2f49c22 Mon Sep 17 00:00:00 2001 From: Holger Schinzel Date: Sat, 23 Jul 2016 10:06:19 +0200 Subject: [PATCH 0279/1154] add python-ecdsa dependency --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a7eb16ca8a..dfb48d277f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ RUN apt-get update # install build tools and dependencies -RUN apt-get install -y build-essential git python gcc-arm-none-eabi +RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi From bf465357ee682ba307158e6d671f50948c47c4be Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 23 May 2016 21:27:18 +0100 Subject: [PATCH 0280/1154] Include placeholder handlers for the Ethereum protocol --- firmware/Makefile | 1 + firmware/fsm.c | 19 +++++++++++++++++++ firmware/fsm.h | 3 +++ firmware/messages.c | 5 +++++ 4 files changed, 28 insertions(+) diff --git a/firmware/Makefile b/firmware/Makefile index 36fc371b9d..6d134cd24f 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -59,3 +59,4 @@ CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DED25519_CUSTOMRANDOM=1 CFLAGS += -DED25519_CUSTOMHASH=1 +CFLAGS += -DUSE_ETHEREUM=1 diff --git a/firmware/fsm.c b/firmware/fsm.c index ea7b1c3142..f5ee14ade5 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -419,6 +419,19 @@ void fsm_msgSignTx(SignTx *msg) signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); } + +void fsm_msgEthereumSignTx(EthereumSignTx *msg) +{ + (void)msg; + fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); +} + +void fsm_msgEthereumTxAck(EthereumTxAck *msg) +{ + (void)msg; + fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); +} + void fsm_msgCancel(Cancel *msg) { (void)msg; @@ -628,6 +641,12 @@ void fsm_msgGetAddress(GetAddress *msg) layoutHome(); } +void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) +{ + (void)msg; + fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); +} + void fsm_msgEntropyAck(EntropyAck *msg) { if (msg->has_entropy) { diff --git a/firmware/fsm.h b/firmware/fsm.h index b361ad79de..085c236381 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -59,6 +59,9 @@ void fsm_msgEstimateTxSize(EstimateTxSize *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); void fsm_msgWordAck(WordAck *msg); void fsm_msgSetU2FCounter(SetU2FCounter *msg); +void fsm_msgEthereumGetAddress(EthereumGetAddress *msg); +void fsm_msgEthereumSignTx(EthereumSignTx *msg); +void fsm_msgEthereumTxAck(EthereumTxAck *msg); // debug message functions #if DEBUG_LINK diff --git a/firmware/messages.c b/firmware/messages.c index ee323b82e5..9981bc2b12 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -73,6 +73,9 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, {'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *))fsm_msgWordAck}, {'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *))fsm_msgSetU2FCounter}, + {'n', 'i', MessageType_MessageType_EthereumGetAddress, EthereumGetAddress_fields, (void (*)(void *))fsm_msgEthereumGetAddress}, + {'n', 'i', MessageType_MessageType_EthereumSignTx, EthereumSignTx_fields, (void (*)(void *))fsm_msgEthereumSignTx}, + {'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *))fsm_msgEthereumTxAck}, // out messages {'n', 'o', MessageType_MessageType_Success, Success_fields, 0}, {'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0}, @@ -95,6 +98,8 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, + {'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0}, + {'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0}, #if DEBUG_LINK // debug in messages // {'d', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *))fsm_msgDebugLinkDecision}, From 3c2d9111e21d55d8d5d73fe9b0ac3da47e4bb773 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 23 May 2016 21:28:33 +0100 Subject: [PATCH 0281/1154] Implement EthereumGetAddress --- firmware/fsm.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index f5ee14ade5..9bbfa0c303 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -643,8 +643,44 @@ void fsm_msgGetAddress(GetAddress *msg) void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) { - (void)msg; - fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); + RESP_INIT(EthereumAddress); + + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + resp->address.size = 20; + + if (!ecdsa_get_ethereum_pubkeyhash(node->public_key, resp->address.bytes)) return; + + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, "Address:", sizeof(desc)); + + char address[43]; + address[0] = '0'; + address[1] = 'x'; + data2hex(resp->address.bytes, 20, address + 2); + + layoutAddress(address, desc); + if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + layoutHome(); + return; + } + } + + msg_write(MessageType_MessageType_Address, resp); + layoutHome(); } void fsm_msgEntropyAck(EntropyAck *msg) From 352d296f773db6b58bd186d1c082f61788240868 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Tue, 24 May 2016 20:31:25 +0100 Subject: [PATCH 0282/1154] Return the correct MessageType from EthereumGetAddress --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9bbfa0c303..3640fbfac3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -679,7 +679,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) } } - msg_write(MessageType_MessageType_Address, resp); + msg_write(MessageType_MessageType_EthereumAddress, resp); layoutHome(); } From a031b79e2485460bbff4b5714407abd2743ecd3f Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Tue, 24 May 2016 20:31:34 +0100 Subject: [PATCH 0283/1154] Add sha3.o to OBJS --- firmware/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/Makefile b/firmware/Makefile index 6d134cd24f..dbb7a4658d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -34,6 +34,7 @@ OBJS += ../vendor/trezor-crypto/base58.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/sha3.o OBJS += ../vendor/trezor-crypto/aescrypt.o OBJS += ../vendor/trezor-crypto/aeskey.o From 9c7e41f15bbce502d2596b351c66d9b8fae2d9e5 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 24 May 2016 22:14:10 +0100 Subject: [PATCH 0284/1154] Reorder fsm.c for logical grouping of signing methods --- firmware/fsm.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 3640fbfac3..3ab2304374 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -419,6 +419,22 @@ void fsm_msgSignTx(SignTx *msg) signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); } +void fsm_msgTxAck(TxAck *msg) +{ + if (msg->has_tx) { + signing_txack(&(msg->tx)); + } else { + fsm_sendFailure(FailureType_Failure_SyntaxError, "No transaction provided"); + } +} + +void fsm_msgCancel(Cancel *msg) +{ + (void)msg; + recovery_abort(); + signing_abort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); +} void fsm_msgEthereumSignTx(EthereumSignTx *msg) { @@ -432,23 +448,6 @@ void fsm_msgEthereumTxAck(EthereumTxAck *msg) fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); } -void fsm_msgCancel(Cancel *msg) -{ - (void)msg; - recovery_abort(); - signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); -} - -void fsm_msgTxAck(TxAck *msg) -{ - if (msg->has_tx) { - signing_txack(&(msg->tx)); - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No transaction provided"); - } -} - void fsm_msgCipherKeyValue(CipherKeyValue *msg) { if (!storage_isInitialized()) { From a9449520b8f6c0dc17157f71580f92f8b9f8a5ab Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 24 May 2016 22:22:30 +0100 Subject: [PATCH 0285/1154] Ethereum signing skeleton --- firmware/Makefile | 1 + firmware/ethereum.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ firmware/ethereum.h | 32 ++++++++++++++++++++++++ firmware/fsm.c | 21 +++++++++++++--- 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 firmware/ethereum.c create mode 100644 firmware/ethereum.h diff --git a/firmware/Makefile b/firmware/Makefile index dbb7a4658d..845d3c02cf 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -17,6 +17,7 @@ OBJS += recovery.o OBJS += reset.o OBJS += signing.o OBJS += crypto.o +OBJS += ethereum.o OBJS += debug.o diff --git a/firmware/ethereum.c b/firmware/ethereum.c new file mode 100644 index 0000000000..f9653bbb7e --- /dev/null +++ b/firmware/ethereum.c @@ -0,0 +1,61 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Alex Beregszaszi + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "ethereum.h" +#include "fsm.h" +#include "layout2.h" +#include "messages.h" +#include "transaction.h" +#include "ecdsa.h" +#include "protect.h" +#include "crypto.h" +#include "secp256k1.h" +#include "sha3.h" + +static bool signing = false; + +void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) +{ + (void)node; + + signing = true; + + fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); +} + +void ethereum_signing_txack(EthereumTxAck *tx) +{ + (void)tx; + + if (!signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); + layoutHome(); + return; + } + + fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); +} + +void ethereum_signing_abort(void) +{ + if (signing) { + layoutHome(); + signing = false; + } +} diff --git a/firmware/ethereum.h b/firmware/ethereum.h new file mode 100644 index 0000000000..8c55d2db58 --- /dev/null +++ b/firmware/ethereum.h @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Alex Beregszaszi + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __ETHEREUM_H__ +#define __ETHEREUM_H__ + +#include +#include +#include "bip32.h" +#include "messages.pb.h" + +void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); +void ethereum_signing_abort(void); +void ethereum_signing_txack(EthereumTxAck *msg); + +#endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 3ab2304374..b2e3ef7dc2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -47,6 +47,7 @@ #include "curves.h" #include "secp256k1.h" #include +#include "ethereum.h" // message methods @@ -433,19 +434,31 @@ void fsm_msgCancel(Cancel *msg) (void)msg; recovery_abort(); signing_abort(); + ethereum_signing_abort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); } void fsm_msgEthereumSignTx(EthereumSignTx *msg) { - (void)msg; - fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); + if (!storage_isInitialized()) { + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); + return; + } + + if (!protectPin(true)) { + layoutHome(); + return; + } + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + ethereum_signing_init(msg, node); } void fsm_msgEthereumTxAck(EthereumTxAck *msg) { - (void)msg; - fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); + ethereum_signing_txack(msg); } void fsm_msgCipherKeyValue(CipherKeyValue *msg) From 1d2f9b6ecd9c9782a5fcdab87d21bb24f9f5a402 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 00:38:32 +0100 Subject: [PATCH 0286/1154] Initial signing implementation for Ethereum --- firmware/ethereum.c | 217 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 6 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index f9653bbb7e..24c42a736c 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -29,32 +29,237 @@ #include "sha3.h" static bool signing = false; +static size_t data_left; +static EthereumTxRequest resp; +static uint8_t hash[32], sig[64], privkey[32]; +// FIXME: this is currently 400 bytes. Could be probably improved. +struct SHA3_CTX keccak_ctx; + +/* + * Encode length according to RLP. + * FIXME: improve + */ +static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte, bool list) +{ + if (!list && (length == 1 && firstbyte <= 0x7f)) { + buf[0] = firstbyte; + return 1; + } else if (length <= 55) { + buf[0] = (list ? 0xc0 : 0x80) + length; + return 1; + } else if (length <= 0xff) { + buf[0] = (list ? 0xf7 : 0xb7) + 1; + buf[1] = length; + return 2; + } else if (length <= 0xffff) { + buf[0] = (list ? 0xf7 : 0xb7) + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + return 3; + } else { + buf[0] = (list ? 0xf7 : 0xb7) + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + return 4; + } +} + +/* + * Calculate the number of bytes needed for an RLP length header. + * NOTE: supports up to 16MB of data (how unlikely...) + * FIXME: improve + */ +static int rlp_calculate_length(int length, uint8_t firstbyte) { + if (length == 1 && firstbyte <= 0x7f) { + return 1; + } else if (length <= 55) { + return 2; + } else if (length <= 0xff) { + return 2; + } else if (length <= 0xffff) { + return 3; + } else + return 4; +} + +static inline void hash_data(const uint8_t *buf, size_t size) +{ + sha3_Update(&keccak_ctx, buf, size); +} + +/* + * Push an RLP encoded length to the hash buffer. + */ +static void hash_rlp_length(int length, uint8_t firstbyte) +{ + uint8_t buf[4]; + size_t size = rlp_encode_length(buf, length, firstbyte, false); + hash_data(buf, size); +} + +/* + * Push an RLP encoded list length to the hash buffer. + */ +static void hash_rlp_list_length(int length) +{ + uint8_t buf[4]; + size_t size = rlp_encode_length(buf, length, 0, true); + hash_data(buf, size); +} + +/* + * Push an RLP encoded length field and data to the hash buffer. + */ +static void hash_rlp_field(const uint8_t *buf, size_t size) +{ + hash_rlp_length(size, buf[0]); + /* FIXME: this special case should be handled more nicely */ + if (!(size == 1 && buf[0] <= 0x7f)) + hash_data(buf, size); +} + +static void send_request_chunk(size_t length) +{ + resp.data_length = length <= 1024 ? length : 1024; + msg_write(MessageType_MessageType_EthereumTxRequest, &resp); +} + +/* + * RLP fields: + * - nonce (0 .. 32) + * - gas_price (0 .. 32) + * - gas_limit (0 .. 32) + * - to (0, 20) + * - value (0 .. 32) + * - data (0 ..) + */ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) { - (void)node; - signing = true; + sha3_256_Init(&keccak_ctx); - fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); + memset(&resp, 0, sizeof(EthereumTxRequest)); + /* NOTE: in the first stage we'll always request more data */ + resp.has_data_length = true; + + /* Stage 1: Calculate total RLP length */ + int total_rlp_length = 0; + + if (msg->has_nonce) + total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); + else + total_rlp_length++; + + if (msg->has_gas_price) + total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); + else + total_rlp_length++; + + if (msg->has_gas_limit) + total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); + else + total_rlp_length++; + + if (msg->has_to) + total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); + else + total_rlp_length++; + + if (msg->has_value) + total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); + else + total_rlp_length++; + + if (msg->has_data_initial_chunk) { + if (msg->has_data_length) + total_rlp_length += rlp_calculate_length(msg->data_initial_chunk.size + msg->data_length, msg->data_initial_chunk.bytes[0]); + else + total_rlp_length += rlp_calculate_length(msg->data_initial_chunk.size, msg->data_initial_chunk.bytes[0]); + } else + total_rlp_length++; + + /* Stage 2: Store header fields */ + hash_rlp_list_length(total_rlp_length); + + if (msg->has_nonce) + hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + if (msg->has_gas_price) + hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + if (msg->has_gas_limit) + hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); + if (msg->has_to) + hash_rlp_field(msg->to.bytes, msg->to.size); + if (msg->has_value) + hash_rlp_field(msg->value.bytes, msg->value.size); + if (msg->has_data_initial_chunk) + hash_rlp_field(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); + + /* FIXME: probably this shouldn't be done here, but at a later stage */ + memcpy(privkey, node->private_key, 32); + + if (msg->has_data_length && msg->data_length > 0) { + data_left = msg->data_length; + send_request_chunk(msg->data_length); + } } void ethereum_signing_txack(EthereumTxAck *tx) { - (void)tx; - if (!signing) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); layoutHome(); return; } - fsm_sendFailure(FailureType_Failure_Other, "Unsupported feature"); + if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { + fsm_sendFailure(FailureType_Failure_Other, "Empty data chunk received"); + ethereum_signing_abort(); + return; + } + + hash_data(tx->data_chunk.bytes, tx->data_chunk.size); + + data_left -= tx->data_chunk.size; + + if (data_left > 0) { + /* Request more data */ + send_request_chunk(data_left); + } else { + /* Create signature */ + keccak_Final(&keccak_ctx, hash); + uint8_t v; + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + ethereum_signing_abort(); + return; + } + + memset(privkey, 0, sizeof(privkey)); + + /* Send back the result */ + resp.has_data_length = false; + + resp.has_signature_v = true; + resp.signature_v = v + 27; + + resp.has_signature_r = true; + resp.signature_r.size = 32; + memcpy(resp.signature_r.bytes, sig, 32); + + resp.has_signature_s = true; + resp.signature_s.size = 32; + memcpy(resp.signature_s.bytes, sig + 32, 32); + + msg_write(MessageType_MessageType_EthereumTxRequest, &resp); + } } void ethereum_signing_abort(void) { if (signing) { + memset(privkey, 0, sizeof(privkey)); layoutHome(); signing = false; } From 2b6c99117999ace8742716b1c4459a0547d97701 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 02:41:10 +0100 Subject: [PATCH 0287/1154] Split out send_signature and support short requests --- firmware/ethereum.c | 98 ++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 27 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 24c42a736c..ab3416f6fd 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -125,6 +125,37 @@ static void send_request_chunk(size_t length) msg_write(MessageType_MessageType_EthereumTxRequest, &resp); } +static void send_signature(void) +{ + keccak_Final(&keccak_ctx, hash); + uint8_t v; + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + ethereum_signing_abort(); + return; + } + + memset(privkey, 0, sizeof(privkey)); + + /* Send back the result */ + resp.has_data_length = false; + + resp.has_signature_v = true; + resp.signature_v = v + 27; + + resp.has_signature_r = true; + resp.signature_r.size = 32; + memcpy(resp.signature_r.bytes, sig, 32); + + resp.has_signature_s = true; + resp.signature_s.size = 32; + memcpy(resp.signature_s.bytes, sig + 32, 32); + + msg_write(MessageType_MessageType_EthereumTxRequest, &resp); + + ethereum_signing_abort(); +} + /* * RLP fields: * - nonce (0 .. 32) @@ -147,31 +178,43 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* Stage 1: Calculate total RLP length */ int total_rlp_length = 0; + layoutProgress("Signing Eth", 1); + if (msg->has_nonce) total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); else total_rlp_length++; + layoutProgress("Signing Eth", 2); + if (msg->has_gas_price) total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); else total_rlp_length++; + layoutProgress("Signing Eth", 3); + if (msg->has_gas_limit) total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); else total_rlp_length++; + layoutProgress("Signing Eth", 4); + if (msg->has_to) total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); else total_rlp_length++; + layoutProgress("Signing Eth", 5); + if (msg->has_value) total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); else total_rlp_length++; + layoutProgress("Signing Eth", 6); + if (msg->has_data_initial_chunk) { if (msg->has_data_length) total_rlp_length += rlp_calculate_length(msg->data_initial_chunk.size + msg->data_length, msg->data_initial_chunk.bytes[0]); @@ -180,28 +223,55 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } else total_rlp_length++; + layoutProgress("Signing Eth", 7); + /* Stage 2: Store header fields */ hash_rlp_list_length(total_rlp_length); + layoutProgress("Signing Eth", 8); + if (msg->has_nonce) hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + else + hash_rlp_length(1, 0); + if (msg->has_gas_price) hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + else + hash_rlp_length(1, 0); + if (msg->has_gas_limit) hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); + else + hash_rlp_length(1, 0); + if (msg->has_to) hash_rlp_field(msg->to.bytes, msg->to.size); + else + hash_rlp_length(1, 0); + if (msg->has_value) hash_rlp_field(msg->value.bytes, msg->value.size); + else + hash_rlp_length(1, 0); + if (msg->has_data_initial_chunk) hash_rlp_field(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); + else + hash_rlp_length(1, 0); + + layoutProgress("Signing Eth", 9); /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); if (msg->has_data_length && msg->data_length > 0) { + layoutProgress("Signing Eth", 20); data_left = msg->data_length; send_request_chunk(msg->data_length); + } else { + layoutProgress("Signing Eth", 50); + send_signature(); } } @@ -224,35 +294,9 @@ void ethereum_signing_txack(EthereumTxAck *tx) data_left -= tx->data_chunk.size; if (data_left > 0) { - /* Request more data */ send_request_chunk(data_left); } else { - /* Create signature */ - keccak_Final(&keccak_ctx, hash); - uint8_t v; - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); - ethereum_signing_abort(); - return; - } - - memset(privkey, 0, sizeof(privkey)); - - /* Send back the result */ - resp.has_data_length = false; - - resp.has_signature_v = true; - resp.signature_v = v + 27; - - resp.has_signature_r = true; - resp.signature_r.size = 32; - memcpy(resp.signature_r.bytes, sig, 32); - - resp.has_signature_s = true; - resp.signature_s.size = 32; - memcpy(resp.signature_s.bytes, sig + 32, 32); - - msg_write(MessageType_MessageType_EthereumTxRequest, &resp); + send_signature(); } } From e0395b13eb922614d253423d838e7097c1b4c9bc Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 09:28:53 +0100 Subject: [PATCH 0288/1154] Fix RLP length calculation --- firmware/ethereum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index ab3416f6fd..32d5672ead 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -74,13 +74,13 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) { if (length == 1 && firstbyte <= 0x7f) { return 1; } else if (length <= 55) { - return 2; + return 1 + length; } else if (length <= 0xff) { - return 2; + return 2 + length; } else if (length <= 0xffff) { - return 3; + return 3 + length; } else - return 4; + return 4 + length; } static inline void hash_data(const uint8_t *buf, size_t size) From ab49a7cb45bcaabf836c683063c17ecf831866a0 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 15:32:52 +0100 Subject: [PATCH 0289/1154] Calculate data length based on the initial chunk and the supplied length --- firmware/ethereum.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 32d5672ead..337138a17e 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -177,6 +177,12 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* Stage 1: Calculate total RLP length */ int total_rlp_length = 0; + int total_data_length = 0; + + if (msg->has_data_initial_chunk) + total_data_length += msg->data_initial_chunk.size; + if (msg->has_data_length) + total_data_length += msg->data_length; layoutProgress("Signing Eth", 1); @@ -215,12 +221,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing Eth", 6); - if (msg->has_data_initial_chunk) { - if (msg->has_data_length) - total_rlp_length += rlp_calculate_length(msg->data_initial_chunk.size + msg->data_length, msg->data_initial_chunk.bytes[0]); - else - total_rlp_length += rlp_calculate_length(msg->data_initial_chunk.size, msg->data_initial_chunk.bytes[0]); - } else + if (msg->has_data_initial_chunk) + total_rlp_length += rlp_calculate_length(total_data_length, msg->data_initial_chunk.bytes[0]); + else total_rlp_length++; layoutProgress("Signing Eth", 7); @@ -255,9 +258,10 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) else hash_rlp_length(1, 0); - if (msg->has_data_initial_chunk) - hash_rlp_field(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - else + if (msg->has_data_initial_chunk) { + hash_rlp_length(total_data_length, msg->data_initial_chunk.bytes[0]); + hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); + } else hash_rlp_length(1, 0); layoutProgress("Signing Eth", 9); From e0a174300378cfd6e85aca3ed6a324189eaa9e34 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 15:33:12 +0100 Subject: [PATCH 0290/1154] Add sanity checks for data fields in EthereumSignTx --- firmware/ethereum.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 337138a17e..840a5e0076 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -175,6 +175,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* NOTE: in the first stage we'll always request more data */ resp.has_data_length = true; + /* FIXME: simplify this check */ + if (msg->has_data_initial_chunk) { + if (msg->has_data_length && msg->data_initial_chunk.size != 1024) { + fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but initial chunk too small"); + ethereum_signing_abort(); + return; + } + } else if (msg->has_data_length) { + fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); + ethereum_signing_abort(); + return; + } + /* Stage 1: Calculate total RLP length */ int total_rlp_length = 0; int total_data_length = 0; From a617200c9c45a1726348b08e765201de4e20ae74 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 15:33:23 +0100 Subject: [PATCH 0291/1154] Add confirmation dialog to EthereumSignTx --- firmware/ethereum.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 840a5e0076..4a25b38f44 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -27,6 +27,7 @@ #include "crypto.h" #include "secp256k1.h" #include "sha3.h" +#include "util.h" static bool signing = false; static size_t data_left; @@ -156,6 +157,30 @@ static void send_signature(void) ethereum_signing_abort(); } +/* FIXME */ +static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value) +{ + static char _value[21] = {0}; + static char _to1[21] = {0}; + static char _to2[21] = {0}; + + data2hex(value, 10, _value); + data2hex(to, 10, _to1); + data2hex(to + 10, 10, _to2); + + layoutDialogSwipe(DIALOG_ICON_QUESTION, + "Cancel", + "Confirm", + NULL, + "Really send", + _value, + "from your wallet?", + "To:", + _to1, + _to2 + ); +} + /* * RLP fields: * - nonce (0 .. 32) @@ -188,6 +213,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) return; } + /* FIXME: include default values (0 / 0) */ + layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + /* Stage 1: Calculate total RLP length */ int total_rlp_length = 0; int total_data_length = 0; From 78b1370de99c11bf378b9fb74ce54906b8d0e55a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 15:39:11 +0100 Subject: [PATCH 0292/1154] More input sanity checks in EthereumSignTx --- firmware/ethereum.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 4a25b38f44..5dd03542d1 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -202,10 +202,17 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* FIXME: simplify this check */ if (msg->has_data_initial_chunk) { - if (msg->has_data_length && msg->data_initial_chunk.size != 1024) { - fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but initial chunk too small"); - ethereum_signing_abort(); - return; + if (msg->has_data_length) { + if (msg->data_initial_chunk.size != 1024) { + fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but initial chunk too small"); + ethereum_signing_abort(); + return; + } + if (msg->data_length == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided"); + ethereum_signing_abort(); + return; + } } } else if (msg->has_data_length) { fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); From 079d282541e97c6c28ceb776d59e69fe362859f8 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 15:40:23 +0100 Subject: [PATCH 0293/1154] Simplify send_request_chunk() --- firmware/ethereum.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 5dd03542d1..5e554c67d1 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -120,9 +120,9 @@ static void hash_rlp_field(const uint8_t *buf, size_t size) hash_data(buf, size); } -static void send_request_chunk(size_t length) +static void send_request_chunk(void) { - resp.data_length = length <= 1024 ? length : 1024; + resp.data_length = data_left <= 1024 ? data_left : 1024; msg_write(MessageType_MessageType_EthereumTxRequest, &resp); } @@ -325,7 +325,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_data_length && msg->data_length > 0) { layoutProgress("Signing Eth", 20); data_left = msg->data_length; - send_request_chunk(msg->data_length); + send_request_chunk(); } else { layoutProgress("Signing Eth", 50); send_signature(); @@ -351,7 +351,7 @@ void ethereum_signing_txack(EthereumTxAck *tx) data_left -= tx->data_chunk.size; if (data_left > 0) { - send_request_chunk(data_left); + send_request_chunk(); } else { send_signature(); } From 7432805b6aae638bf4378e10ee2fb9511ca41800 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 25 May 2016 20:03:13 +0100 Subject: [PATCH 0294/1154] Fix special RLP case for length=1 firstbyte=0 --- firmware/ethereum.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 5e554c67d1..6baf2cbd9c 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -43,7 +43,8 @@ struct SHA3_CTX keccak_ctx; static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte, bool list) { if (!list && (length == 1 && firstbyte <= 0x7f)) { - buf[0] = firstbyte; + /* Extra-special case: null is encoded differently */ + buf[0] = !firstbyte ? 0x80 : firstbyte; return 1; } else if (length <= 55) { buf[0] = (list ? 0xc0 : 0x80) + length; From 4a195ebd86874803a04c31724f4fc037c032d81b Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Thu, 26 May 2016 21:56:31 +0100 Subject: [PATCH 0295/1154] Don't include 0x in address display, so everything fits --- firmware/fsm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b2e3ef7dc2..e72e38a531 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -678,10 +678,8 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) char desc[16]; strlcpy(desc, "Address:", sizeof(desc)); - char address[43]; - address[0] = '0'; - address[1] = 'x'; - data2hex(resp->address.bytes, 20, address + 2); + char address[41]; + data2hex(resp->address.bytes, 20, address); layoutAddress(address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { From 7d9a56e678cfcb035a994a498ffe31002355a94d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Jun 2016 20:44:54 +0200 Subject: [PATCH 0296/1154] fix curly braces in if statements --- firmware/ethereum.c | 70 ++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 6baf2cbd9c..b76a2b17d6 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -81,8 +81,9 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) { return 2 + length; } else if (length <= 0xffff) { return 3 + length; - } else + } else { return 4 + length; + } } static inline void hash_data(const uint8_t *buf, size_t size) @@ -117,8 +118,9 @@ static void hash_rlp_field(const uint8_t *buf, size_t size) { hash_rlp_length(size, buf[0]); /* FIXME: this special case should be handled more nicely */ - if (!(size == 1 && buf[0] <= 0x7f)) + if (!(size == 1 && buf[0] <= 0x7f)) { hash_data(buf, size); + } } static void send_request_chunk(void) @@ -233,52 +235,60 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) int total_rlp_length = 0; int total_data_length = 0; - if (msg->has_data_initial_chunk) + if (msg->has_data_initial_chunk) { total_data_length += msg->data_initial_chunk.size; - if (msg->has_data_length) + } + if (msg->has_data_length) { total_data_length += msg->data_length; + } layoutProgress("Signing Eth", 1); - if (msg->has_nonce) + if (msg->has_nonce) { total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 2); - if (msg->has_gas_price) + if (msg->has_gas_price) { total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 3); - if (msg->has_gas_limit) + if (msg->has_gas_limit) { total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 4); - if (msg->has_to) + if (msg->has_to) { total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 5); - if (msg->has_value) + if (msg->has_value) { total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 6); - if (msg->has_data_initial_chunk) + if (msg->has_data_initial_chunk) { total_rlp_length += rlp_calculate_length(total_data_length, msg->data_initial_chunk.bytes[0]); - else + } else { total_rlp_length++; + } layoutProgress("Signing Eth", 7); @@ -287,36 +297,42 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing Eth", 8); - if (msg->has_nonce) + if (msg->has_nonce) { hash_rlp_field(msg->nonce.bytes, msg->nonce.size); - else + } else { hash_rlp_length(1, 0); + } - if (msg->has_gas_price) + if (msg->has_gas_price) { hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); - else + } else { hash_rlp_length(1, 0); + } - if (msg->has_gas_limit) + if (msg->has_gas_limit) { hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - else + } else { hash_rlp_length(1, 0); + } - if (msg->has_to) + if (msg->has_to) { hash_rlp_field(msg->to.bytes, msg->to.size); - else + } else { hash_rlp_length(1, 0); + } - if (msg->has_value) + if (msg->has_value) { hash_rlp_field(msg->value.bytes, msg->value.size); - else + } else { hash_rlp_length(1, 0); + } if (msg->has_data_initial_chunk) { hash_rlp_length(total_data_length, msg->data_initial_chunk.bytes[0]); hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - } else + } else { hash_rlp_length(1, 0); + } layoutProgress("Signing Eth", 9); From 48008ddd8eeae19005011dc01a3d9bc24c1be244 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Jun 2016 14:03:12 +0200 Subject: [PATCH 0297/1154] implement layoutEthereumConfirmTx --- firmware/ethereum.c | 77 ++++++++++++++++++++++++++++++++++++++++----- firmware/layout2.c | 7 ++++- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index b76a2b17d6..98b1747408 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -160,23 +160,87 @@ static void send_signature(void) ethereum_signing_abort(); } -/* FIXME */ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value) { - static char _value[21] = {0}; + static bignum256 val; + static uint16_t num[26]; + static uint8_t last_used = 0; + if (value) { + bn_read_be(value, &val); + } else { + bn_zero(&val); + } + for (int i = 0; i < 26; i++) { + bn_divmod1000(&val, (uint32_t *)&(num[i])); + if (num[i] > 0) { + last_used = i; + } + } + + static char _value[25] = {0}; + const char *value_ptr = _value; + + if (last_used < 3) { + // value is smaller than 1e9 wei => show value in wei + _value[0] = '0' + (num[2] / 100) % 10; + _value[1] = '0' + (num[2] / 10) % 10; + _value[2] = '0' + (num[2]) % 10; + _value[3] = '0' + (num[1] / 100) % 10; + _value[4] = '0' + (num[1] / 10) % 10; + _value[5] = '0' + (num[1]) % 10; + _value[6] = '0' + (num[0] / 100) % 10; + _value[7] = '0' + (num[0] / 10) % 10; + _value[8] = '0' + (num[0]) % 10; + strlcpy(_value + 9, " wei", sizeof(_value) - 9); + } else if (last_used < 9) { + // value is bigger than 1e9 wei and smaller than 1e9 ETH => show value in ETH + _value[0] = '0' + (num[8] / 100) % 10; + _value[1] = '0' + (num[8] / 10) % 10; + _value[2] = '0' + (num[8]) % 10; + _value[3] = '0' + (num[7] / 100) % 10; + _value[4] = '0' + (num[7] / 10) % 10; + _value[5] = '0' + (num[7]) % 10; + _value[6] = '0' + (num[6] / 100) % 10; + _value[7] = '0' + (num[6] / 10) % 10; + _value[8] = '0' + (num[6]) % 10; + _value[9] = '.'; + _value[10] = '0' + (num[5] / 100) % 10; + _value[11] = '0' + (num[5] / 10) % 10; + _value[12] = '0' + (num[5]) % 10; + _value[13] = '0' + (num[4] / 100) % 10; + _value[14] = '0' + (num[4] / 10) % 10; + _value[15] = '0' + (num[4]) % 10; + _value[16] = '0' + (num[3] / 100) % 10; + _value[17] = '0' + (num[3] / 10) % 10; + _value[18] = '0' + (num[3]) % 10; + strlcpy(_value + 19, " ETH", sizeof(_value) - 19); + } else { + // value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik) + strlcpy(_value, "more than a billion ETH", sizeof(_value)); + } + + value_ptr = _value; + while (*value_ptr == '0') { // skip leading zeroes + value_ptr++; + } + static char _to1[21] = {0}; static char _to2[21] = {0}; - data2hex(value, 10, _value); - data2hex(to, 10, _to1); - data2hex(to + 10, 10, _to2); + if (to) { + data2hex(to, 10, _to1); + data2hex(to + 10, 10, _to2); + } else { + strlcpy(_to1, "no recipient", sizeof(_to1)); + strlcpy(_to2, "", sizeof(_to2)); + } layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Really send", - _value, + value_ptr, "from your wallet?", "To:", _to1, @@ -223,7 +287,6 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) return; } - /* FIXME: include default values (0 / 0) */ layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); diff --git a/firmware/layout2.c b/firmware/layout2.c index fdb3626923..c26d0fcab6 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -261,7 +261,12 @@ void layoutAddress(const char *address, const char *desc) } } - const char **str = split_message((const uint8_t *)address, strlen(address), 9); + uint32_t addrlen = strlen(address); + uint32_t rowlen = addrlen / 4; + if (addrlen % 4) { + rowlen++; + } + const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { oledDrawString(68, 0 * 9, desc); From 3d1ab24d92cca4094b63b8956bdecf61623486bb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Aug 2016 18:37:30 +0200 Subject: [PATCH 0298/1154] simplify ethereum code, EthereumSignTx.data_length is the total length now --- firmware/ethereum.c | 64 ++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 98b1747408..f89a6f9508 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -125,6 +125,7 @@ static void hash_rlp_field(const uint8_t *buf, size_t size) static void send_request_chunk(void) { + resp.has_data_length = true; resp.data_length = data_left <= 1024 ? data_left : 1024; msg_write(MessageType_MessageType_EthereumTxRequest, &resp); } @@ -264,27 +265,23 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) sha3_256_Init(&keccak_ctx); memset(&resp, 0, sizeof(EthereumTxRequest)); - /* NOTE: in the first stage we'll always request more data */ - resp.has_data_length = true; - /* FIXME: simplify this check */ - if (msg->has_data_initial_chunk) { - if (msg->has_data_length) { - if (msg->data_initial_chunk.size != 1024) { - fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but initial chunk too small"); - ethereum_signing_abort(); - return; - } - if (msg->data_length == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided"); - ethereum_signing_abort(); - return; - } + if (msg->has_data_length) { + if (msg->data_length == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided"); + ethereum_signing_abort(); + return; + } + if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); + ethereum_signing_abort(); + return; + } + if (msg->data_initial_chunk.size > msg->data_length) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + ethereum_signing_abort(); + return; } - } else if (msg->has_data_length) { - fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); - ethereum_signing_abort(); - return; } layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL); @@ -298,14 +295,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) int total_rlp_length = 0; int total_data_length = 0; - if (msg->has_data_initial_chunk) { - total_data_length += msg->data_initial_chunk.size; - } if (msg->has_data_length) { - total_data_length += msg->data_length; + total_data_length = msg->data_length; } - layoutProgress("Signing Eth", 1); + layoutProgress("Signing", 1); if (msg->has_nonce) { total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); @@ -313,7 +307,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 2); + layoutProgress("Signing", 2); if (msg->has_gas_price) { total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); @@ -321,7 +315,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 3); + layoutProgress("Signing", 3); if (msg->has_gas_limit) { total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); @@ -329,7 +323,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 4); + layoutProgress("Signing", 4); if (msg->has_to) { total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); @@ -337,7 +331,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 5); + layoutProgress("Signing", 5); if (msg->has_value) { total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); @@ -345,7 +339,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 6); + layoutProgress("Signing", 6); if (msg->has_data_initial_chunk) { total_rlp_length += rlp_calculate_length(total_data_length, msg->data_initial_chunk.bytes[0]); @@ -353,12 +347,12 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) total_rlp_length++; } - layoutProgress("Signing Eth", 7); + layoutProgress("Signing", 7); /* Stage 2: Store header fields */ hash_rlp_list_length(total_rlp_length); - layoutProgress("Signing Eth", 8); + layoutProgress("Signing", 8); if (msg->has_nonce) { hash_rlp_field(msg->nonce.bytes, msg->nonce.size); @@ -397,17 +391,17 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) hash_rlp_length(1, 0); } - layoutProgress("Signing Eth", 9); + layoutProgress("Signing", 9); /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); if (msg->has_data_length && msg->data_length > 0) { - layoutProgress("Signing Eth", 20); - data_left = msg->data_length; + layoutProgress("Signing", 20); + data_left = msg->data_length - msg->data_initial_chunk.size; send_request_chunk(); } else { - layoutProgress("Signing Eth", 50); + layoutProgress("Signing", 50); send_signature(); } } From 3db323c599caca8d284a434b521764429bff118d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Aug 2016 19:15:29 +0200 Subject: [PATCH 0299/1154] fix printing of ethereum value and address --- firmware/ethereum.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index f89a6f9508..9bf34cc88b 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -161,16 +161,19 @@ static void send_signature(void) ethereum_signing_abort(); } -static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value) +static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uint32_t value_len) { - static bignum256 val; - static uint16_t num[26]; - static uint8_t last_used = 0; - if (value) { - bn_read_be(value, &val); + bignum256 val; + if (value && value_len <= 32) { + uint8_t pad_val[32]; + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); } else { bn_zero(&val); } + uint16_t num[26]; + uint8_t last_used = 0; for (int i = 0; i < 26; i++) { bn_divmod1000(&val, (uint32_t *)&(num[i])); if (num[i] > 0) { @@ -221,19 +224,24 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value) } value_ptr = _value; - while (*value_ptr == '0') { // skip leading zeroes + while (*value_ptr == '0' && *(value_ptr + 1) >= '0' && *(value_ptr + 1) <= '9') { // skip leading zeroes value_ptr++; } - static char _to1[21] = {0}; - static char _to2[21] = {0}; + static char _to1[17] = {0}; + static char _to2[17] = {0}; + static char _to3[17] = {0}; if (to) { - data2hex(to, 10, _to1); - data2hex(to + 10, 10, _to2); + strcpy(_to1, "to "); + data2hex(to, 6, _to1 + 3); + data2hex(to + 6, 7, _to2); + data2hex(to + 13, 7, _to3); + _to3[14] = '?'; _to3[15] = 0; } else { - strlcpy(_to1, "no recipient", sizeof(_to1)); + strlcpy(_to1, "to no recipient?", sizeof(_to1)); strlcpy(_to2, "", sizeof(_to2)); + strlcpy(_to3, "", sizeof(_to3)); } layoutDialogSwipe(DIALOG_ICON_QUESTION, @@ -242,10 +250,10 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value) NULL, "Really send", value_ptr, - "from your wallet?", - "To:", _to1, - _to2 + _to2, + _to3, + NULL ); } @@ -284,7 +292,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } } - layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL); + layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); ethereum_signing_abort(); From 1558d77ea020fb2b231f547823ff24ab3f057d97 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Aug 2016 14:06:05 +0200 Subject: [PATCH 0300/1154] split rlp_encode_length into rlp_encode_length and rlp_encode_list_length --- firmware/ethereum.c | 50 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 9bf34cc88b..5b8df6c052 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -38,28 +38,56 @@ struct SHA3_CTX keccak_ctx; /* * Encode length according to RLP. - * FIXME: improve */ -static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte, bool list) +static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte) { - if (!list && (length == 1 && firstbyte <= 0x7f)) { - /* Extra-special case: null is encoded differently */ - buf[0] = !firstbyte ? 0x80 : firstbyte; + if (length == 1 && firstbyte == 0x00) { + // extra-special case: null is encoded differently + buf[0] = 0x80; + return 1; + } else if (length == 1 && firstbyte <= 0x7f) { + buf[0] = firstbyte; return 1; } else if (length <= 55) { - buf[0] = (list ? 0xc0 : 0x80) + length; + buf[0] = 0x80 + length; return 1; } else if (length <= 0xff) { - buf[0] = (list ? 0xf7 : 0xb7) + 1; + buf[0] = 0xb7 + 1; buf[1] = length; return 2; } else if (length <= 0xffff) { - buf[0] = (list ? 0xf7 : 0xb7) + 2; + buf[0] = 0xb7 + 2; buf[1] = length >> 8; buf[2] = length & 0xff; return 3; } else { - buf[0] = (list ? 0xf7 : 0xb7) + 3; + buf[0] = 0xb7 + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + return 4; + } +} + +/* + * Encode list length according to RLP. + */ +static int rlp_encode_list_length(uint8_t *buf, int length) +{ + if (length <= 55) { + buf[0] = 0xc0 + length; + return 1; + } else if (length <= 0xff) { + buf[0] = 0xf7 + 1; + buf[1] = length; + return 2; + } else if (length <= 0xffff) { + buf[0] = 0xf7 + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + return 3; + } else { + buf[0] = 0xf7 + 3; buf[1] = length >> 16; buf[2] = length >> 8; buf[3] = length & 0xff; @@ -97,7 +125,7 @@ static inline void hash_data(const uint8_t *buf, size_t size) static void hash_rlp_length(int length, uint8_t firstbyte) { uint8_t buf[4]; - size_t size = rlp_encode_length(buf, length, firstbyte, false); + size_t size = rlp_encode_length(buf, length, firstbyte); hash_data(buf, size); } @@ -107,7 +135,7 @@ static void hash_rlp_length(int length, uint8_t firstbyte) static void hash_rlp_list_length(int length) { uint8_t buf[4]; - size_t size = rlp_encode_length(buf, length, 0, true); + size_t size = rlp_encode_list_length(buf, length); hash_data(buf, size); } From 4e0a69b6ea4ab69e359561d78b13b8c1fa498ced Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 17 Aug 2016 13:26:54 +0200 Subject: [PATCH 0301/1154] refactor ethereum methods, show progress properly --- firmware/ethereum.c | 176 +++++++++++++++----------------------------- 1 file changed, 58 insertions(+), 118 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 5b8df6c052..b52abc729d 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -2,6 +2,7 @@ * This file is part of the TREZOR project. * * Copyright (C) 2016 Alex Beregszaszi + * Copyright (C) 2016 Pavol Rusnak * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -30,68 +31,85 @@ #include "util.h" static bool signing = false; -static size_t data_left; +static uint32_t data_total, data_left; static EthereumTxRequest resp; static uint8_t hash[32], sig[64], privkey[32]; -// FIXME: this is currently 400 bytes. Could be probably improved. struct SHA3_CTX keccak_ctx; -/* - * Encode length according to RLP. - */ -static int rlp_encode_length(uint8_t *buf, int length, uint8_t firstbyte) +static inline void hash_data(const uint8_t *buf, size_t size) { + sha3_Update(&keccak_ctx, buf, size); +} + +/* + * Push an RLP encoded length to the hash buffer. + */ +static void hash_rlp_length(uint32_t length, uint8_t firstbyte) +{ + uint8_t buf[4]; if (length == 1 && firstbyte == 0x00) { - // extra-special case: null is encoded differently + // special case: null is encoded differently buf[0] = 0x80; - return 1; + hash_data(buf, 1); } else if (length == 1 && firstbyte <= 0x7f) { buf[0] = firstbyte; - return 1; + hash_data(buf, 1); } else if (length <= 55) { buf[0] = 0x80 + length; - return 1; + hash_data(buf, 1); } else if (length <= 0xff) { buf[0] = 0xb7 + 1; buf[1] = length; - return 2; + hash_data(buf, 2); } else if (length <= 0xffff) { buf[0] = 0xb7 + 2; buf[1] = length >> 8; buf[2] = length & 0xff; - return 3; + hash_data(buf, 3); } else { buf[0] = 0xb7 + 3; buf[1] = length >> 16; buf[2] = length >> 8; buf[3] = length & 0xff; - return 4; + hash_data(buf, 4); } } /* - * Encode list length according to RLP. + * Push an RLP encoded list length to the hash buffer. */ -static int rlp_encode_list_length(uint8_t *buf, int length) +static void hash_rlp_list_length(uint32_t length) { + uint8_t buf[4]; if (length <= 55) { buf[0] = 0xc0 + length; - return 1; + hash_data(buf, 1); } else if (length <= 0xff) { buf[0] = 0xf7 + 1; buf[1] = length; - return 2; + hash_data(buf, 2); } else if (length <= 0xffff) { buf[0] = 0xf7 + 2; buf[1] = length >> 8; buf[2] = length & 0xff; - return 3; + hash_data(buf, 3); } else { buf[0] = 0xf7 + 3; buf[1] = length >> 16; buf[2] = length >> 8; buf[3] = length & 0xff; - return 4; + hash_data(buf, 4); + } +} + +/* + * Push an RLP encoded length field and data to the hash buffer. + */ +static void hash_rlp_field(const uint8_t *buf, size_t size) +{ + hash_rlp_length(size, buf[0]); + if (size > 1 || buf[0] >= 0x80) { + hash_data(buf, size); } } @@ -100,7 +118,8 @@ static int rlp_encode_list_length(uint8_t *buf, int length) * NOTE: supports up to 16MB of data (how unlikely...) * FIXME: improve */ -static int rlp_calculate_length(int length, uint8_t firstbyte) { +static int rlp_calculate_length(int length, uint8_t firstbyte) +{ if (length == 1 && firstbyte <= 0x7f) { return 1; } else if (length <= 55) { @@ -114,45 +133,10 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) { } } -static inline void hash_data(const uint8_t *buf, size_t size) -{ - sha3_Update(&keccak_ctx, buf, size); -} - -/* - * Push an RLP encoded length to the hash buffer. - */ -static void hash_rlp_length(int length, uint8_t firstbyte) -{ - uint8_t buf[4]; - size_t size = rlp_encode_length(buf, length, firstbyte); - hash_data(buf, size); -} - -/* - * Push an RLP encoded list length to the hash buffer. - */ -static void hash_rlp_list_length(int length) -{ - uint8_t buf[4]; - size_t size = rlp_encode_list_length(buf, length); - hash_data(buf, size); -} - -/* - * Push an RLP encoded length field and data to the hash buffer. - */ -static void hash_rlp_field(const uint8_t *buf, size_t size) -{ - hash_rlp_length(size, buf[0]); - /* FIXME: this special case should be handled more nicely */ - if (!(size == 1 && buf[0] <= 0x7f)) { - hash_data(buf, size); - } -} static void send_request_chunk(void) { + layoutProgress("Signing", 1000 - 800 * data_left / data_total); resp.has_data_length = true; resp.data_length = data_left <= 1024 ? data_left : 1024; msg_write(MessageType_MessageType_EthereumTxRequest, &resp); @@ -160,6 +144,7 @@ static void send_request_chunk(void) static void send_signature(void) { + layoutProgress("Signing", 1000); keccak_Final(&keccak_ctx, hash); uint8_t v; if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) { @@ -318,6 +303,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) ethereum_signing_abort(); return; } + data_total = msg->data_length; + } else { + data_total = 0; } layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0); @@ -328,67 +316,21 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } /* Stage 1: Calculate total RLP length */ - int total_rlp_length = 0; - int total_data_length = 0; + uint32_t rlp_length = 0; - if (msg->has_data_length) { - total_data_length = msg->data_length; - } + layoutProgress("Signing", 0); - layoutProgress("Signing", 1); - - if (msg->has_nonce) { - total_rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 2); - - if (msg->has_gas_price) { - total_rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 3); - - if (msg->has_gas_limit) { - total_rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 4); - - if (msg->has_to) { - total_rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 5); - - if (msg->has_value) { - total_rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 6); - - if (msg->has_data_initial_chunk) { - total_rlp_length += rlp_calculate_length(total_data_length, msg->data_initial_chunk.bytes[0]); - } else { - total_rlp_length++; - } - - layoutProgress("Signing", 7); + rlp_length += msg->has_nonce ? rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]) : 1; + rlp_length += msg->has_gas_price ? rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]) : 1; + rlp_length += msg->has_gas_limit ? rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]) : 1; + rlp_length += msg->has_to ? rlp_calculate_length(msg->to.size, msg->to.bytes[0]) : 1; + rlp_length += msg->has_value ? rlp_calculate_length(msg->value.size, msg->value.bytes[0]) : 1; + rlp_length += (msg->has_data_length && msg->has_data_initial_chunk) ? rlp_calculate_length(msg->data_length, msg->data_initial_chunk.bytes[0]) : 1; /* Stage 2: Store header fields */ - hash_rlp_list_length(total_rlp_length); + hash_rlp_list_length(rlp_length); - layoutProgress("Signing", 8); + layoutProgress("Signing", 100); if (msg->has_nonce) { hash_rlp_field(msg->nonce.bytes, msg->nonce.size); @@ -420,24 +362,22 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) hash_rlp_length(1, 0); } - if (msg->has_data_initial_chunk) { - hash_rlp_length(total_data_length, msg->data_initial_chunk.bytes[0]); + if (msg->has_data_length && msg->has_data_initial_chunk) { + hash_rlp_length(msg->data_length, msg->data_initial_chunk.bytes[0]); hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); } else { hash_rlp_length(1, 0); } - layoutProgress("Signing", 9); + layoutProgress("Signing", 200); /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); - if (msg->has_data_length && msg->data_length > 0) { - layoutProgress("Signing", 20); + if (msg->has_data_length && msg->data_length > msg->data_initial_chunk.size) { data_left = msg->data_length - msg->data_initial_chunk.size; send_request_chunk(); } else { - layoutProgress("Signing", 50); send_signature(); } } From efd443abe82f10f43930ce6a87e6908781b394ca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 17 Aug 2016 17:18:13 +0200 Subject: [PATCH 0302/1154] implement ethereum signing check --- firmware/ethereum.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index b52abc729d..a023ab325a 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -280,6 +280,31 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uin * - data (0 ..) */ +static bool ethereum_signing_check(EthereumSignTx *msg) +{ + // determine if address == 0 + bool address_zero = msg->has_to; + if (address_zero) { + for (size_t i = 0; i < msg->to.size; i++) { + if (msg->to.bytes[i] > 0) { + address_zero = false; + break; + } + } + } + + // sending value to address 0 + if (address_zero && msg->has_value && msg->value.size) { + return false; + } + // sending transaction to address 0 without a data field + if (address_zero && (!msg->has_data_length || msg->data_length == 0)) { + return false; + } + + return true; +} + void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) { signing = true; @@ -308,6 +333,13 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) data_total = 0; } + // safety checks + if (!ethereum_signing_check(msg)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing aborted (safety check failed)"); + ethereum_signing_abort(); + return; + } + layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); From 22d0e7a05363de73508bb6425e6d623cc8e08dea Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 18 Aug 2016 16:32:51 +0200 Subject: [PATCH 0303/1154] Incorporated changes for updated master --- firmware/ethereum.c | 2 +- firmware/fsm.c | 3 ++- vendor/trezor-crypto | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index a023ab325a..857f2f9a42 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -257,7 +257,7 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uin strlcpy(_to3, "", sizeof(_to3)); } - layoutDialogSwipe(DIALOG_ICON_QUESTION, + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, diff --git a/firmware/fsm.c b/firmware/fsm.c index e72e38a531..c54439b3d4 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -672,7 +672,8 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) resp->address.size = 20; - if (!ecdsa_get_ethereum_pubkeyhash(node->public_key, resp->address.bytes)) return; + if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) + return; if (msg->has_show_display && msg->show_display) { char desc[16]; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 9a8df5a4bb..f4ed55377d 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 9a8df5a4bb5de3b1ebaa28591c2ae0a5bb39348e +Subproject commit f4ed55377d67b48a94c219313faa3035186369cb From 05a73593f68e8424640b6c5fb9a4920d54cd0544 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 19 Aug 2016 22:25:01 +0200 Subject: [PATCH 0304/1154] No special case encoding for '\x0', cleanups The encoding for data '\x00' was tested here: http://testnet.etherscan.io/tx/0x05d6f97de3ecd33ad4059fa9bd342a10ef99d580a2d881b0c5a0c9e8c55ff975 --- firmware/ethereum.c | 59 +++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 857f2f9a42..358ccfc09b 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -3,6 +3,7 @@ * * Copyright (C) 2016 Alex Beregszaszi * Copyright (C) 2016 Pavol Rusnak + * Copyright (C) 2016 Jochen Hoenicke * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -30,7 +31,7 @@ #include "sha3.h" #include "util.h" -static bool signing = false; +static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest resp; static uint8_t hash[32], sig[64], privkey[32]; @@ -47,11 +48,7 @@ static inline void hash_data(const uint8_t *buf, size_t size) static void hash_rlp_length(uint32_t length, uint8_t firstbyte) { uint8_t buf[4]; - if (length == 1 && firstbyte == 0x00) { - // special case: null is encoded differently - buf[0] = 0x80; - hash_data(buf, 1); - } else if (length == 1 && firstbyte <= 0x7f) { + if (length == 1 && firstbyte <= 0x7f) { buf[0] = firstbyte; hash_data(buf, 1); } else if (length <= 55) { @@ -307,7 +304,7 @@ static bool ethereum_signing_check(EthereumSignTx *msg) void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) { - signing = true; + ethereum_signing = true; sha3_256_Init(&keccak_ctx); memset(&resp, 0, sizeof(EthereumTxRequest)); @@ -323,8 +320,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) ethereum_signing_abort(); return; } - if (msg->data_initial_chunk.size > msg->data_length) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + /* Our encoding only supports transactions up to 2^24 bytes. To + * prevent exceeding the limit we use a stricter limit on data length. + */ + if (msg->data_length > 16000000) { + fsm_sendFailure(FailureType_Failure_Other, "Data length exceeds limit"); ethereum_signing_abort(); return; } @@ -332,6 +332,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } else { data_total = 0; } + if (msg->data_initial_chunk.size > data_total) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + ethereum_signing_abort(); + return; + } // safety checks if (!ethereum_signing_check(msg)) { @@ -357,7 +362,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += msg->has_gas_limit ? rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]) : 1; rlp_length += msg->has_to ? rlp_calculate_length(msg->to.size, msg->to.bytes[0]) : 1; rlp_length += msg->has_value ? rlp_calculate_length(msg->value.size, msg->value.bytes[0]) : 1; - rlp_length += (msg->has_data_length && msg->has_data_initial_chunk) ? rlp_calculate_length(msg->data_length, msg->data_initial_chunk.bytes[0]) : 1; + rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); /* Stage 2: Store header fields */ hash_rlp_list_length(rlp_length); @@ -367,47 +372,43 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_nonce) { hash_rlp_field(msg->nonce.bytes, msg->nonce.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_gas_price) { hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_gas_limit) { hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_to) { hash_rlp_field(msg->to.bytes, msg->to.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_value) { hash_rlp_field(msg->value.bytes, msg->value.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } - if (msg->has_data_length && msg->has_data_initial_chunk) { - hash_rlp_length(msg->data_length, msg->data_initial_chunk.bytes[0]); + hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); + if (data_total > 1 || msg->data_initial_chunk.bytes[0] >= 0x80) { hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - } else { - hash_rlp_length(1, 0); } - - layoutProgress("Signing", 200); + data_left = data_total - msg->data_initial_chunk.size; /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); - if (msg->has_data_length && msg->data_length > msg->data_initial_chunk.size) { - data_left = msg->data_length - msg->data_initial_chunk.size; + if (data_left > 0) { send_request_chunk(); } else { send_signature(); @@ -416,12 +417,18 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { - if (!signing) { + if (!ethereum_signing) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); layoutHome(); return; } + if (tx->data_chunk.size > data_left) { + fsm_sendFailure(FailureType_Failure_Other, "Too much data"); + ethereum_signing_abort(); + return; + } + if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { fsm_sendFailure(FailureType_Failure_Other, "Empty data chunk received"); ethereum_signing_abort(); @@ -441,9 +448,9 @@ void ethereum_signing_txack(EthereumTxAck *tx) void ethereum_signing_abort(void) { - if (signing) { + if (ethereum_signing) { memset(privkey, 0, sizeof(privkey)); layoutHome(); - signing = false; + ethereum_signing = false; } } From a37a2e36124e1ab428080bc974886da414922ddb Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 22 Aug 2016 21:58:57 +0200 Subject: [PATCH 0305/1154] Confirm data, streamlining code Set all size fields to 0, if fields was not given to avoid the conditions later. Display data and ask for confirmation. --- firmware/ethereum.c | 125 ++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 358ccfc09b..67cf0e1698 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -133,7 +133,10 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) static void send_request_chunk(void) { - layoutProgress("Signing", 1000 - 800 * data_left / data_total); + int progress = 1000 - (data_total > 1000000 + ? data_left / (data_total/800) + : data_left * 800 / data_total); + layoutProgress("Signing", progress); resp.has_data_length = true; resp.data_length = data_left <= 1024 ? data_left : 1024; msg_write(MessageType_MessageType_EthereumTxRequest, &resp); @@ -171,7 +174,7 @@ static void send_signature(void) ethereum_signing_abort(); } -static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uint32_t value_len) +static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len) { bignum256 val; if (value && value_len <= 32) { @@ -242,14 +245,14 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uin static char _to2[17] = {0}; static char _to3[17] = {0}; - if (to) { + if (to_len) { strcpy(_to1, "to "); data2hex(to, 6, _to1 + 3); data2hex(to + 6, 7, _to2); data2hex(to + 13, 7, _to3); _to3[14] = '?'; _to3[15] = 0; } else { - strlcpy(_to1, "to no recipient?", sizeof(_to1)); + strlcpy(_to1, "to new contract?", sizeof(_to1)); strlcpy(_to2, "", sizeof(_to2)); strlcpy(_to3, "", sizeof(_to3)); } @@ -267,6 +270,45 @@ static void layoutEthereumConfirmTx(const uint8_t *to, const uint8_t *value, uin ); } +static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total_len) +{ + char hexdata[3][17]; + char summary[20]; + int i; + uint32_t printed = 0; + for (i = 0; i < 3; i++) { + uint32_t linelen = len - printed; + if (linelen > 8) + linelen = 8; + data2hex(data, linelen, hexdata[i]); + data += linelen; + printed += linelen; + } + + strcpy(summary, "... bytes"); + char *p = summary + 11; + uint32_t number = total_len; + while (number > 0) { + *p-- = '0' + number % 10; + number = number / 10; + } + char *summarystart = summary; + if (total_len == printed) + summarystart = summary + 4; + + layoutDialogSwipe(&bmp_icon_question, + "Cancel", + "Confirm", + NULL, + "Transaction data:", + hexdata[0], + hexdata[1], + hexdata[2], + summarystart, + NULL + ); +} + /* * RLP fields: * - nonce (0 .. 32) @@ -309,6 +351,25 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) memset(&resp, 0, sizeof(EthereumTxRequest)); + if (!msg->has_nonce || !msg->has_gas_price || !msg->has_gas_limit) { + fsm_sendFailure(FailureType_Failure_Other, "Required field missing"); + ethereum_signing_abort(); + return; + } + /* set fields to 0, to avoid conditions later */ + if (!msg->has_value) + msg->value.size = 0; + if (!msg->has_data_initial_chunk) + msg->data_initial_chunk.size = 0; + + if (!msg->has_to) { + msg->to.size = 0; + } else if (msg->to.size != 20) { + fsm_sendFailure(FailureType_Failure_Other, "Address has wrong length"); + ethereum_signing_abort(); + return; + } + if (msg->has_data_length) { if (msg->data_length == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided"); @@ -345,23 +406,32 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) return; } - layoutEthereumConfirmTx(msg->has_to ? msg->to.bytes : NULL, msg->has_value ? msg->value.bytes : NULL, msg->has_value ? msg->value.size : 0); + layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); ethereum_signing_abort(); return; } + if (data_total > 0) { + layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + } + /* Stage 1: Calculate total RLP length */ uint32_t rlp_length = 0; layoutProgress("Signing", 0); - rlp_length += msg->has_nonce ? rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]) : 1; - rlp_length += msg->has_gas_price ? rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]) : 1; - rlp_length += msg->has_gas_limit ? rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]) : 1; - rlp_length += msg->has_to ? rlp_calculate_length(msg->to.size, msg->to.bytes[0]) : 1; - rlp_length += msg->has_value ? rlp_calculate_length(msg->value.size, msg->value.bytes[0]) : 1; + rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); + rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); + rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); + rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); + rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); /* Stage 2: Store header fields */ @@ -369,36 +439,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing", 100); - if (msg->has_nonce) { - hash_rlp_field(msg->nonce.bytes, msg->nonce.size); - } else { - hash_rlp_length(0, 0); - } - - if (msg->has_gas_price) { - hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); - } else { - hash_rlp_length(0, 0); - } - - if (msg->has_gas_limit) { - hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - } else { - hash_rlp_length(0, 0); - } - - if (msg->has_to) { - hash_rlp_field(msg->to.bytes, msg->to.size); - } else { - hash_rlp_length(0, 0); - } - - if (msg->has_value) { - hash_rlp_field(msg->value.bytes, msg->value.size); - } else { - hash_rlp_length(0, 0); - } - + hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); + hash_rlp_field(msg->to.bytes, msg->to.size); + hash_rlp_field(msg->value.bytes, msg->value.size); hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); if (data_total > 1 || msg->data_initial_chunk.bytes[0] >= 0x80) { hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); From 91dcead35eba26dbad74ccacbe3f99de904d0cc6 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 23 Aug 2016 18:44:46 +0200 Subject: [PATCH 0306/1154] Gas estimate screen, tweaked display of value --- firmware/ethereum.c | 210 ++++++++++++++++++++++++++----------------- vendor/trezor-crypto | 2 +- 2 files changed, 131 insertions(+), 81 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 67cf0e1698..ca6b08be86 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -174,73 +174,84 @@ static void send_signature(void) ethereum_signing_abort(); } -static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len) +/* Format a 256 bit number (amount in wei) into a human readable format + * using standard ethereum units. + * The buffer must be at least 25 bytes. + */ +static void ethereumFormatAmount(bignum256 *val, char buffer[25]) { - bignum256 val; - if (value && value_len <= 32) { - uint8_t pad_val[32]; - memset(pad_val, 0, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, &val); - } else { - bn_zero(&val); - } + char value[25] = {0}; + char *value_ptr = value; + uint16_t num[26]; uint8_t last_used = 0; for (int i = 0; i < 26; i++) { - bn_divmod1000(&val, (uint32_t *)&(num[i])); + bn_divmod1000(val, (uint32_t *)&(num[i])); if (num[i] > 0) { last_used = i; } } - - static char _value[25] = {0}; - const char *value_ptr = _value; - + if (last_used < 3) { // value is smaller than 1e9 wei => show value in wei - _value[0] = '0' + (num[2] / 100) % 10; - _value[1] = '0' + (num[2] / 10) % 10; - _value[2] = '0' + (num[2]) % 10; - _value[3] = '0' + (num[1] / 100) % 10; - _value[4] = '0' + (num[1] / 10) % 10; - _value[5] = '0' + (num[1]) % 10; - _value[6] = '0' + (num[0] / 100) % 10; - _value[7] = '0' + (num[0] / 10) % 10; - _value[8] = '0' + (num[0]) % 10; - strlcpy(_value + 9, " wei", sizeof(_value) - 9); - } else if (last_used < 9) { - // value is bigger than 1e9 wei and smaller than 1e9 ETH => show value in ETH - _value[0] = '0' + (num[8] / 100) % 10; - _value[1] = '0' + (num[8] / 10) % 10; - _value[2] = '0' + (num[8]) % 10; - _value[3] = '0' + (num[7] / 100) % 10; - _value[4] = '0' + (num[7] / 10) % 10; - _value[5] = '0' + (num[7]) % 10; - _value[6] = '0' + (num[6] / 100) % 10; - _value[7] = '0' + (num[6] / 10) % 10; - _value[8] = '0' + (num[6]) % 10; - _value[9] = '.'; - _value[10] = '0' + (num[5] / 100) % 10; - _value[11] = '0' + (num[5] / 10) % 10; - _value[12] = '0' + (num[5]) % 10; - _value[13] = '0' + (num[4] / 100) % 10; - _value[14] = '0' + (num[4] / 10) % 10; - _value[15] = '0' + (num[4]) % 10; - _value[16] = '0' + (num[3] / 100) % 10; - _value[17] = '0' + (num[3] / 10) % 10; - _value[18] = '0' + (num[3]) % 10; - strlcpy(_value + 19, " ETH", sizeof(_value) - 19); + for (int i = last_used; i >= 0; i--) { + *value_ptr++ = '0' + (num[i] / 100) % 10; + *value_ptr++ = '0' + (num[i] / 10) % 10; + *value_ptr++ = '0' + (num[i]) % 10; + } + strcpy(value_ptr, " Wei"); + // value is at most 9 + 4 + 1 characters long + } else if (last_used < 10) { + // value is bigger than 1e9 wei and smaller than 1e12 ETH => show value in ETH + int i = last_used; + if (i < 6) + i = 6; + int end = i - 4; + while (i >= end) { + *value_ptr++ = '0' + (num[i] / 100) % 10; + *value_ptr++ = '0' + (num[i] / 10) % 10; + *value_ptr++ = '0' + (num[i]) % 10; + if (i == 6) + *value_ptr++ = '.'; + i--; + } + while (value_ptr[-1] == '0') // remove trailing zeros + value_ptr--; + // remove trailing dot. + if (value_ptr[-1] == '.') + value_ptr--; + strcpy(value_ptr, " ETH"); + // value is at most 16 + 4 + 1 characters long } else { // value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik) - strlcpy(_value, "more than a billion ETH", sizeof(_value)); + strlcpy(value, "trillions of ETH", sizeof(value)); } - value_ptr = _value; - while (*value_ptr == '0' && *(value_ptr + 1) >= '0' && *(value_ptr + 1) <= '9') { // skip leading zeroes + // skip leading zeroes + value_ptr = value; + while (*value_ptr == '0' && *(value_ptr + 1) >= '0' && *(value_ptr + 1) <= '9') { value_ptr++; } + // copy to destination buffer + strcpy(buffer, value_ptr); +} + +static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len) +{ + bignum256 val; + uint8_t pad_val[32]; + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); + + char amount[25]; + if (bn_is_zero(&val)) { + strcpy(amount, "message"); + } else { + ethereumFormatAmount(&val, amount); + } + static char _to1[17] = {0}; static char _to2[17] = {0}; static char _to3[17] = {0}; @@ -261,8 +272,8 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui "Cancel", "Confirm", NULL, - "Really send", - value_ptr, + "Send", + amount, _to1, _to2, _to3, @@ -309,6 +320,49 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total ); } +static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, + const uint8_t *gas_price, uint32_t gas_price_len, + const uint8_t *gas_limit, uint32_t gas_limit_len) +{ + bignum256 val, gas; + uint8_t pad_val[32]; + char tx_value[25]; + char gas_value[25]; + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); + bn_read_be(pad_val, &val); + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); + bn_read_be(pad_val, &gas); + bn_multiply(&val, &gas, &secp256k1.prime); + + ethereumFormatAmount(&gas, gas_value); + + memset(pad_val, 0, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); + + if (bn_is_zero(&val)) { + strcpy(tx_value, "message"); + } else { + ethereumFormatAmount(&val, tx_value); + } + + layoutDialogSwipe(&bmp_icon_question, + "Cancel", + "Confirm", + NULL, + "Really send", + tx_value, + "paying up to", + gas_value, + "for gas?", + NULL + ); +} + /* * RLP fields: * - nonce (0 .. 32) @@ -321,23 +375,22 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total static bool ethereum_signing_check(EthereumSignTx *msg) { - // determine if address == 0 - bool address_zero = msg->has_to; - if (address_zero) { - for (size_t i = 0; i < msg->to.size; i++) { - if (msg->to.bytes[i] > 0) { - address_zero = false; - break; - } - } - } - - // sending value to address 0 - if (address_zero && msg->has_value && msg->value.size) { + if (!msg->has_nonce || !msg->has_gas_price || !msg->has_gas_limit) { return false; } - // sending transaction to address 0 without a data field - if (address_zero && (!msg->has_data_length || msg->data_length == 0)) { + + if (msg->to.size != 20 && msg->to.size != 0) { + /* Address has wrong length */ + return false; + } + + // sending transaction to address 0 (contract creation) without a data field + if (msg->to.size == 0 && (!msg->has_data_length || msg->data_length == 0)) { + return false; + } + + if (msg->gas_price.size + msg->gas_limit.size > 30) { + // sanity check that fee doesn't overflow return false; } @@ -350,25 +403,13 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) sha3_256_Init(&keccak_ctx); memset(&resp, 0, sizeof(EthereumTxRequest)); - - if (!msg->has_nonce || !msg->has_gas_price || !msg->has_gas_limit) { - fsm_sendFailure(FailureType_Failure_Other, "Required field missing"); - ethereum_signing_abort(); - return; - } /* set fields to 0, to avoid conditions later */ if (!msg->has_value) msg->value.size = 0; if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0; - - if (!msg->has_to) { + if (!msg->has_to) msg->to.size = 0; - } else if (msg->to.size != 20) { - fsm_sendFailure(FailureType_Failure_Other, "Address has wrong length"); - ethereum_signing_abort(); - return; - } if (msg->has_data_length) { if (msg->data_length == 0) { @@ -422,6 +463,15 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } } + layoutEthereumFee(msg->value.bytes, msg->value.size, + msg->gas_price.bytes, msg->gas_price.size, + msg->gas_limit.bytes, msg->gas_limit.size); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + ethereum_signing_abort(); + return; + } + /* Stage 1: Calculate total RLP length */ uint32_t rlp_length = 0; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f4ed55377d..7ce6b8b147 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f4ed55377d67b48a94c219313faa3035186369cb +Subproject commit 7ce6b8b14761ab770ff896f7d9c7a76d434e3df2 From bc550139423385d73da2ee48e283f14eb9303884 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 25 Aug 2016 12:59:40 +0200 Subject: [PATCH 0307/1154] Simplified one-byte encodings --- firmware/ethereum.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index ca6b08be86..70738710c8 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -49,8 +49,7 @@ static void hash_rlp_length(uint32_t length, uint8_t firstbyte) { uint8_t buf[4]; if (length == 1 && firstbyte <= 0x7f) { - buf[0] = firstbyte; - hash_data(buf, 1); + /* empty length header */ } else if (length <= 55) { buf[0] = 0x80 + length; hash_data(buf, 1); @@ -105,9 +104,7 @@ static void hash_rlp_list_length(uint32_t length) static void hash_rlp_field(const uint8_t *buf, size_t size) { hash_rlp_length(size, buf[0]); - if (size > 1 || buf[0] >= 0x80) { - hash_data(buf, size); - } + hash_data(buf, size); } /* @@ -495,12 +492,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) hash_rlp_field(msg->to.bytes, msg->to.size); hash_rlp_field(msg->value.bytes, msg->value.size); hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); - if (data_total > 1 || msg->data_initial_chunk.bytes[0] >= 0x80) { - hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - } + hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); data_left = data_total - msg->data_initial_chunk.size; - /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); if (data_left > 0) { From 5dae02bbbf083e8b1fb0d2ff3f01dcaaa0c63fbd Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 13 Jul 2016 12:51:47 +0200 Subject: [PATCH 0308/1154] Faster SPI communication According to specs, the display can handle up to 10 MHz SPI traffic (minimum cycle time is 100 ns). This patch sets the SPI port to 7.5 MHz (60 MHz clock with divisor 8). In my tests the display works even fine with SPI frequency at 60 MHz. I also minimized the delays (the spec doesn't require a long setup time) and use the registers to check when transfer is done instead of using a fixed delay. This patch also changes the swipe function to swipe pixel by pixel. Otherwise, the swipe would happen too fast to be seen. This changes the display update time from 11 ms to 1.5 ms. --- oled.c | 17 ++++++----------- setup.c | 3 ++- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/oled.c b/oled.c index a63d810a9f..926428e775 100644 --- a/oled.c +++ b/oled.c @@ -82,11 +82,12 @@ static bool is_debug_mode = 0; inline void SPISend(uint32_t base, uint8_t *data, int len) { int i; - delay(400); + delay(1); for (i = 0; i < len; i++) { spi_send(base, data[i]); } - delay(800); + while (!(SPI_SR(base) & SPI_SR_TXE)); + while ((SPI_SR(base) & SPI_SR_BSY)); } /* @@ -364,18 +365,12 @@ void oledFrame(int x1, int y1, int x2, int y2) void oledSwipeLeft(void) { int i, j, k; - for (i = 0; i < OLED_WIDTH / 4; i++) { + for (i = 0; i < OLED_WIDTH; i++) { for (j = 0; j < OLED_HEIGHT / 8; j++) { - for (k = OLED_WIDTH / 4 - 1; k > 0; k--) { - _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 1 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 2 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 3 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 - 4 + j * OLED_WIDTH]; + for (k = OLED_WIDTH-1; k > 0; k--) { + _oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1]; } _oledbuffer[j * OLED_WIDTH] = 0; - _oledbuffer[j * OLED_WIDTH + 1] = 0; - _oledbuffer[j * OLED_WIDTH + 2] = 0; - _oledbuffer[j * OLED_WIDTH + 3] = 0; } oledRefresh(); } diff --git a/setup.c b/setup.c index c85bd8d0c1..b91c2d6933 100644 --- a/setup.c +++ b/setup.c @@ -55,7 +55,7 @@ void setup(void) gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); // spi_disable_crc(SPI1); - spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); + spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); spi_enable_ss_output(SPI1); // spi_enable_software_slave_management(SPI1); // spi_set_nss_high(SPI1); @@ -71,4 +71,5 @@ void setupApp(void) { // hotfix for old bootloader gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); + spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); } From fff16e813a91698537ec05d0b040f29f0f43be7a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Aug 2016 10:44:28 +0200 Subject: [PATCH 0309/1154] add link to protobuf definition in coins.c --- firmware/coins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/coins.c b/firmware/coins.c index b0a0b77649..d55107c755 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -20,6 +20,7 @@ #include #include "coins.h" +// filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 const CoinType coins[COINS_COUNT] = { {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n"}, {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n"}, From 0a55a9e415fb9402708ce1235a8e3bc3d426cb06 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Aug 2016 12:59:29 +0200 Subject: [PATCH 0310/1154] update to nanopb 0.2.9.3 --- firmware/protob/messages.pb.c | 2 +- firmware/protob/messages.pb.h | 2 +- firmware/protob/pb.h | 2 +- firmware/protob/pb_decode.c | 6 ++++++ firmware/protob/storage.pb.c | 2 +- firmware/protob/storage.pb.h | 2 +- firmware/protob/types.pb.c | 2 +- firmware/protob/types.pb.h | 2 +- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index c72e3073c3..c16857f90d 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #include "messages.pb.h" diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 2b814ba8fe..aed732c41d 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #ifndef _PB_MESSAGES_PB_H_ #define _PB_MESSAGES_PB_H_ diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h index 70911e4dbd..dedcfe46af 100644 --- a/firmware/protob/pb.h +++ b/firmware/protob/pb.h @@ -46,7 +46,7 @@ /* Version of the nanopb library. Just in case you want to check it in * your own program. */ -#define NANOPB_VERSION nanopb-0.2.9.2 +#define NANOPB_VERSION nanopb-0.2.9.3 /* Include all the system headers needed by nanopb. You will need the * definitions of the following: diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c index 9edc8b3abb..c97ffde222 100644 --- a/firmware/protob/pb_decode.c +++ b/firmware/protob/pb_decode.c @@ -992,6 +992,12 @@ static void pb_release_single_field(const pb_field_iterator_t *iter) if (PB_HTYPE(type) == PB_HTYPE_REPEATED) { count = *(pb_size_t*)iter->pSize; + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) + { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } } if (pItem) diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 67f1619a8f..fd33888094 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #include "storage.pb.h" diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index c5d942eb90..7e8f5840ff 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #ifndef _PB_STORAGE_PB_H_ #define _PB_STORAGE_PB_H_ diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index a00a97dab8..89c11a18c8 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #include "types.pb.h" diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index beff78c031..e8318e1932 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.2 */ +/* Generated by nanopb-0.2.9.3 */ #ifndef _PB_TYPES_PB_H_ #define _PB_TYPES_PB_H_ From aaf2631dd63ed31a90ec37b34faa8cb3f3ff8a32 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Aug 2016 19:20:50 +0200 Subject: [PATCH 0311/1154] sign firmware inside docker container --- firmware-docker-build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 2b32c6c7b5..564a45e7e5 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -13,11 +13,12 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ make -C vendor/libopencm3 && \ make && \ make -C firmware && \ + make -C firmware sign && \ cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin" echo "---------------------" echo "Firmware fingerprint:" FILENAME=output/trezor-$FIRMWARETAG.bin -sha256sum "$FILENAME" +tail -c +257 "$FILENAME" | sha256sum FILESIZE=$(stat -c%s "$FILENAME") echo "Firmware size: $FILESIZE bytes (out of 491520 maximum)" From d7c0fbc379951d6107bb2e911fbce4114e8a3e90 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Aug 2016 22:36:18 +0200 Subject: [PATCH 0312/1154] add const where possible (for message parsing) --- firmware/messages.c | 8 ++++---- firmware/messages.h | 10 +++++----- firmware/protob/pb_decode.c | 2 +- firmware/protob/pb_decode.h | 4 ++-- firmware/usb.c | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 9981bc2b12..c927e531b7 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -308,7 +308,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * } } -void msg_read_common(char type, uint8_t *buf, int len) +void msg_read_common(char type, const uint8_t *buf, int len) { static char read_state = READSTATE_IDLE; static uint8_t msg_in[MSG_IN_SIZE]; @@ -357,7 +357,7 @@ void msg_read_common(char type, uint8_t *buf, int len) } } -uint8_t *msg_out_data(void) +const uint8_t *msg_out_data(void) { if (msg_out_start == msg_out_end) return 0; uint8_t *data = msg_out + (msg_out_start * 64); @@ -368,7 +368,7 @@ uint8_t *msg_out_data(void) #if DEBUG_LINK -uint8_t *msg_debug_out_data(void) +const uint8_t *msg_debug_out_data(void) { if (msg_debug_out_start == msg_debug_out_end) return 0; uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); @@ -382,7 +382,7 @@ uint8_t *msg_debug_out_data(void) uint8_t msg_tiny[64]; uint16_t msg_tiny_id = 0xFFFF; -void msg_read_tiny(uint8_t *buf, int len) +void msg_read_tiny(const uint8_t *buf, int len) { if (len != 64) return; if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { diff --git a/firmware/messages.h b/firmware/messages.h index a32e3ce8be..ac481101e6 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -30,7 +30,7 @@ #define msg_read(buf, len) msg_read_common('n', (buf), (len)) #define msg_write(id, ptr) msg_write_common('n', (id), (ptr)) -uint8_t *msg_out_data(void); +const uint8_t *msg_out_data(void); #if DEBUG_LINK @@ -38,15 +38,15 @@ uint8_t *msg_out_data(void); #define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) #define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) -uint8_t *msg_debug_out_data(void); +const uint8_t *msg_debug_out_data(void); #endif -void msg_read_common(char type, uint8_t *buf, int len); +void msg_read_common(char type, const uint8_t *buf, int len); bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr); -void msg_read_tiny(uint8_t *buf, int len); -void msg_debug_read_tiny(uint8_t *buf, int len); +void msg_read_tiny(const uint8_t *buf, int len); +void msg_debug_read_tiny(const uint8_t *buf, int len); extern uint8_t msg_tiny[64]; extern uint16_t msg_tiny_id; diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c index c97ffde222..307bbc4597 100644 --- a/firmware/protob/pb_decode.c +++ b/firmware/protob/pb_decode.c @@ -151,7 +151,7 @@ static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) return true; } -pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize) +pb_istream_t pb_istream_from_buffer(const uint8_t *buf, size_t bufsize) { pb_istream_t stream; #ifdef PB_BUFFER_ONLY diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h index 8dc67408a8..45c0675fc0 100644 --- a/firmware/protob/pb_decode.h +++ b/firmware/protob/pb_decode.h @@ -37,7 +37,7 @@ struct _pb_istream_t bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count); #endif - void *state; /* Free field for use by callback implementation */ + const void *state; /* Free field for use by callback implementation */ size_t bytes_left; #ifndef PB_NO_ERRMSG @@ -103,7 +103,7 @@ void pb_release(const pb_field_t fields[], void *dest_struct); * Alternatively, you can use a custom stream that reads directly from e.g. * a file or a network socket. */ -pb_istream_t pb_istream_from_buffer(uint8_t *buf, size_t bufsize); +pb_istream_t pb_istream_from_buffer(const uint8_t *buf, size_t bufsize); /* Function to read from a pb_istream_t. You can use this if you need to * read some custom header data, or to read data in field callbacks. diff --git a/firmware/usb.c b/firmware/usb.c index 4224761c71..6466f4ae2b 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -391,7 +391,7 @@ void usbInit(void) void usbPoll(void) { - static uint8_t *data; + static const uint8_t *data; // poll read buffer usbd_poll(usbd_dev); // write pending data From fd79570aafed31e289b574d112d36b6db3d48f8c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 Aug 2016 22:37:01 +0200 Subject: [PATCH 0313/1154] fix unaligned access in serialno; update trezor-crypto --- serialno.c | 8 ++++---- vendor/trezor-crypto | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/serialno.c b/serialno.c index b8c6741634..e16f31afa9 100644 --- a/serialno.c +++ b/serialno.c @@ -28,9 +28,9 @@ void fill_serialno_fixed(char *s) { - uint8_t uuid[32]; - desig_get_unique_id((uint32_t *)uuid); - sha256_Raw(uuid, 12, uuid); - sha256_Raw(uuid, 32, uuid); + uint32_t uuid[8]; + desig_get_unique_id(uuid); + sha256_Raw((const uint8_t *)uuid, 12, (uint8_t *)uuid); + sha256_Raw((const uint8_t *)uuid, 32, (uint8_t *)uuid); data2hex(uuid, 12, s); } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 7ce6b8b147..62b8f845f2 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 7ce6b8b14761ab770ff896f7d9c7a76d434e3df2 +Subproject commit 62b8f845f28539df7b305664ae56ba57a8cbc44c From dec9484a17cf459f79b34682b18b10ea1a83921d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 30 Aug 2016 10:33:13 +0200 Subject: [PATCH 0314/1154] update version --- firmware/trezor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index 79eee420b1..31877dca3e 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,8 +21,8 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 3 -#define VERSION_PATCH 6 +#define VERSION_MINOR 4 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 6d65551b827115c2fc7e927f032e60e045eaab2b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 29 Aug 2016 23:22:49 +0200 Subject: [PATCH 0315/1154] More alignment fixes --- firmware/ethereum.c | 8 ++++++-- firmware/fsm.c | 10 +++++----- firmware/storage.c | 18 +++++++++++------- firmware/u2f.c | 17 +++++++++-------- firmware/usb.c | 2 +- 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 70738710c8..4b714ca190 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -180,11 +180,15 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25]) char value[25] = {0}; char *value_ptr = value; + // convert val into base 1000 for easy printing. uint16_t num[26]; uint8_t last_used = 0; for (int i = 0; i < 26; i++) { - bn_divmod1000(val, (uint32_t *)&(num[i])); - if (num[i] > 0) { + uint32_t limb; + bn_divmod1000(val, &limb); + // limb is < 1000. + num[i] = (uint16_t) limb; + if (limb > 0) { last_used = i; } } diff --git a/firmware/fsm.c b/firmware/fsm.c index c54439b3d4..93c3639203 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -51,9 +51,9 @@ // message methods -static uint8_t msg_resp[MSG_OUT_SIZE]; +static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); -#define RESP_INIT(TYPE) TYPE *resp = (TYPE *)msg_resp; \ +#define RESP_INIT(TYPE) TYPE *resp = (TYPE *) (void *) msg_resp; \ _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ memset(resp, 0, sizeof(TYPE)); @@ -1142,10 +1142,10 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) if (msg->flash) { flash_clear_status_flags(); flash_unlock(); - uint32_t* src = (uint32_t *) msg->memory.bytes; for (unsigned int i = 0; i < length; i += 4) { - flash_program_word(msg->address + i, *src); - src++; + uint32_t word; + memcpy(&word, msg->memory.bytes + i, 4); + flash_program_word(msg->address + i, word); } flash_lock(); } else { diff --git a/firmware/storage.c b/firmware/storage.c index 2cc9204ae5..0eaa8554a9 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -42,7 +42,7 @@ Storage storage; -uint8_t storage_uuid[12]; +uint32_t storage_uuid[12/sizeof(uint32_t)]; char storage_uuid_str[25]; /* @@ -77,6 +77,7 @@ be added to the storage u2f_counter to get the real counter value. #define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) #define FLASH_STORAGE_U2FAREA_LEN (0x100) #define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage)) + _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); _Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); _Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); @@ -87,6 +88,9 @@ _Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); */ static uint32_t storage_u2f_offset; +/* magic constant to check validity of storage block */ +static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t + static bool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t sessionSeed[64]; @@ -114,7 +118,7 @@ void storage_check_flash_errors(void) bool storage_from_flash(void) { - if (memcmp((void *)FLASH_STORAGE_START, "stor", 4) != 0) { + if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, 4) != 0) { // wrong magic return false; } @@ -182,7 +186,7 @@ void storage_init(void) void storage_reset_uuid(void) { // set random uuid - random_buffer(storage_uuid, sizeof(storage_uuid)); + random_buffer((uint8_t *)storage_uuid, sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); } @@ -216,7 +220,7 @@ static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) { static void storage_commit_locked(void) { - uint8_t meta_backup[FLASH_META_DESC_LEN]; + uint32_t meta_backup[FLASH_META_DESC_LEN/4]; // backup meta memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); @@ -225,11 +229,11 @@ static void storage_commit_locked(void) flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); // copy meta uint32_t flash = FLASH_META_START; - flash = storage_flash_words(flash, (uint32_t *)meta_backup, FLASH_META_DESC_LEN/4); + flash = storage_flash_words(flash, meta_backup, FLASH_META_DESC_LEN/4); // copy storage - flash_program_word(flash, *(uint32_t *) "stor"); + flash_program_word(flash, storage_magic); flash += 4; - flash = storage_flash_words(flash, (uint32_t *)&storage_uuid, sizeof(storage_uuid)/4); + flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid)/4); flash = storage_flash_words(flash, (uint32_t *)&storage, sizeof(storage)/4); // fill remainder with zero for future extensions while (flash < FLASH_STORAGE_PINAREA) { diff --git a/firmware/u2f.c b/firmware/u2f.c index 76eb80f511..22eb3e1d95 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -297,7 +297,7 @@ void u2fhid_init(const U2FHID_FRAME *in) { const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; U2FHID_FRAME f; - U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; + U2FHID_INIT_RESP resp; debugLog(0, "", "u2fhid_init"); @@ -312,13 +312,14 @@ void u2fhid_init(const U2FHID_FRAME *in) f.init.bcnth = 0; f.init.bcntl = U2FHID_INIT_RESP_SIZE; - memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); - resp->cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; - resp->versionInterface = U2FHID_IF_VERSION; - resp->versionMajor = VERSION_MAJOR; - resp->versionMinor = VERSION_MINOR; - resp->versionBuild = VERSION_PATCH; - resp->capFlags = CAPFLAG_WINK; + memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); + resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; + resp.versionInterface = U2FHID_IF_VERSION; + resp.versionMajor = VERSION_MAJOR; + resp.versionMinor = VERSION_MINOR; + resp.versionBuild = VERSION_PATCH; + resp.capFlags = CAPFLAG_WINK; + memcpy(&f.init.data, &resp, sizeof(resp)); queue_u2f_pkt(&f); } diff --git a/firmware/usb.c b/firmware/usb.c index 6466f4ae2b..56504deee8 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -342,7 +342,7 @@ static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) debugLog(0, "", "hid_u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; - u2fhid_read(tiny, (const U2FHID_FRAME *)buf); + u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } #if DEBUG_LINK From e0e190b3dc29bcb0f6ab9699c439fe7bfbcde370 Mon Sep 17 00:00:00 2001 From: bitcartel Date: Wed, 31 Aug 2016 04:35:24 -0700 Subject: [PATCH 0316/1154] Update coins.c for Zcash mainnet (#111) --- firmware/coins.c | 1 + firmware/coins.h | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index d55107c755..8a50dbdc81 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -28,6 +28,7 @@ const CoinType coins[COINS_COUNT] = { {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, + {true, "Zcash", true, "ZEC", true, 65, true, 1000000, true, 5, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/coins.h b/firmware/coins.h index b57566ee33..32a3ba8b3c 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 6 +#define COINS_COUNT 7 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index daf1211b1e..6ee1493341 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:6 +Features.coins max_count:7 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index aed732c41d..f6dfa2444c 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -536,7 +536,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[6]; + CoinType coins[7]; bool has_initialized; bool initialized; bool has_revision; @@ -835,7 +835,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -901,7 +901,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -1206,7 +1206,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (242 + 6*CoinType_size) +#define Features_size (248 + 7*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 From 259eeae26ea7ae62d91a3bbb86b1f27326257c87 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 25 Sep 2016 15:49:12 +0200 Subject: [PATCH 0317/1154] don't halt on broken firmware but stay in bootloader mode --- bootloader/bootloader.c | 33 +++++++++++++++------------------ bootloader/bootloader.h | 4 ++-- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 30abc4bc54..53d1de996c 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -111,22 +111,18 @@ void bootloader_loop(void) usbLoop(); } -void check_firmware_sanity(void) +int check_firmware_sanity(void) { - int broken = 0; if (memcmp((void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match - broken++; + return 0; } if (*((uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB - broken++; + return 0; } if (*((uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size - broken++; - } - if (broken) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); - system_halt(); + return 0; } + return 1; } uint32_t __stack_chk_guard; @@ -148,19 +144,20 @@ int main(void) uint16_t state = gpio_port_read(BTN_PORT); if ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO) { - check_firmware_sanity(); + if (check_firmware_sanity()) { - oledClear(); - oledDrawBitmap(40, 0, &bmp_logo64_empty); - oledRefresh(); + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64_empty); + oledRefresh(); - uint8_t hash[32]; - if (!signatures_ok(hash)) { - show_unofficial_warning(hash); + uint8_t hash[32]; + if (!signatures_ok(hash)) { + show_unofficial_warning(hash); + } + + load_app(); } - load_app(); - } bootloader_loop(); diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index abe80786ff..7046c62bca 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 -#define VERSION_PATCH 7 +#define VERSION_PATCH 8 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x02" -#define VERSION_PATCH_CHAR "\x07" +#define VERSION_PATCH_CHAR "\x08" #include "memory.h" From dc8348b4a039188a47478b81ae5e37011f949737 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 25 Sep 2016 16:04:07 +0200 Subject: [PATCH 0318/1154] add flash target to bootloader makefile --- bootloader/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index 85b9aa0480..8f06bb84f9 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -16,5 +16,8 @@ CFLAGS += -DUSE_PRECOMPUTED_CP=0 include ../Makefile.include -align: +align: $(NAME).bin ./firmware_align.py $(NAME).bin + +flash: $(NAME).bin + $(FLASH) write $(NAME).bin 0x8000000 From cda9ae4b292d4b22e49eafa7c767da57e0a550bf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 25 Sep 2016 16:36:44 +0200 Subject: [PATCH 0319/1154] change version description in bootloader --- bootloader/bootloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 53d1de996c..decb26719d 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -103,7 +103,7 @@ void bootloader_loop(void) serial[12] = 0; oledDrawString(52, 30, serial); // first part of serial - oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "BLv" VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); + oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); oledRefresh(); From 2f7ed2aa0fec6647c1a1e4940d38ff816a51324c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Sep 2016 13:09:09 +0200 Subject: [PATCH 0320/1154] implement firmware_present flag in bootloader --- bootloader/bootloader.c | 52 ++++++++++++++++++++++------------------- bootloader/bootloader.h | 8 +++---- bootloader/usb.c | 29 ++++++++++++++++------- vendor/trezor-common | 2 +- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index decb26719d..10db8ff214 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -89,22 +89,26 @@ void load_app(void) (*(void (**)())(FLASH_APP_START + 4))(); } +int firmware_present; + void bootloader_loop(void) { - static char serial[25]; - - fill_serialno_fixed(serial); - + oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); - oledDrawString(52, 0, "TREZOR"); - - oledDrawString(52, 20, "Serial No."); - oledDrawString(52, 40, serial + 12); // second part of serial - serial[12] = 0; - oledDrawString(52, 30, serial); // first part of serial - - oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); - + if (firmware_present) { + oledDrawString(52, 0, "TREZOR"); + static char serial[25]; + fill_serialno_fixed(serial); + oledDrawString(52, 20, "Serial No."); + oledDrawString(52, 40, serial + 12); // second part of serial + serial[12] = 0; + oledDrawString(52, 30, serial); // first part of serial + oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); + } else { + oledDrawString(52, 10, "Welcome!"); + oledDrawString(52, 30, "Please visit"); + oledDrawString(52, 50, "trezor.io/start"); + } oledRefresh(); usbInit(); @@ -140,24 +144,24 @@ int main(void) memory_protect(); oledInit(); + firmware_present = check_firmware_sanity(); + // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); - if ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO) { + int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); - if (check_firmware_sanity()) { + if (firmware_present && unpressed) { - oledClear(); - oledDrawBitmap(40, 0, &bmp_logo64_empty); - oledRefresh(); + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64_empty); + oledRefresh(); - uint8_t hash[32]; - if (!signatures_ok(hash)) { - show_unofficial_warning(hash); - } - - load_app(); + uint8_t hash[32]; + if (!signatures_ok(hash)) { + show_unofficial_warning(hash); } + load_app(); } bootloader_loop(); diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 7046c62bca..687c3fffbf 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,15 +21,15 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 2 -#define VERSION_PATCH 8 +#define VERSION_MINOR 3 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x02" -#define VERSION_PATCH_CHAR "\x08" +#define VERSION_MINOR_CHAR "\x03" +#define VERSION_PATCH_CHAR "\x00" #include "memory.h" diff --git a/bootloader/usb.c b/bootloader/usb.c index 3745b0cacd..ecdaa6b124 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -202,21 +202,34 @@ static void send_msg_failure(usbd_device *dev) , 64) != 64) {} } +extern int firmware_present; + static void send_msg_features(usbd_device *dev) { - // send response: Features message (id 17), payload len 27 + // send response: Features message (id 17), payload len 30 // vendor = "bitcointrezor.com" // major_version = VERSION_MAJOR // minor_version = VERSION_MINOR // patch_version = VERSION_PATCH // bootloader_mode = True - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x11" // msg_id - "\x00\x00\x00\x1b" // payload_len - "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} + // firmware_present = True/False + if (firmware_present) { + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, + "?##" // header + "\x00\x11" // msg_id + "\x00\x00\x00\x1e" // payload_len + "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data + "\x90\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} + } else { + while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, + "?##" // header + "\x00\x11" // msg_id + "\x00\x00\x00\x1e" // payload_len + "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data + "\x90\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + , 64) != 64) {} + } } static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) diff --git a/vendor/trezor-common b/vendor/trezor-common index 4c2b12b0c5..c2a0b255ff 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 4c2b12b0c51e293fe08f04554cdd55a081250653 +Subproject commit c2a0b255ff1ba174085ebe76c46f8e049f85d197 From 9fe9ebc990ab012f9988b9a42af51d9f0fa4ca35 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Sep 2016 14:57:10 +0200 Subject: [PATCH 0321/1154] fix usb descriptor in bootloader --- bootloader/usb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index ecdaa6b124..0b31630b1e 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -55,17 +55,20 @@ static const struct usb_device_descriptor dev_descr = { }; static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Reserved) + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (1) 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x85, 0x3f, // REPORT_ID (63) 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x3f, // REPORT_COUNT (63) - 0x09, 0x01, // USAGE (1) + 0x95, 0x40, // REPORT_COUNT (64) 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x01, // USAGE (1) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; From d767e52055ffb6da0610e95ad5f7902e490e9dcf Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 27 Sep 2016 23:33:28 +0200 Subject: [PATCH 0322/1154] Confirm to change U2F counter (#114) --- firmware/fsm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 93c3639203..1ed2a95a5c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1067,8 +1067,15 @@ void fsm_msgWordAck(WordAck *msg) void fsm_msgSetU2FCounter(SetU2FCounter *msg) { + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you want to set", "the U2F counter?", NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "SetU2FCounter cancelled"); + layoutHome(); + return; + } storage_setU2FCounter(msg->u2f_counter); fsm_sendSuccess("U2F counter set"); + layoutHome(); } #if DEBUG_LINK From d7ff70caf60d8cb0d65d0598087508dfd62b0f56 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Oct 2016 15:02:44 +0200 Subject: [PATCH 0323/1154] add checking of buttons to bootloader --- bootloader/bootloader.c | 2 ++ bootloader/usb.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 10db8ff214..cf1e7d1e0e 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -161,6 +161,8 @@ int main(void) show_unofficial_warning(hash); } + delay(100000); + load_app(); } diff --git a/bootloader/usb.c b/bootloader/usb.c index 0b31630b1e..51172ca2c0 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -483,9 +483,26 @@ void usbInit(void) usbd_register_set_config_callback(usbd_dev, hid_set_config); } +void checkButtons(void) +{ + uint16_t state = gpio_port_read(BTN_PORT); + if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { + if ((state & BTN_PIN_NO) != BTN_PIN_NO) { + oledInvert(0, 0, 3, 3); + } + if ((state & BTN_PIN_YES) != BTN_PIN_YES) { + oledInvert(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3); + } + oledRefresh(); + } +} + void usbLoop(void) { for (;;) { usbd_poll(usbd_dev); + if (flash_state == STATE_READY || flash_state == STATE_OPEN) { + checkButtons(); + } } } From a0ade6343e04670dd766a94f13c644398cc1faff Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 6 Oct 2016 16:58:05 +0200 Subject: [PATCH 0324/1154] Reworked rfc6979 signing. (#116) New parameter is_canonical that allows for generating signatures that have additional requirements. --- firmware/crypto.c | 6 +++--- firmware/ethereum.c | 13 ++++++++++--- firmware/signing.c | 2 +- firmware/u2f.c | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 45e96c822c..a1c8f4c91d 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -88,7 +88,7 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign(node, message, message_len, signature + 1, NULL); + return hdnode_sign(node, message, message_len, signature + 1, NULL, NULL); } int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) @@ -98,7 +98,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin return 1; } signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign_digest(node, message, signature + 1, NULL); + return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); } int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key) @@ -133,7 +133,7 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message sha256_Final(&ctx, hash); sha256_Raw(hash, 32, hash); uint8_t pby; - int result = hdnode_sign_digest(node, hash, signature + 1, &pby); + int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); if (result == 0) { signature[0] = 27 + pby + 4; } diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 4b714ca190..5284795b84 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -34,7 +34,7 @@ static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest resp; -static uint8_t hash[32], sig[64], privkey[32]; +static uint8_t privkey[32]; struct SHA3_CTX keccak_ctx; static inline void hash_data(const uint8_t *buf, size_t size) @@ -139,12 +139,19 @@ static void send_request_chunk(void) msg_write(MessageType_MessageType_EthereumTxRequest, &resp); } +static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) +{ + (void) signature; + return (v & 2) == 0; +} + static void send_signature(void) { + uint8_t hash[32], sig[64]; + uint8_t v; layoutProgress("Signing", 1000); keccak_Final(&keccak_ctx, hash); - uint8_t v; - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v) != 0) { + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); ethereum_signing_abort(); return; diff --git a/firmware/signing.c b/firmware/signing.c index e78eec628b..4648536619 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -540,7 +540,7 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(&secp256k1, privkey, hash, sig, 0); + ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (input.script_type == InputScriptType_SPENDMULTISIG) { if (!input.has_multisig) { diff --git a/firmware/u2f.c b/firmware/u2f.c index 22eb3e1d95..942ef9bf79 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -617,7 +617,7 @@ void u2f_register(const APDU *a) memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, - sizeof(sig_base), sig, NULL); + sizeof(sig_base), sig, NULL, NULL); // Where to write the signature in the response uint8_t *resp_sig = resp->keyHandleCertSig + @@ -738,7 +738,7 @@ void u2f_authenticate(const APDU *a) memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); ecdsa_sign(&nist256p1, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, - NULL); + NULL, NULL); // Copy DER encoded signature into response const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); From 1234ab94d42a9f3d9e6d9c68e0ee7d321725422a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Oct 2016 17:01:17 +0200 Subject: [PATCH 0325/1154] update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 62b8f845f2..157caf3763 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 62b8f845f28539df7b305664ae56ba57a8cbc44c +Subproject commit 157caf3763866c386f9bcc287db3a1a472b5d55e From 69d99d202d0d9360c6cdbef9e17f25cd81477ff1 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Sun, 9 Oct 2016 20:38:51 +0100 Subject: [PATCH 0326/1154] Add support for multi-byte address prefixes. --- firmware/coins.c | 54 +++++++++++++++++++++++++++++++++++++++++- firmware/coins.h | 6 ++++- firmware/crypto.c | 11 +++++---- firmware/crypto.h | 2 +- firmware/fsm.c | 20 +++++++--------- firmware/transaction.c | 28 ++++++++++------------ firmware/transaction.h | 2 +- vendor/trezor-crypto | 2 +- 8 files changed, 89 insertions(+), 36 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 8a50dbdc81..d027f56d3b 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -55,7 +55,7 @@ const CoinType *coinByName(const char *name) return 0; } -const CoinType *coinByAddressType(uint8_t address_type) +const CoinType *coinByAddressType(uint32_t address_type) { int i; for (i = 0; i < COINS_COUNT; i++) { @@ -65,3 +65,55 @@ const CoinType *coinByAddressType(uint8_t address_type) } return 0; } + +size_t prefixBytesByAddressType(uint32_t address_type) +{ + if (address_type <= 0xFF) return 1; + if (address_type <= 0xFFFF) return 2; + if (address_type <= 0xFFFFFF) return 3; + return 4; +} + +bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type) +{ + if (address_type <= 0xFF) { + return address_type == (uint32_t)(addr[0]); + } + if (address_type <= 0xFFFF) { + return address_type == ((uint32_t)(addr[0] << 8) | (uint32_t)(addr[1])); + } + if (address_type <= 0xFFFFFF) { + return address_type == ((uint32_t)(addr[0] << 16) | (uint32_t)(addr[1] << 8) | (uint32_t)(addr[2])); + } + return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); +} + +void writeAddressPrefix(uint8_t *addr, uint32_t address_type) +{ + if (address_type > 0xFFFFFF) *(addr++) = address_type >> 24; + if (address_type > 0xFFFF) *(addr++) = (address_type >> 16) & 0xFF; + if (address_type > 0xFF) *(addr++) = (address_type >> 8) & 0xFF; + *(addr++) = address_type & 0xFF; +} + +bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type) +{ + if (coin->has_address_type && addressHasExpectedPrefix(addr, coin->address_type)) { + *address_type = coin->address_type; + return true; + } + if (coin->has_address_type_p2sh && addressHasExpectedPrefix(addr, coin->address_type_p2sh)) { + *address_type = coin->address_type_p2sh; + return true; + } + if (coin->has_address_type_p2wpkh && addressHasExpectedPrefix(addr, coin->address_type_p2wpkh)) { + *address_type = coin->address_type_p2wpkh; + return true; + } + if (coin->has_address_type_p2wsh && addressHasExpectedPrefix(addr, coin->address_type_p2wsh)) { + *address_type = coin->address_type_p2wsh; + return true; + } + *address_type = 0; + return false; +} diff --git a/firmware/coins.h b/firmware/coins.h index 32a3ba8b3c..b09e241fdd 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -28,6 +28,10 @@ extern const CoinType coins[COINS_COUNT]; const CoinType *coinByShortcut(const char *shortcut); const CoinType *coinByName(const char *name); -const CoinType *coinByAddressType(uint8_t address_type); +const CoinType *coinByAddressType(uint32_t address_type); +size_t prefixBytesByAddressType(uint32_t address_type); +bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type); +void writeAddressPrefix(uint8_t *addr, uint32_t address_type); +bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type); #endif diff --git a/firmware/crypto.c b/firmware/crypto.c index a1c8f4c91d..b3e3ce1526 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -28,6 +28,7 @@ #include "curves.h" #include "secp256k1.h" #include "macros.h" +#include "coins.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -140,10 +141,10 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message return result; } -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) { SHA256_CTX ctx; - uint8_t pubkey[65], addr_raw[21], hash[32]; + uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32]; // calculate hash sha256_Init(&ctx); @@ -171,8 +172,8 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes pubkey[0] = 0x02 | (pubkey[64] & 1); } // check if the address is correct - ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw); - if (memcmp(addr_raw, address_raw, 21) != 0) { + ecdsa_get_address_raw(pubkey, address_type, addr_raw); + if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(address_type) + 20) != 0) { return 2; } return 0; @@ -272,9 +273,11 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le uint32_t l, o; l = deser_length(payload + 1, &o); if (*signing) { + // FIXME: assumes a raw address is 21 bytes (also below). if (1 + l + o + 21 + 65 != payload_len) { return 4; } + // FIXME: cryptoMessageVerify changed to take the address_type as a parameter. if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) { return 5; } diff --git a/firmware/crypto.h b/firmware/crypto.h index e6d3c00faf..ff97f91f2f 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -42,7 +42,7 @@ int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 1ed2a95a5c..c2b5dd57a6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -732,9 +732,7 @@ void fsm_msgSignMessage(SignMessage *msg) layoutProgressSwipe("Signing", 0); if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; - uint8_t addr_raw[21]; - hdnode_get_address_raw(node, coin->address_type, addr_raw); - base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); + hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); @@ -757,11 +755,13 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; layoutProgressSwipe("Verifying", 0); - uint8_t addr_raw[21]; - if (!ecdsa_address_decode(msg->address, addr_raw)) { + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint32_t address_type; + if (!getAddressType(coin, (const uint8_t *) msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); + return; } - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); @@ -845,9 +845,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) resp->has_address = false; } else { resp->has_address = true; - uint8_t addr_raw[21]; - hdnode_get_address_raw(node, 0x00, addr_raw); // hardcoded Bitcoin address type - base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); + hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type } resp->has_public_key = true; resp->public_key.size = 33; @@ -943,7 +941,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) RESP_INIT(EncryptedMessage); const CoinType *coin = 0; const HDNode *node = 0; - uint8_t address_raw[21]; + uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (signing) { coin = coinByName(msg->coin_name); if (!coin) { @@ -1011,7 +1009,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; - uint8_t address_raw[21]; + uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message"); layoutHome(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 6b0ec88e6c..54801a3761 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -59,7 +59,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T { memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; - uint8_t addr_raw[21]; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; if (in->script_type == OutputScriptType_PAYTOADDRESS) { @@ -80,12 +80,10 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return -1; } } - if (!ecdsa_address_decode(in->address, addr_raw)) { - return 0; - } - if (addr_raw[0] != coin->address_type) { + if (!ecdsa_address_decode(in->address, coin->address_type, addr_raw)) { return 0; } + } else { // does not have address_n neither address -> error return 0; } @@ -93,7 +91,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + memcpy(out->script_pubkey.bytes + 3, addr_raw + prefixBytesByAddressType(coin->address_type), 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; @@ -101,10 +99,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) { - if (!in->has_address || !ecdsa_address_decode(in->address, addr_raw)) { - return 0; - } - if (addr_raw[0] != coin->address_type_p2sh) { + if (!in->has_address || !ecdsa_address_decode(in->address, coin->address_type_p2sh, addr_raw)) { return 0; } if (needs_confirm) { @@ -115,7 +110,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefixBytesByAddressType(coin->address_type_p2sh), 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; return 23; @@ -123,16 +118,17 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (in->script_type == OutputScriptType_PAYTOMULTISIG) { uint8_t buf[32]; + size_t prefix_bytes = prefixBytesByAddressType(coin->address_type_p2sh); if (!in->has_multisig) { return 0; } if (compile_script_multisig_hash(&(in->multisig), buf) == 0) { return 0; } - addr_raw[0] = coin->address_type_p2sh; - ripemd160(buf, 32, addr_raw + 1); + writeAddressPrefix(addr_raw, coin->address_type_p2sh); + ripemd160(buf, 32, addr_raw + prefix_bytes); if (needs_confirm) { - base58_encode_check(addr_raw, 21, in->address, sizeof(in->address)); + base58_encode_check(addr_raw, prefix_bytes + 20, in->address, sizeof(in->address)); layoutConfirmOutput(coin, in); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; @@ -140,7 +136,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_bytes, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; return 23; @@ -159,7 +155,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 0; } -uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out) +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out) { if (coinByAddressType(address_type)) { // valid coin type out[0] = 0x76; // OP_DUP diff --git a/firmware/transaction.h b/firmware/transaction.h index e6980a0416..bd64baa4f2 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -41,7 +41,7 @@ typedef struct { SHA256_CTX ctx; } TxStruct; -uint32_t compile_script_sig(uint8_t address_type, const uint8_t *pubkeyhash, uint8_t *out); +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 157caf3763..ad73c0d4e7 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 157caf3763866c386f9bcc287db3a1a472b5d55e +Subproject commit ad73c0d4e73fe138ebbbc39d6a335167ba7c9923 From 6bfe487f19aa1b6407fb876d6cd8e7d786fbd759 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Sun, 9 Oct 2016 20:39:35 +0100 Subject: [PATCH 0327/1154] Update address prefixes for Zcash. --- firmware/coins.c | 16 +++++++++------- firmware/coins.h | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index d027f56d3b..b9eb7468be 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -21,14 +21,16 @@ #include "coins.h" // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 +// address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n"}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n"}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n"}, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, - {true, "Zcash", true, "ZEC", true, 65, true, 1000000, true, 5, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, + {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n"}, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n"}, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n"}, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, + {true, "Zcash", true, "ZEC", true, 0x1CB8, true, 1000000, true, 0x1CBD, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, + {true, "Zcash Testnet", true, "TAZ", true, 0x1CBA, true, 1000000, true, 0x1D25, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/coins.h b/firmware/coins.h index b09e241fdd..5acd61e52f 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 7 +#define COINS_COUNT 8 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 6ee1493341..1e1a86f696 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:7 +Features.coins max_count:8 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index f6dfa2444c..36c92b3c8f 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -536,7 +536,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[7]; + CoinType coins[8]; bool has_initialized; bool initialized; bool has_revision; @@ -835,7 +835,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -901,7 +901,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -1206,7 +1206,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (248 + 7*CoinType_size) +#define Features_size (254 + 8*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 From 3a42032c63ab4c8d2bd1769b25bcc502934376e0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Oct 2016 00:18:57 +0200 Subject: [PATCH 0328/1154] simplify cryptoMessageVerify call --- firmware/crypto.c | 6 +++--- firmware/crypto.h | 3 +-- firmware/fsm.c | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index b3e3ce1526..0f8344efec 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -141,7 +141,7 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message return result; } -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) { SHA256_CTX ctx; uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32]; @@ -172,8 +172,8 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes pubkey[0] = 0x02 | (pubkey[64] & 1); } // check if the address is correct - ecdsa_get_address_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(address_type) + 20) != 0) { + ecdsa_get_address_raw(pubkey, coin->address_type, addr_raw); + if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(coin->address_type) + 20) != 0) { return 2; } return 0; diff --git a/firmware/crypto.h b/firmware/crypto.h index ff97f91f2f..28f11bf05c 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -39,10 +39,9 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); - int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index c2b5dd57a6..144b8d1b47 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -756,12 +756,11 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) if (!coin) return; layoutProgressSwipe("Verifying", 0); uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint32_t address_type; - if (!getAddressType(coin, (const uint8_t *) msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { + if (!ecdsa_address_decode(msg->address, coin->address_type, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); return; } - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); From e70900d49e4d3b433934e90574f79ea3c1e1b562 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Oct 2016 10:17:51 +0200 Subject: [PATCH 0329/1154] don't tie message verification with P2PKH addresses --- firmware/crypto.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 0f8344efec..de0e8e91c7 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -172,8 +172,12 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes pubkey[0] = 0x02 | (pubkey[64] & 1); } // check if the address is correct - ecdsa_get_address_raw(pubkey, coin->address_type, addr_raw); - if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(coin->address_type) + 20) != 0) { + uint32_t address_type; + if (!getAddressType(coin, address_raw, &address_type)) { + return 2; + } + ecdsa_get_address_raw(pubkey, address_type, addr_raw); + if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(address_type) + 20) != 0) { return 2; } return 0; From c0181b1aec2d4235d9684635a732cdca3355ae99 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Oct 2016 11:26:52 +0200 Subject: [PATCH 0330/1154] extract address related stuff into trezor-crypto --- firmware/Makefile | 1 + firmware/coins.c | 41 ++++++----------------------------------- firmware/coins.h | 5 +---- firmware/crypto.c | 5 +++-- firmware/transaction.c | 9 +++++---- vendor/trezor-crypto | 2 +- 6 files changed, 17 insertions(+), 46 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 845d3c02cf..9c60e6522a 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -21,6 +21,7 @@ OBJS += ethereum.o OBJS += debug.o +OBJS += ../vendor/trezor-crypto/address.o OBJS += ../vendor/trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/curves.o diff --git a/firmware/coins.c b/firmware/coins.c index b9eb7468be..4853770734 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -19,6 +19,7 @@ #include #include "coins.h" +#include "address.h" // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order @@ -68,51 +69,21 @@ const CoinType *coinByAddressType(uint32_t address_type) return 0; } -size_t prefixBytesByAddressType(uint32_t address_type) +bool coinExtractAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type) { - if (address_type <= 0xFF) return 1; - if (address_type <= 0xFFFF) return 2; - if (address_type <= 0xFFFFFF) return 3; - return 4; -} - -bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type) -{ - if (address_type <= 0xFF) { - return address_type == (uint32_t)(addr[0]); - } - if (address_type <= 0xFFFF) { - return address_type == ((uint32_t)(addr[0] << 8) | (uint32_t)(addr[1])); - } - if (address_type <= 0xFFFFFF) { - return address_type == ((uint32_t)(addr[0] << 16) | (uint32_t)(addr[1] << 8) | (uint32_t)(addr[2])); - } - return address_type == ((uint32_t)(addr[0] << 24) | (uint32_t)(addr[1] << 16) | (uint32_t)(addr[2] << 8) | (uint32_t)(addr[3])); -} - -void writeAddressPrefix(uint8_t *addr, uint32_t address_type) -{ - if (address_type > 0xFFFFFF) *(addr++) = address_type >> 24; - if (address_type > 0xFFFF) *(addr++) = (address_type >> 16) & 0xFF; - if (address_type > 0xFF) *(addr++) = (address_type >> 8) & 0xFF; - *(addr++) = address_type & 0xFF; -} - -bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type) -{ - if (coin->has_address_type && addressHasExpectedPrefix(addr, coin->address_type)) { + if (coin->has_address_type && address_check_prefix(addr, coin->address_type)) { *address_type = coin->address_type; return true; } - if (coin->has_address_type_p2sh && addressHasExpectedPrefix(addr, coin->address_type_p2sh)) { + if (coin->has_address_type_p2sh && address_check_prefix(addr, coin->address_type_p2sh)) { *address_type = coin->address_type_p2sh; return true; } - if (coin->has_address_type_p2wpkh && addressHasExpectedPrefix(addr, coin->address_type_p2wpkh)) { + if (coin->has_address_type_p2wpkh && address_check_prefix(addr, coin->address_type_p2wpkh)) { *address_type = coin->address_type_p2wpkh; return true; } - if (coin->has_address_type_p2wsh && addressHasExpectedPrefix(addr, coin->address_type_p2wsh)) { + if (coin->has_address_type_p2wsh && address_check_prefix(addr, coin->address_type_p2wsh)) { *address_type = coin->address_type_p2wsh; return true; } diff --git a/firmware/coins.h b/firmware/coins.h index 5acd61e52f..69cb002fee 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -29,9 +29,6 @@ extern const CoinType coins[COINS_COUNT]; const CoinType *coinByShortcut(const char *shortcut); const CoinType *coinByName(const char *name); const CoinType *coinByAddressType(uint32_t address_type); -size_t prefixBytesByAddressType(uint32_t address_type); -bool addressHasExpectedPrefix(const uint8_t *addr, uint32_t address_type); -void writeAddressPrefix(uint8_t *addr, uint32_t address_type); -bool getAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type); +bool coinExtractAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type); #endif diff --git a/firmware/crypto.c b/firmware/crypto.c index de0e8e91c7..1728793b84 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -27,6 +27,7 @@ #include "layout.h" #include "curves.h" #include "secp256k1.h" +#include "address.h" #include "macros.h" #include "coins.h" @@ -173,11 +174,11 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes } // check if the address is correct uint32_t address_type; - if (!getAddressType(coin, address_raw, &address_type)) { + if (!coinExtractAddressType(coin, address_raw, &address_type)) { return 2; } ecdsa_get_address_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, prefixBytesByAddressType(address_type) + 20) != 0) { + if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { return 2; } return 0; diff --git a/firmware/transaction.c b/firmware/transaction.c index 54801a3761..2513e58698 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -28,6 +28,7 @@ #include "crypto.h" #include "ripemd160.h" #include "base58.h" +#include "address.h" #include "messages.pb.h" #include "types.pb.h" @@ -91,7 +92,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + prefixBytesByAddressType(coin->address_type), 20); + memcpy(out->script_pubkey.bytes + 3, addr_raw + address_prefix_bytes_len(coin->address_type), 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; @@ -110,7 +111,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefixBytesByAddressType(coin->address_type_p2sh), 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + address_prefix_bytes_len(coin->address_type_p2sh), 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; return 23; @@ -118,14 +119,14 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (in->script_type == OutputScriptType_PAYTOMULTISIG) { uint8_t buf[32]; - size_t prefix_bytes = prefixBytesByAddressType(coin->address_type_p2sh); + size_t prefix_bytes = address_prefix_bytes_len(coin->address_type_p2sh); if (!in->has_multisig) { return 0; } if (compile_script_multisig_hash(&(in->multisig), buf) == 0) { return 0; } - writeAddressPrefix(addr_raw, coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, addr_raw); ripemd160(buf, 32, addr_raw + prefix_bytes); if (needs_confirm) { base58_encode_check(addr_raw, prefix_bytes + 20, in->address, sizeof(in->address)); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index ad73c0d4e7..b05776be77 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit ad73c0d4e73fe138ebbbc39d6a335167ba7c9923 +Subproject commit b05776be77168738d94ef9963019abb4d80a5356 From 7ddccdb7f4999c26292727ac75b6531844ad9bf7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Oct 2016 17:40:35 +0200 Subject: [PATCH 0331/1154] Revert "simplify cryptoMessageVerify call" This reverts commit 3a42032c63ab4c8d2bd1769b25bcc502934376e0. --- firmware/crypto.c | 6 +----- firmware/crypto.h | 2 +- firmware/fsm.c | 5 +++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 1728793b84..92d6e17f43 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -142,7 +142,7 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message return result; } -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) { SHA256_CTX ctx; uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32]; @@ -173,10 +173,6 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes pubkey[0] = 0x02 | (pubkey[64] & 1); } // check if the address is correct - uint32_t address_type; - if (!coinExtractAddressType(coin, address_raw, &address_type)) { - return 2; - } ecdsa_get_address_raw(pubkey, address_type, addr_raw); if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { return 2; diff --git a/firmware/crypto.h b/firmware/crypto.h index 28f11bf05c..b666da376e 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -41,7 +41,7 @@ int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 144b8d1b47..6304857588 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -756,11 +756,12 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) if (!coin) return; layoutProgressSwipe("Verifying", 0); uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - if (!ecdsa_address_decode(msg->address, coin->address_type, addr_raw)) { + uint32_t address_type; + if (!coinExtractAddressType(coin, (const uint8_t *)msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); return; } - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); From dfc543c955fde42cb50a0317bd1689e2701dec59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20B=C3=ADlek?= Date: Thu, 13 Oct 2016 11:39:35 +0200 Subject: [PATCH 0332/1154] Switching address types (#119) Address_type and address_type_p2sh were switched --- firmware/coins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 4853770734..0dfe09e6aa 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -30,8 +30,8 @@ const CoinType coins[COINS_COUNT] = { {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, - {true, "Zcash", true, "ZEC", true, 0x1CB8, true, 1000000, true, 0x1CBD, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, - {true, "Zcash Testnet", true, "TAZ", true, 0x1CBA, true, 1000000, true, 0x1D25, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, + {true, "Zcash", true, "ZEC", true, 0x1CBD, true, 1000000, true, 0x1CB8, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, + {true, "Zcash Testnet", true, "TAZ", true, 0x1D25, true, 1000000, true, 0x1CBA, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, }; const CoinType *coinByShortcut(const char *shortcut) From b57c0ff4301c403c3551ad98e1955011c56d170d Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Thu, 13 Oct 2016 22:32:26 +0300 Subject: [PATCH 0333/1154] Use trezor-crypto ECDH, adding Curve25519 support --- Makefile.include | 1 + firmware/Makefile | 1 + firmware/crypto.c | 19 ------------------- firmware/crypto.h | 2 -- firmware/fsm.c | 5 +++-- vendor/trezor-crypto | 2 +- 6 files changed, 6 insertions(+), 24 deletions(-) diff --git a/Makefile.include b/Makefile.include index 0f46d7d828..7651370950 100644 --- a/Makefile.include +++ b/Makefile.include @@ -49,6 +49,7 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ + -I$(TOP_DIR)vendor/trezor-crypto/curve25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc ifdef APPVER diff --git a/firmware/Makefile b/firmware/Makefile index 9c60e6522a..573a1b01bb 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,6 +28,7 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o +OBJS += ../vendor/trezor-crypto/curve25519-donna/curve25519-donna.o OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o diff --git a/firmware/crypto.c b/firmware/crypto.c index 92d6e17f43..f0d205ca93 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -103,25 +103,6 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); } -int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key) -{ - curve_point point; - const ecdsa_curve *curve = node->curve->params; - if (!ecdsa_read_pubkey(curve, peer_public_key, &point)) { - return 1; - } - bignum256 k; - bn_read_be(node->private_key, &k); - point_multiply(curve, &k, &point, &point); - MEMSET_BZERO(&k, sizeof(k)); - - session_key[0] = 0x04; - bn_write_be(&point.x, session_key + 1); - bn_write_be(&point.y, session_key + 33); - MEMSET_BZERO(&point, sizeof(point)); - return 0; -} - int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; diff --git a/firmware/crypto.h b/firmware/crypto.h index b666da376e..1f211c37f4 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -37,8 +37,6 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoGetECDHSessionKey(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key); - int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 6304857588..b352392cca 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -906,9 +906,10 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); if (!node) return; - if (cryptoGetECDHSessionKey(node, msg->peer_public_key.bytes, resp->session_key.bytes) == 0) { + int result_size = 0; + if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { resp->has_session_key = true; - resp->session_key.size = 65; + resp->session_key.size = result_size; msg_write(MessageType_MessageType_ECDHSessionKey, resp); } else { fsm_sendFailure(FailureType_Failure_Other, "Error getting ECDH session key"); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b05776be77..707c869fb9 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b05776be77168738d94ef9963019abb4d80a5356 +Subproject commit 707c869fb92b78054d75f9f44789502672d5c51d From f0b93b44f586a033eb7b2e1b0ede8c04e7ef7f9a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Oct 2016 02:05:03 +0200 Subject: [PATCH 0334/1154] multibyte addresses can be 40 chars long --- firmware/protob/messages.options | 10 +++++----- firmware/protob/types.options | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 1e1a86f696..9164ce6dba 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -32,7 +32,7 @@ PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 GetAddress.coin_name max_size:17 -Address.address max_size:36 +Address.address max_size:41 EthereumGetAddress.address_n max_count:8 EthereumAddress.address max_size:20 @@ -56,12 +56,12 @@ SignMessage.address_n max_count:8 SignMessage.message max_size:1024 SignMessage.coin_name max_size:17 -VerifyMessage.address max_size:36 +VerifyMessage.address max_size:41 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 VerifyMessage.coin_name max_size:17 -MessageSignature.address max_size:36 +MessageSignature.address max_size:41 MessageSignature.signature max_size:65 EncryptMessage.pubkey max_size:33 @@ -78,7 +78,7 @@ DecryptMessage.nonce max_size:33 DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 DecryptMessage.hmac max_size:8 -DecryptedMessage.address max_size:36 +DecryptedMessage.address max_size:41 DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 @@ -109,7 +109,7 @@ SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 SignIdentity.ecdsa_curve_name max_size:32 -SignedIdentity.address max_size:36 +SignedIdentity.address max_size:41 SignedIdentity.public_key max_size:33 SignedIdentity.signature max_size:65 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 422d9420d5..40f553d3fb 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -12,7 +12,7 @@ TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 -TxOutputType.address max_size:36 +TxOutputType.address max_size:41 TxOutputType.address_n max_count:8 TxOutputType.op_return_data max_size:80 From 771a0c014bd2b777378f559ac40466760ac39bad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Oct 2016 02:06:49 +0200 Subject: [PATCH 0335/1154] update protobuf --- firmware/protob/messages.pb.c | 7 ++++-- firmware/protob/messages.pb.h | 43 ++++++++++++++++++++--------------- firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 26 +++++++++++++-------- vendor/trezor-common | 2 +- 5 files changed, 50 insertions(+), 31 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index c16857f90d..1d7024fc00 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -4,6 +4,7 @@ #include "messages.pb.h" const char GetAddress_coin_name_default[17] = "Bitcoin"; +const InputScriptType GetAddress_script_type_default = InputScriptType_SPENDADDRESS; const char LoadDevice_language_default[17] = "english"; const uint32_t ResetDevice_strength_default = 256u; const char ResetDevice_language_default[17] = "english"; @@ -28,7 +29,7 @@ const pb_field_t GetFeatures_fields[1] = { PB_LAST_FIELD }; -const pb_field_t Features_fields[18] = { +const pb_field_t Features_fields[19] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), @@ -46,6 +47,7 @@ const pb_field_t Features_fields[18] = { PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), PB_FIELD2( 16, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_cached, imported, 0), PB_FIELD2( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), + PB_FIELD2( 18, BOOL , OPTIONAL, STATIC , OTHER, Features, firmware_present, passphrase_cached, 0), PB_LAST_FIELD }; @@ -141,11 +143,12 @@ const pb_field_t PublicKey_fields[3] = { PB_LAST_FIELD }; -const pb_field_t GetAddress_fields[5] = { +const pb_field_t GetAddress_fields[6] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), PB_FIELD2( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), + PB_FIELD2( 5, ENUM , OPTIONAL, STATIC , OTHER, GetAddress, script_type, multisig, &GetAddress_script_type_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 36c92b3c8f..83173d6994 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -130,7 +130,7 @@ typedef struct _WordRequest { } WordRequest; typedef struct _Address { - char address[36]; + char address[41]; } Address; typedef struct { @@ -315,7 +315,7 @@ typedef struct _DecryptedMessage { bool has_message; DecryptedMessage_message_t message; bool has_address; - char address[36]; + char address[41]; } DecryptedMessage; typedef struct { @@ -549,6 +549,8 @@ typedef struct _Features { bool pin_cached; bool has_passphrase_cached; bool passphrase_cached; + bool has_firmware_present; + bool firmware_present; } Features; typedef struct { @@ -569,6 +571,8 @@ typedef struct _GetAddress { bool show_display; bool has_multisig; MultisigRedeemScriptType multisig; + bool has_script_type; + InputScriptType script_type; } GetAddress; typedef struct { @@ -622,7 +626,7 @@ typedef struct { typedef struct _MessageSignature { bool has_address; - char address[36]; + char address[41]; bool has_signature; MessageSignature_signature_t signature; } MessageSignature; @@ -744,7 +748,7 @@ typedef struct { typedef struct _SignedIdentity { bool has_address; - char address[36]; + char address[41]; bool has_public_key; SignedIdentity_public_key_t public_key; bool has_signature; @@ -802,7 +806,7 @@ typedef struct { typedef struct _VerifyMessage { bool has_address; - char address[36]; + char address[41]; bool has_signature; VerifyMessage_signature_t signature; bool has_message; @@ -817,6 +821,7 @@ typedef struct _WordAck { /* Default values for struct fields */ extern const char GetAddress_coin_name_default[17]; +extern const InputScriptType GetAddress_script_type_default; extern const char LoadDevice_language_default[17]; extern const uint32_t ResetDevice_strength_default; extern const char ResetDevice_language_default[17]; @@ -835,7 +840,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -853,7 +858,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Entropy_init_default {{0, {0}}} #define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_default {HDNodeType_init_default, false, ""} -#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default} +#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default, false, InputScriptType_SPENDADDRESS} #define EthereumGetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} #define Address_init_default {""} #define EthereumAddress_init_default {{0, {0}}} @@ -901,7 +906,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -919,7 +924,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Entropy_init_zero {{0, {0}}} #define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} -#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero} +#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero, false, (InputScriptType)0} #define EthereumGetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} #define Address_init_zero {""} #define EthereumAddress_init_zero {{0, {0}}} @@ -1059,11 +1064,13 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Features_imported_tag 15 #define Features_pin_cached_tag 16 #define Features_passphrase_cached_tag 17 +#define Features_firmware_present_tag 18 #define FirmwareUpload_payload_tag 1 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 #define GetAddress_multisig_tag 4 +#define GetAddress_script_type_tag 5 #define GetECDHSessionKey_identity_tag 1 #define GetECDHSessionKey_peer_public_key_tag 2 #define GetECDHSessionKey_ecdsa_curve_name_tag 3 @@ -1138,7 +1145,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; extern const pb_field_t GetFeatures_fields[1]; -extern const pb_field_t Features_fields[18]; +extern const pb_field_t Features_fields[19]; extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[5]; extern const pb_field_t ChangePin_fields[2]; @@ -1156,7 +1163,7 @@ extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; extern const pb_field_t GetPublicKey_fields[4]; extern const pb_field_t PublicKey_fields[3]; -extern const pb_field_t GetAddress_fields[5]; +extern const pb_field_t GetAddress_fields[6]; extern const pb_field_t EthereumGetAddress_fields[3]; extern const pb_field_t Address_fields[2]; extern const pb_field_t EthereumAddress_fields[2]; @@ -1206,7 +1213,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (254 + 8*CoinType_size) +#define Features_size (257 + 8*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 @@ -1224,9 +1231,9 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define Entropy_size 1027 #define GetPublicKey_size 84 #define PublicKey_size (121 + HDNodeType_size) -#define GetAddress_size (75 + MultisigRedeemScriptType_size) +#define GetAddress_size (81 + MultisigRedeemScriptType_size) #define EthereumGetAddress_size 50 -#define Address_size 38 +#define Address_size 43 #define EthereumAddress_size 22 #define WipeDevice_size 0 #define LoadDevice_size (320 + HDNodeType_size) @@ -1237,12 +1244,12 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define WordRequest_size 0 #define WordAck_size 14 #define SignMessage_size 1094 -#define VerifyMessage_size 1151 -#define MessageSignature_size 105 +#define VerifyMessage_size 1156 +#define MessageSignature_size 110 #define EncryptMessage_size 1131 #define EncryptedMessage_size 1168 #define DecryptMessage_size 1216 -#define DecryptedMessage_size 1065 +#define DecryptedMessage_size 1070 #define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 @@ -1255,7 +1262,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define EthereumTxRequest_size 80 #define EthereumTxAck_size 1027 #define SignIdentity_size (558 + IdentityType_size) -#define SignedIdentity_size 140 +#define SignedIdentity_size 145 #define GetECDHSessionKey_size (107 + IdentityType_size) #define ECDHSessionKey_size 67 #define SetU2FCounter_size 6 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 89c11a18c8..04ef17f7bb 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -47,7 +47,7 @@ const pb_field_t MultisigRedeemScriptType_fields[4] = { PB_LAST_FIELD }; -const pb_field_t TxInputType_fields[8] = { +const pb_field_t TxInputType_fields[9] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), @@ -55,6 +55,7 @@ const pb_field_t TxInputType_fields[8] = { PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), + PB_FIELD2( 8, UINT64 , OPTIONAL, STATIC , OTHER, TxInputType, amount, multisig, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index e8318e1932..de87ac94f7 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -28,12 +28,17 @@ typedef enum _OutputScriptType { OutputScriptType_PAYTOADDRESS = 0, OutputScriptType_PAYTOSCRIPTHASH = 1, OutputScriptType_PAYTOMULTISIG = 2, - OutputScriptType_PAYTOOPRETURN = 3 + OutputScriptType_PAYTOOPRETURN = 3, + OutputScriptType_PAYTOWITNESS = 4, + OutputScriptType_PAYTOP2SHWITNESS = 5 } OutputScriptType; typedef enum _InputScriptType { InputScriptType_SPENDADDRESS = 0, - InputScriptType_SPENDMULTISIG = 1 + InputScriptType_SPENDMULTISIG = 1, + InputScriptType_EXTERNAL = 2, + InputScriptType_SPENDWITNESS = 3, + InputScriptType_SPENDP2SHWITNESS = 4 } InputScriptType; typedef enum _RequestType { @@ -208,6 +213,8 @@ typedef struct _TxInputType { InputScriptType script_type; bool has_multisig; MultisigRedeemScriptType multisig; + bool has_amount; + uint64_t amount; } TxInputType; typedef struct { @@ -217,7 +224,7 @@ typedef struct { typedef struct _TxOutputType { bool has_address; - char address[36]; + char address[41]; size_t address_n_count; uint32_t address_n[8]; uint64_t amount; @@ -265,7 +272,7 @@ extern const uint32_t IdentityType_index_default; #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, ""} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} -#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} +#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} #define TxOutputBinType_init_default {0, {0, {0}}} #define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} @@ -276,7 +283,7 @@ extern const uint32_t IdentityType_index_default; #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, ""} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} -#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} +#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} #define TxOutputBinType_init_zero {0, {0, {0}}} #define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} @@ -324,6 +331,7 @@ extern const uint32_t IdentityType_index_default; #define TxInputType_sequence_tag 5 #define TxInputType_script_type_tag 6 #define TxInputType_multisig_tag 7 +#define TxInputType_amount_tag 8 #define TxOutputType_address_tag 1 #define TxOutputType_address_n_tag 2 #define TxOutputType_amount_tag 3 @@ -347,7 +355,7 @@ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; extern const pb_field_t CoinType_fields[9]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; -extern const pb_field_t TxInputType_fields[8]; +extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TransactionType_fields[8]; @@ -360,10 +368,10 @@ extern const pb_field_t IdentityType_fields[7]; #define HDNodePathType_size 171 #define CoinType_size 99 #define MultisigRedeemScriptType_size 3741 -#define TxInputType_size 5497 -#define TxOutputType_size 3929 +#define TxInputType_size 5508 +#define TxOutputType_size 3934 #define TxOutputBinType_size 534 -#define TransactionType_size 9993 +#define TransactionType_size 10009 #define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 #define IdentityType_size 416 diff --git a/vendor/trezor-common b/vendor/trezor-common index c2a0b255ff..1e74952359 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit c2a0b255ff1ba174085ebe76c46f8e049f85d197 +Subproject commit 1e749523593506f2f268c038225f2c847ad2d0ef From 68a1bcc9081066fe840a9a07fe3346db76dca396 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 17 Oct 2016 19:08:02 +0300 Subject: [PATCH 0336/1154] Add specific layout for GPG signature (#122) Following ECDH usage of layoutDecryptIdentity (which shows "GPG decrypt for:") this commit adds a specific case for layoutSignIdentity, showing "GPG sign for:", instead of "GPG login to:" (which is less appropriate in the GPG context). --- firmware/layout2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/layout2.c b/firmware/layout2.c index c26d0fcab6..ca226ca87d 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -304,6 +304,8 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) if (identity->has_proto && identity->proto[0]) { if (strcmp(identity->proto, "https") == 0) { strlcpy(row_proto, "Web sign in to:", sizeof(row_proto)); + } else if (strcmp(identity->proto, "gpg") == 0) { + strlcpy(row_proto, "GPG sign for:", sizeof(row_proto)); } else { strlcpy(row_proto, identity->proto, sizeof(row_proto)); char *p = row_proto; From c288a0e328428572de99e4848184c1a2b0661e79 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Oct 2016 09:37:46 +0200 Subject: [PATCH 0337/1154] implement TXEXTRADATA transaction RequestType --- firmware/protob/types.options | 1 + firmware/protob/types.pb.c | 8 +++-- firmware/protob/types.pb.h | 36 +++++++++++++++++------ firmware/signing.c | 55 ++++++++++++++++++++++++++++++++--- firmware/transaction.c | 24 ++++++++++++++- firmware/transaction.h | 7 ++++- vendor/trezor-common | 2 +- 7 files changed, 115 insertions(+), 18 deletions(-) diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 40f553d3fb..536e91ab48 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -21,6 +21,7 @@ TxOutputBinType.script_pubkey max_size:520 TransactionType.inputs max_count:1 TransactionType.bin_outputs max_count:1 TransactionType.outputs max_count:1 +TransactionType.extra_data max_size:1024 TxRequestDetailsType.tx_hash max_size:32 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 04ef17f7bb..67148cacd7 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -75,7 +75,7 @@ const pb_field_t TxOutputBinType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t TransactionType_fields[8] = { +const pb_field_t TransactionType_fields[10] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), @@ -83,12 +83,16 @@ const pb_field_t TransactionType_fields[8] = { PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), + PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, TransactionType, extra_data, outputs_cnt, 0), + PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, extra_data_len, extra_data, 0), PB_LAST_FIELD }; -const pb_field_t TxRequestDetailsType_fields[3] = { +const pb_field_t TxRequestDetailsType_fields[5] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), + PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_len, tx_hash, 0), + PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_offset, extra_data_len, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index de87ac94f7..a7dd51e8a2 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -45,7 +45,8 @@ typedef enum _RequestType { RequestType_TXINPUT = 0, RequestType_TXOUTPUT = 1, RequestType_TXMETA = 2, - RequestType_TXFINISHED = 3 + RequestType_TXFINISHED = 3, + RequestType_TXEXTRADATA = 4 } RequestType; typedef enum _ButtonRequestType { @@ -149,6 +150,10 @@ typedef struct _TxRequestDetailsType { uint32_t request_index; bool has_tx_hash; TxRequestDetailsType_tx_hash_t tx_hash; + bool has_extra_data_len; + uint32_t extra_data_len; + bool has_extra_data_offset; + uint32_t extra_data_offset; } TxRequestDetailsType; typedef struct { @@ -235,6 +240,11 @@ typedef struct _TxOutputType { TxOutputType_op_return_data_t op_return_data; } TxOutputType; +typedef struct { + size_t size; + uint8_t bytes[1024]; +} TransactionType_extra_data_t; + typedef struct _TransactionType { bool has_version; uint32_t version; @@ -250,6 +260,10 @@ typedef struct _TransactionType { uint32_t inputs_cnt; bool has_outputs_cnt; uint32_t outputs_cnt; + bool has_extra_data; + TransactionType_extra_data_t extra_data; + bool has_extra_data_len; + uint32_t extra_data_len; } TransactionType; /* Extensions */ @@ -275,8 +289,8 @@ extern const uint32_t IdentityType_index_default; #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} #define TxOutputBinType_init_default {0, {0, {0}}} -#define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} -#define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} +#define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0, false, {0, {0}}, false, 0} +#define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}, false, 0, false, 0} #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} @@ -286,8 +300,8 @@ extern const uint32_t IdentityType_index_default; #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} #define TxOutputBinType_init_zero {0, {0, {0}}} -#define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} -#define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} +#define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0, false, {0, {0}}, false, 0} +#define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}, false, 0, false, 0} #define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}} #define IdentityType_init_zero {false, "", false, "", false, "", false, "", false, "", false, 0} @@ -316,6 +330,8 @@ extern const uint32_t IdentityType_index_default; #define TxOutputBinType_script_pubkey_tag 2 #define TxRequestDetailsType_request_index_tag 1 #define TxRequestDetailsType_tx_hash_tag 2 +#define TxRequestDetailsType_extra_data_len_tag 3 +#define TxRequestDetailsType_extra_data_offset_tag 4 #define TxRequestSerializedType_signature_index_tag 1 #define TxRequestSerializedType_signature_tag 2 #define TxRequestSerializedType_serialized_tx_tag 3 @@ -345,6 +361,8 @@ extern const uint32_t IdentityType_index_default; #define TransactionType_lock_time_tag 4 #define TransactionType_inputs_cnt_tag 6 #define TransactionType_outputs_cnt_tag 7 +#define TransactionType_extra_data_tag 8 +#define TransactionType_extra_data_len_tag 9 #define wire_in_tag 50002 #define wire_out_tag 50003 #define wire_debug_in_tag 50004 @@ -358,8 +376,8 @@ extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; extern const pb_field_t TxOutputBinType_fields[3]; -extern const pb_field_t TransactionType_fields[8]; -extern const pb_field_t TxRequestDetailsType_fields[3]; +extern const pb_field_t TransactionType_fields[10]; +extern const pb_field_t TxRequestDetailsType_fields[5]; extern const pb_field_t TxRequestSerializedType_fields[4]; extern const pb_field_t IdentityType_fields[7]; @@ -371,8 +389,8 @@ extern const pb_field_t IdentityType_fields[7]; #define TxInputType_size 5508 #define TxOutputType_size 3934 #define TxOutputBinType_size 534 -#define TransactionType_size 10009 -#define TxRequestDetailsType_size 40 +#define TransactionType_size 11042 +#define TxRequestDetailsType_size 52 #define TxRequestSerializedType_size 2132 #define IdentityType_size 416 diff --git a/firmware/signing.c b/firmware/signing.c index 4648536619..805d36b137 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -38,6 +38,7 @@ enum { STAGE_REQUEST_2_PREV_META, STAGE_REQUEST_2_PREV_INPUT, STAGE_REQUEST_2_PREV_OUTPUT, + STAGE_REQUEST_2_PREV_EXTRADATA, STAGE_REQUEST_3_OUTPUT, STAGE_REQUEST_4_INPUT, STAGE_REQUEST_4_OUTPUT, @@ -85,6 +86,7 @@ foreach I (idx1): foreach prevhash O (idx2): Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT Add amount of prevhash O (which is amount of I) + Request prevhash extra data (if applicable) STAGE_REQUEST_2_PREV_EXTRADATA Calculate hash of streamed tx, compare to prevhash I foreach O (idx1): Request O STAGE_REQUEST_3_OUTPUT @@ -173,6 +175,22 @@ void send_req_2_prev_output(void) msg_write(MessageType_MessageType_TxRequest, &resp); } +void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) +{ + signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; + resp.has_request_type = true; + resp.request_type = RequestType_TXEXTRADATA; + resp.has_details = true; + resp.details.has_extra_data_offset = true; + resp.details.extra_data_offset = chunk_offset; + resp.details.has_extra_data_len = true; + resp.details.extra_data_len = chunk_len; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); +} + void send_req_3_output(void) { signing_stage = STAGE_REQUEST_3_OUTPUT; @@ -249,7 +267,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp multisig_fp_set = false; multisig_fp_mismatch = false; - tx_init(&to, inputs_count, outputs_count, version, lock_time, false); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, false); sha256_Init(&tc); sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); @@ -261,6 +279,8 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp send_req_1_input(); } +#define MIN(a,b) (((a)<(b))?(a):(b)) + void signing_txack(TransactionType *tx) { if (!signing) { @@ -311,7 +331,7 @@ void signing_txack(TransactionType *tx) send_req_2_prev_meta(); return; case STAGE_REQUEST_2_PREV_META: - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, false); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; send_req_2_prev_input(); @@ -345,8 +365,35 @@ void signing_txack(TransactionType *tx) /* Check prevtx of next input */ idx2++; send_req_2_prev_output(); + } else { // last output + if (tp.extra_data_len > 0) { // has extra data + send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); + return; + } + tx_hash_final(&tp, hash, true); + if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); + signing_abort(); + return; + } + if (idx1 < inputs_count - 1) { + idx1++; + send_req_1_input(); + } else { + idx1 = 0; + send_req_3_output(); + } + } + return; + case STAGE_REQUEST_2_PREV_EXTRADATA: + if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize extra data"); + signing_abort(); + return; + } + if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining + send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received)); } else { - /* Check next output */ tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); @@ -453,7 +500,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, true); sha256_Init(&tc); sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); diff --git a/firmware/transaction.c b/firmware/transaction.c index 2513e58698..c4667b963b 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -407,7 +407,27 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) return r; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type) +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen) +{ + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs < tx->outputs_len) { + // not all inputs provided + return 0; + } + if (tx->extra_data_received + datalen > tx->extra_data_len) { + // we are receiving too much data + return 0; + } + sha256_Update(&(tx->ctx), data, datalen); + tx->extra_data_received += datalen; + tx->size += datalen; + return datalen; +} + +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; @@ -416,6 +436,8 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->add_hash_type = add_hash_type; tx->have_inputs = 0; tx->have_outputs = 0; + tx->extra_data_len = extra_data_len; + tx->extra_data_received = 0; tx->size = 0; sha256_Init(&(tx->ctx)); } diff --git a/firmware/transaction.h b/firmware/transaction.h index bd64baa4f2..f9d76f8200 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -36,6 +36,10 @@ typedef struct { uint32_t have_inputs; uint32_t have_outputs; + + uint32_t extra_data_len; + uint32_t extra_data_received; + uint32_t size; SHA256_CTX ctx; @@ -50,9 +54,10 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); diff --git a/vendor/trezor-common b/vendor/trezor-common index 1e74952359..20c1d05f9d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 1e749523593506f2f268c038225f2c847ad2d0ef +Subproject commit 20c1d05f9de778e28726690c4969e6ce92296ce4 From 2daab8cf02f5760ad65feb6a08534981cf497342 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 20 Oct 2016 15:27:34 +0200 Subject: [PATCH 0338/1154] add coins-gen.py script and generate coins.c using that script --- firmware/coins-gen.py | 44 +++++++++++++++++++++++++++++++++++++++++++ firmware/coins.c | 16 ++++++++-------- 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100755 firmware/coins-gen.py diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py new file mode 100755 index 0000000000..d3109ec8d1 --- /dev/null +++ b/firmware/coins-gen.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import json + +coins = json.load(open('../vendor/trezor-common/coins.json', 'r')) + +fields = [] + +for c in coins: + fields.append([ + 'true' if c['coin_name'] is not None else 'false', + '"%s"' % c['coin_name'] if c['coin_name'] is not None else 'NULL', + + 'true' if c['coin_shortcut'] is not None else 'false', + '"%s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', + + 'true' if c['address_type'] is not None else 'false', + '%d' % c['address_type'] if c['address_type'] is not None else '0', + + 'true' if c['maxfee_kb'] is not None else 'false', + '%d' % c['maxfee_kb'] if c['maxfee_kb'] is not None else '0', + + 'true' if c['address_type_p2sh'] is not None else 'false', + '%d' % c['address_type_p2sh'] if c['address_type_p2sh'] is not None else '0', + + 'true' if c['address_type_p2wpkh'] is not None else 'false', + '%d' % c['address_type_p2wpkh'] if c['address_type_p2wpkh'] is not None else '0', + + 'true' if c['address_type_p2wsh'] is not None else 'false', + '%d' % c['address_type_p2wsh'] if c['address_type_p2wsh'] is not None else '0', + + 'true' if c['signed_message_header'] is not None else 'false', + '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', + ]) + +for j in range(len(fields[0])): + l = max([len(x[j]) for x in fields]) + 1 + for i in range(len(fields)): + if fields[i][j][0] in '0123456789': + fields[i][j] = (fields[i][j] + ',').rjust(l) + else: + fields[i][j] = (fields[i][j] + ',').ljust(l) + +for row in fields: + print('\t{' + ' '.join(row) + ' },') diff --git a/firmware/coins.c b/firmware/coins.c index 0dfe09e6aa..5c862f80a2 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -24,14 +24,14 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n"}, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n"}, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n"}, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n"}, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n"}, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n"}, - {true, "Zcash", true, "ZEC", true, 0x1CBD, true, 1000000, true, 0x1CB8, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, - {true, "Zcash Testnet", true, "TAZ", true, 0x1D25, true, 1000000, true, 0x1CBA, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n"}, + {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", }, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", }, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", }, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", }, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", }, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", }, + {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", }, + {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", }, }; const CoinType *coinByShortcut(const char *shortcut) From e9f0706c2ec6bb25e09ba4373ad064912f0a2285 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Oct 2016 13:20:57 +0200 Subject: [PATCH 0339/1154] fix prevtx hashing when input count is 0 --- firmware/signing.c | 7 ++++++- firmware/transaction.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index 805d36b137..3743092309 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -334,7 +334,12 @@ void signing_txack(TransactionType *tx) tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, false); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; - send_req_2_prev_input(); + if (tp.inputs_len > 0) { + send_req_2_prev_input(); + } else { + tx_serialize_header_hash(&tp); + send_req_2_prev_output(); + } return; case STAGE_REQUEST_2_PREV_INPUT: progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; diff --git a/firmware/transaction.h b/firmware/transaction.h index f9d76f8200..71ec1c1137 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -55,6 +55,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type); +uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); From 0bb7f16b7891e88204b4e11f62e810322372e722 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 24 Oct 2016 13:41:10 +0300 Subject: [PATCH 0340/1154] crypto: allow Ed25519 signing larger digests (#124) --- firmware/crypto.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index f0d205ca93..06019fbe2d 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -95,12 +95,18 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { - // GPG should sign a SHA256 digest of the original message. - if (message_len != 32) { - return 1; - } signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); + const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); + if (ed25519_curve_info && node->curve == ed25519_curve_info) { + // GPG supports variable size digest for Ed25519 signatures + return hdnode_sign(node, message, message_len, signature + 1, NULL, NULL); + } else { + // Ensure 256-bit digest before proceeding + if (message_len != 32) { + return 1; + } + return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); + } } int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) From ea35b4bfe7fe1419a630acf498595a0eec02a7fe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 20:55:45 +0200 Subject: [PATCH 0341/1154] update trezor-crypto --- firmware/Makefile | 2 +- vendor/trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 573a1b01bb..4fe85288d1 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,7 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o -OBJS += ../vendor/trezor-crypto/curve25519-donna/curve25519-donna.o +OBJS += ../vendor/trezor-crypto/curve25519-donna/curve25519.o OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 707c869fb9..fa8772dfee 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 707c869fb92b78054d75f9f44789502672d5c51d +Subproject commit fa8772dfee59f426fda238553f4613bcb7d30636 From 0b51d060d87774126181058beefcfeccc5ae436c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 26 Aug 2016 17:50:10 +0100 Subject: [PATCH 0342/1154] allow ClearSession purely via confirm button Holding confirm button at home screen asks user whether they wish to lock the TREZOR (clear the cached PIN and passphrase and show the screensaver). This is identical behaviour to the ClearSession message. --- firmware/layout2.h | 2 ++ firmware/trezor.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/firmware/layout2.h b/firmware/layout2.h index 237207cb44..458fa55fda 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -24,6 +24,8 @@ #include "types.pb.h" #include "bitmaps.h" +extern void *layoutLast; + void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); diff --git a/firmware/trezor.c b/firmware/trezor.c index e54d81c7cc..dbab767bf8 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -27,6 +27,7 @@ #include "layout.h" #include "layout2.h" #include "rng.h" +#include "buttons.h" uint32_t __stack_chk_guard; @@ -36,6 +37,46 @@ void __attribute__((noreturn)) __stack_chk_fail(void) for (;;) {} // loop forever } +void check_lock_screen(void) +{ + buttonUpdate(); + + // wake from screensaver on any button + if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { + layoutHome(); + return; + } + + // button held for long enough + if (layoutLast == layoutHome && button.NoDown >= 500000) { + + layoutDialog(&bmp_icon_question, "Cancel", "Lock Device", NULL, "Do you really want to", "lock your TREZOR?", NULL, NULL, NULL, NULL); + + // wait until NoButton is released + usbTiny(1); + do { + usbDelay(3300); + buttonUpdate(); + } while (!button.NoUp); + + // wait for confirmation/cancellation of the dialog + do { + usbDelay(3300); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + usbTiny(0); + + if (button.YesUp) { + // lock the screen + session_clear(true); + layoutScreensaver(); + } else { + // resume homescreen + layoutHome(); + } + } +} + int main(void) { __stack_chk_guard = random32(); @@ -61,6 +102,7 @@ int main(void) usbInit(); for (;;) { usbPoll(); + check_lock_screen(); } return 0; From f8ad9fc74201c4c84de94a4dd9831dc54cd7cce9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Oct 2016 17:02:02 +0200 Subject: [PATCH 0343/1154] fix Verify (by introducing coinExtractAddressType) --- firmware/coins.c | 23 ++++++++++++++++++----- firmware/coins.h | 3 ++- firmware/fsm.c | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 5c862f80a2..e6056da420 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -20,6 +20,8 @@ #include #include "coins.h" #include "address.h" +#include "ecdsa.h" +#include "base58.h" // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order @@ -69,21 +71,32 @@ const CoinType *coinByAddressType(uint32_t address_type) return 0; } -bool coinExtractAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type) +bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *address_type) { - if (coin->has_address_type && address_check_prefix(addr, coin->address_type)) { + if (!addr) return false; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int len = base58_decode_check(addr, addr_raw, MAX_ADDR_RAW_SIZE); + if (len >= 21) { + return coinExtractAddressTypeRaw(coin, addr_raw, address_type); + } + return false; +} + +bool coinExtractAddressTypeRaw(const CoinType *coin, const uint8_t *addr_raw, uint32_t *address_type) +{ + if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { *address_type = coin->address_type; return true; } - if (coin->has_address_type_p2sh && address_check_prefix(addr, coin->address_type_p2sh)) { + if (coin->has_address_type_p2sh && address_check_prefix(addr_raw, coin->address_type_p2sh)) { *address_type = coin->address_type_p2sh; return true; } - if (coin->has_address_type_p2wpkh && address_check_prefix(addr, coin->address_type_p2wpkh)) { + if (coin->has_address_type_p2wpkh && address_check_prefix(addr_raw, coin->address_type_p2wpkh)) { *address_type = coin->address_type_p2wpkh; return true; } - if (coin->has_address_type_p2wsh && address_check_prefix(addr, coin->address_type_p2wsh)) { + if (coin->has_address_type_p2wsh && address_check_prefix(addr_raw, coin->address_type_p2wsh)) { *address_type = coin->address_type_p2wsh; return true; } diff --git a/firmware/coins.h b/firmware/coins.h index 69cb002fee..46a70a7720 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -29,6 +29,7 @@ extern const CoinType coins[COINS_COUNT]; const CoinType *coinByShortcut(const char *shortcut); const CoinType *coinByName(const char *name); const CoinType *coinByAddressType(uint32_t address_type); -bool coinExtractAddressType(const CoinType *coin, const uint8_t *addr, uint32_t *address_type); +bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *address_type); +bool coinExtractAddressTypeRaw(const CoinType *coin, const uint8_t *addr_raw, uint32_t *address_type); #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index b352392cca..04225a2775 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -754,13 +754,13 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) } const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - layoutProgressSwipe("Verifying", 0); uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint32_t address_type; - if (!coinExtractAddressType(coin, (const uint8_t *)msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { + if (!coinExtractAddressType(coin, msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); return; } + layoutProgressSwipe("Verifying", 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { From 592f3c9afe8a4d0b92ece33acef380f1e1344dae Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Oct 2016 17:45:30 +0200 Subject: [PATCH 0344/1154] lock screen after 10 minutes of inactivity --- firmware/trezor.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index dbab767bf8..487a5e5c5a 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -37,18 +37,21 @@ void __attribute__((noreturn)) __stack_chk_fail(void) for (;;) {} // loop forever } +static uint32_t saver_counter = 0; + void check_lock_screen(void) { buttonUpdate(); // wake from screensaver on any button if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { + saver_counter = 0; layoutHome(); return; } - // button held for long enough - if (layoutLast == layoutHome && button.NoDown >= 500000) { + // button held for long enough (2 seconds) + if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { layoutDialog(&bmp_icon_question, "Cancel", "Lock Device", NULL, "Do you really want to", "lock your TREZOR?", NULL, NULL, NULL, NULL); @@ -75,6 +78,19 @@ void check_lock_screen(void) layoutHome(); } } + + // if homescreen is shown for longer than 10 minutes, lock too + if (layoutLast == layoutHome) { + saver_counter++; + if (saver_counter > 285000 * 60 * 10) { + // lock the screen + session_clear(true); + layoutScreensaver(); + saver_counter = 0; + } + } else { + saver_counter = 0; + } } int main(void) From ae37ea8a9a2ab96e60714451a7a9502e0ef1ffc9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 26 Oct 2016 18:06:13 +0200 Subject: [PATCH 0345/1154] bump version, add changelog --- ChangeLog | 84 +++++++++++++++++++++++++++++++++++++++++++++++ firmware/trezor.h | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..8e2842eb8d --- /dev/null +++ b/ChangeLog @@ -0,0 +1,84 @@ +Version 1.4.1 +* Stable release, optional update +* Support for Zcash JoinSplit transactions +* Enable device lock after 10 minutes of inactivity +* Enable device lock by pressing left button for 2 seconds +* Confirm dialog for U2F counter change + +Version 1.4.0 +* Stable release, optional update +* U2F support +* Ethereum support +* GPG decryption support +* Zcash support + +Version 1.3.6 +* Stable release, optional update +* Enable advanced transactions such as ones with REPLACE-BY-FEE and CHECKLOCKTIMEVERIFY +* Fix message signing for altcoins +* Message verification now shows address +* Enable GPG signing support +* Enable Ed25519 curve (for SSH and GPG) +* Use separate deterministic hierarchy for NIST256P1 and Ed25519 curves +* Users using SSH already need to regenerate their keys using the new firmware!!! + +Version 1.3.5 +* Stable release, optional update +* Double size font for recovery words during the device setup +* Optimizations for simultaneous access when more applications try communicate with the device + +Version 1.3.4 +* Stable release, optional update +* Screensaver active on ClearSession message +* Support for NIST P-256 curve +* Updated SignIdentity to v2 format +* Show seconds counter during PIN lockdown +* Updated maxfee per kb for coins + +Version 1.3.3 +* Stable release, optional update +* Ask for PIN on GetAddress and GetPublicKey +* Signing speed improved + +Version 1.3.2 +* Stable release, optional update +* Fix check during transaction streaming +* Login feature via SignIdentity message +* GetAddress for multisig shows M of N description +* PIN checking in constant time + +Version 1.3.1 +* Stable release, optional update +* Optimized signing speed +* Enabled OP_RETURN +* Added option to change home screen +* Moved fee calculation before any signing +* Made PIN delay increase immune against hardware hacking + +Version 1.3.0 +* Stable release, optional update +* Added multisig support +* Added visual validation of receiving address +* Added ECIES encryption capabilities + +Version 1.2.1 +* Stable release, mandatory update +* Added stack overflow protection +* Added compatibility with TREZOR Bridge + +Version 1.2.0 +* Stable release, optional update +* Fix false positives for fee warning +* Better UI for signing/verifying messages +* Smaller firmware size + +Version 1.1.0 +* Stable release, optional update +* Minor UI fixes +* Better handling of unexpected messages +* Added AES support + +Version 1.0.0 +* Stable release, mandatory update +* Added support for streaming of transactions into the device +* Removed all current limits on size of signed transaction diff --git a/firmware/trezor.h b/firmware/trezor.h index 31877dca3e..72cc0fb9ce 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 4 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) From 4471c6e0e6944024f60965ba6267337e367a7f4d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Oct 2016 11:56:11 +0100 Subject: [PATCH 0346/1154] show different dialog when U2F client uses bogus appid --- firmware/layout2.c | 2 +- firmware/u2f.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index ca226ca87d..e7d49262ab 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -389,5 +389,5 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico if (!appicon) { appicon = &bmp_icon_question; } - layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", "", appname, "", NULL); + layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL); } diff --git a/firmware/u2f.c b/firmware/u2f.c index 942ef9bf79..d8b93135fc 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -62,6 +62,10 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' #define KEY_PATH_ENTRIES (1 + KEY_PATH_LEN / sizeof(uint32_t)) +// Defined as UsbSignHandler.BOGUS_APP_ID_HASH +// in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 +#define BOGUS_APPID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + // Auth/Register request state machine typedef enum { INIT = 0, @@ -569,10 +573,14 @@ void u2f_register(const APDU *a) getDerivedNode(NULL, 0); // error: testof-user-presence is required buttonUpdate(); // Clear button state - const char *appname; - const BITMAP *appicon; - getReadableAppId(req->appId, &appname, &appicon); - layoutU2FDialog("Register", appname, appicon); + if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { + layoutDialog(&bmp_icon_warning, NULL, "OK", NULL, "Another U2F device", "was used to register", "in this application.", NULL, NULL, NULL); + } else { + const char *appname; + const BITMAP *appicon; + getReadableAppId(req->appId, &appname, &appicon); + layoutU2FDialog("Register", appname, appicon); + } last_req_state = REG; } From 71890e4edf6b3b1a705b4e4c28968b471c0f2980 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Oct 2016 16:20:15 +0100 Subject: [PATCH 0347/1154] implement u2f_counter in LoadDevice, Recoverydevice and ResetDevice messages --- firmware/fsm.c | 6 ++++-- firmware/protob/messages.pb.c | 9 ++++++--- firmware/protob/messages.pb.h | 33 +++++++++++++++++++++------------ firmware/recovery.c | 3 ++- firmware/recovery.h | 2 +- firmware/reset.c | 3 ++- firmware/reset.h | 2 +- firmware/storage.c | 4 ++++ vendor/trezor-common | 2 +- 9 files changed, 42 insertions(+), 22 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 04225a2775..ca3c997cdc 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -384,7 +384,8 @@ void fsm_msgResetDevice(ResetDevice *msg) msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0 + msg->has_label ? msg->label : 0, + msg->has_u2f_counter ? msg->u2f_counter : 0 ); } @@ -1055,7 +1056,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist ? msg->enforce_wordlist : false + msg->has_enforce_wordlist ? msg->enforce_wordlist : false, + msg->has_u2f_counter ? msg->u2f_counter : 0 ); } diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 1d7024fc00..7193d53704 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -172,7 +172,7 @@ const pb_field_t WipeDevice_fields[1] = { PB_LAST_FIELD }; -const pb_field_t LoadDevice_fields[8] = { +const pb_field_t LoadDevice_fields[9] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), @@ -180,16 +180,18 @@ const pb_field_t LoadDevice_fields[8] = { PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), + PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, LoadDevice, u2f_counter, skip_checksum, 0), PB_LAST_FIELD }; -const pb_field_t ResetDevice_fields[7] = { +const pb_field_t ResetDevice_fields[8] = { PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), + PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, u2f_counter, label, 0), PB_LAST_FIELD }; @@ -202,13 +204,14 @@ const pb_field_t EntropyAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t RecoveryDevice_fields[7] = { +const pb_field_t RecoveryDevice_fields[8] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), + PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, enforce_wordlist, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 83173d6994..7123f4495b 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -617,6 +617,8 @@ typedef struct _LoadDevice { char label[33]; bool has_skip_checksum; bool skip_checksum; + bool has_u2f_counter; + uint32_t u2f_counter; } LoadDevice; typedef struct { @@ -674,6 +676,8 @@ typedef struct _RecoveryDevice { char label[33]; bool has_enforce_wordlist; bool enforce_wordlist; + bool has_u2f_counter; + uint32_t u2f_counter; } RecoveryDevice; typedef struct _ResetDevice { @@ -689,6 +693,8 @@ typedef struct _ResetDevice { char language[17]; bool has_label; char label[33]; + bool has_u2f_counter; + uint32_t u2f_counter; } ResetDevice; typedef struct _SetU2FCounter { @@ -863,11 +869,11 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Address_init_default {""} #define EthereumAddress_init_default {{0, {0}}} #define WipeDevice_init_default {0} -#define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0} -#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, ""} +#define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0, false, 0} +#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} -#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0} #define WordRequest_init_default {0} #define WordAck_init_default {""} #define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} @@ -929,11 +935,11 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Address_init_zero {""} #define EthereumAddress_init_zero {{0, {0}}} #define WipeDevice_init_zero {0} -#define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0} -#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, ""} +#define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0, false, 0} +#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0} #define EntropyRequest_init_zero {0} #define EntropyAck_init_zero {false, {0, {0}}} -#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} #define WordRequest_init_zero {0} #define WordAck_init_zero {""} #define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} @@ -1085,6 +1091,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define LoadDevice_language_tag 5 #define LoadDevice_label_tag 6 #define LoadDevice_skip_checksum_tag 7 +#define LoadDevice_u2f_counter_tag 8 #define MessageSignature_address_tag 1 #define MessageSignature_signature_tag 2 #define PassphraseAck_passphrase_tag 1 @@ -1102,12 +1109,14 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define RecoveryDevice_language_tag 4 #define RecoveryDevice_label_tag 5 #define RecoveryDevice_enforce_wordlist_tag 6 +#define RecoveryDevice_u2f_counter_tag 7 #define ResetDevice_display_random_tag 1 #define ResetDevice_strength_tag 2 #define ResetDevice_passphrase_protection_tag 3 #define ResetDevice_pin_protection_tag 4 #define ResetDevice_language_tag 5 #define ResetDevice_label_tag 6 +#define ResetDevice_u2f_counter_tag 7 #define SetU2FCounter_u2f_counter_tag 1 #define SignIdentity_identity_tag 1 #define SignIdentity_challenge_hidden_tag 2 @@ -1168,11 +1177,11 @@ extern const pb_field_t EthereumGetAddress_fields[3]; extern const pb_field_t Address_fields[2]; extern const pb_field_t EthereumAddress_fields[2]; extern const pb_field_t WipeDevice_fields[1]; -extern const pb_field_t LoadDevice_fields[8]; -extern const pb_field_t ResetDevice_fields[7]; +extern const pb_field_t LoadDevice_fields[9]; +extern const pb_field_t ResetDevice_fields[8]; extern const pb_field_t EntropyRequest_fields[1]; extern const pb_field_t EntropyAck_fields[2]; -extern const pb_field_t RecoveryDevice_fields[7]; +extern const pb_field_t RecoveryDevice_fields[8]; extern const pb_field_t WordRequest_fields[1]; extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; @@ -1236,11 +1245,11 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define Address_size 43 #define EthereumAddress_size 22 #define WipeDevice_size 0 -#define LoadDevice_size (320 + HDNodeType_size) -#define ResetDevice_size 66 +#define LoadDevice_size (326 + HDNodeType_size) +#define ResetDevice_size 72 #define EntropyRequest_size 0 #define EntropyAck_size 131 -#define RecoveryDevice_size 66 +#define RecoveryDevice_size 72 #define WordRequest_size 0 #define WordAck_size 14 #define SignMessage_size 1094 diff --git a/firmware/recovery.c b/firmware/recovery.c index 7ddceed63a..daa2973fb9 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -67,7 +67,7 @@ void next_word(void) { msg_write(MessageType_MessageType_WordRequest, &resp); } -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist) +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter) { if (_word_count != 12 && _word_count != 18 && _word_count != 24) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (has to be 12, 18 or 24 bits)"); @@ -88,6 +88,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage.passphrase_protection = passphrase_protection; storage_setLanguage(language); storage_setLabel(label); + storage_setU2FCounter(u2f_counter); uint32_t i; for (i = 0; i < word_count; i++) { diff --git a/firmware/recovery.h b/firmware/recovery.h index 4d581138ba..e1de844c42 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -23,7 +23,7 @@ #include #include -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist); +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter); void recovery_word(const char *word); void recovery_abort(void); const char *recovery_get_fake_word(void); diff --git a/firmware/reset.c b/firmware/reset.c index b6b337fcf5..0b7f228ede 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -33,7 +33,7 @@ static uint32_t strength; static uint8_t int_entropy[32]; static bool awaiting_entropy = false; -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label) +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter) { if (_strength != 128 && _strength != 192 && _strength != 256) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid strength (has to be 128, 192 or 256 bits)"); @@ -70,6 +70,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect storage.passphrase_protection = passphrase_protection; storage_setLanguage(language); storage_setLabel(label); + storage_setU2FCounter(u2f_counter); EntropyRequest resp; memset(&resp, 0, sizeof(EntropyRequest)); diff --git a/firmware/reset.h b/firmware/reset.h index 157d94ce16..1cb8575edc 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -23,7 +23,7 @@ #include #include -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label); +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); diff --git a/firmware/storage.c b/firmware/storage.c index 0eaa8554a9..5ec381f0ab 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -290,6 +290,10 @@ void storage_loadDevice(LoadDevice *msg) if (msg->has_label) { storage_setLabel(msg->label); } + + if (msg->has_u2f_counter) { + storage_setU2FCounter(msg->u2f_counter); + } } void storage_setLabel(const char *label) diff --git a/vendor/trezor-common b/vendor/trezor-common index 20c1d05f9d..0b4b667ff1 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 20c1d05f9de778e28726690c4969e6ce92296ce4 +Subproject commit 0b4b667ff1e7cc15e40e983f17eef03ec62921d1 From 1bd4b99f95f15771d24ee2f1f2552a335bede380 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 27 Apr 2016 23:38:59 +0200 Subject: [PATCH 0348/1154] Allow SegWit addresses New output scripts for segwit addresses in accordance to BIP-142 and BIP-141. This allows Trezor to pay to segwit users, but it doesn't enable segwit for Trezor itself. --- firmware/protob/types.options | 2 +- firmware/protob/types.pb.h | 2 +- firmware/transaction.c | 91 +++++++++++++++++++++++------------ 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 536e91ab48..bd56519202 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -12,7 +12,7 @@ TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 -TxOutputType.address max_size:41 +TxOutputType.address max_size:54 TxOutputType.address_n max_count:8 TxOutputType.op_return_data max_size:80 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index a7dd51e8a2..39ddfe3d70 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -229,7 +229,7 @@ typedef struct { typedef struct _TxOutputType { bool has_address; - char address[41]; + char address[54]; size_t address_n_count; uint32_t address_n[8]; uint64_t amount; diff --git a/firmware/transaction.c b/firmware/transaction.c index c4667b963b..fd032067a2 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -61,11 +61,68 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int addr_raw_len; + + if (in->has_address) { // address provided -> regular output + addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); + if (in->script_type != OutputScriptType_PAYTOADDRESS) { + // allow for p2sh (backward compatibility only) + if (in->script_type != OutputScriptType_PAYTOSCRIPTHASH + || addr_raw_len != 21 + || addr_raw[0] != coin->address_type_p2sh) { + return 0; + } + } + + if (addr_raw_len == 21 && + addr_raw[0] == coin->address_type) { // p2pkh + + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + } else if (addr_raw_len == 21 + && addr_raw[0] == coin->address_type_p2sh) { // p2sh + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else if (addr_raw_len == 23 + && addr_raw[0] == coin->address_type_p2wpkh + && addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wpkh v0 + out->script_pubkey.bytes[0] = 0x00; // version 0 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 20); + out->script_pubkey.size = 22; + } else if (addr_raw_len == 35 + && addr_raw[0] == coin->address_type_p2wsh + && addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wsh v0 + out->script_pubkey.bytes[0] = 0x00; // version 0 + out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 32); + out->script_pubkey.size = 34; + } else { + return 0; + } + + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; + } + } + + return out->script_pubkey.size; + } if (in->script_type == OutputScriptType_PAYTOADDRESS) { - // address_n provided-> change address -> calculate from address_n - if (in->address_n_count > 0) { + if (in->script_type == OutputScriptType_PAYTOADDRESS && + in->address_n_count > 0) { HDNode node; memcpy(&node, root, sizeof(HDNode)); if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count) == 0) { @@ -73,18 +130,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } layoutProgressUpdate(true); hdnode_get_address_raw(&node, coin->address_type, addr_raw); - } else - if (in->has_address) { // address provided -> regular output - if (needs_confirm) { - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; - } - } - if (!ecdsa_address_decode(in->address, coin->address_type, addr_raw)) { - return 0; - } - } else { // does not have address_n neither address -> error return 0; } @@ -99,24 +144,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T return 25; } - if (in->script_type == OutputScriptType_PAYTOSCRIPTHASH) { - if (!in->has_address || !ecdsa_address_decode(in->address, coin->address_type_p2sh, addr_raw)) { - return 0; - } - if (needs_confirm) { - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; - } - } - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + address_prefix_bytes_len(coin->address_type_p2sh), 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - return 23; - } - if (in->script_type == OutputScriptType_PAYTOMULTISIG) { uint8_t buf[32]; size_t prefix_bytes = address_prefix_bytes_len(coin->address_type_p2sh); From 5c60be9854d8955ffe4731390d912423d1b215fb Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 21:17:06 +0200 Subject: [PATCH 0349/1154] hashes for segwit signature --- firmware/signing.c | 25 ++++++++++++++++++++++++- firmware/transaction.c | 38 ++++++++++++++++++++++++++++---------- firmware/transaction.h | 5 +++++ 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 3743092309..cc3228e79e 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -50,7 +50,9 @@ static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; static SHA256_CTX tc; -static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; +static SHA256_CTX hashers[2]; +static uint8_t hash_check[32], privkey[32], pubkey[33], sig[64]; +static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; static uint64_t to_spend, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; @@ -273,6 +275,9 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); + // segwit hashes for hashPrevouts and hashSequence + sha256_Init(&hashers[0]); + sha256_Init(&hashers[1]); layoutProgressSwipe("Signing transaction", 0); @@ -326,6 +331,9 @@ void signing_txack(TransactionType *tx) } else { // InputScriptType_SPENDADDRESS multisig_fp_mismatch = true; } + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hashers[0], tx->inputs); + tx_sequence_hash(&hashers[1], tx->inputs); sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); @@ -399,6 +407,8 @@ void signing_txack(TransactionType *tx) if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received)); } else { + /* Check next output */ + uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); @@ -409,6 +419,13 @@ void signing_txack(TransactionType *tx) idx1++; send_req_1_input(); } else { + // compute segwit hashPrevouts & hashSequence + sha256_Final(&hashers[0], hash_prevouts); + sha256_Raw(hash_prevouts, 32, hash_prevouts); + sha256_Final(&hashers[1], hash_sequence); + sha256_Raw(hash_sequence, 32, hash_sequence); + // init hashOutputs + sha256_Init(&hashers[0]); idx1 = 0; send_req_3_output(); } @@ -463,11 +480,15 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + // compute segwit hashOuts + tx_output_hash(&hashers[0], &bin_output); sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); if (idx1 < outputs_count - 1) { idx1++; send_req_3_output(); } else { + sha256_Final(&hashers[0], hash_outputs); + sha256_Raw(hash_sequence, 32, hash_outputs); sha256_Final(&tc, hash_check); // check fees if (spending > to_spend) { @@ -532,6 +553,7 @@ void signing_txack(TransactionType *tx) } tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes); } else { // SPENDADDRESS + uint8_t hash[20]; ecdsa_get_pubkeyhash(node.public_key, hash); tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); } @@ -580,6 +602,7 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_output(); } else { + uint8_t hash[32]; sha256_Final(&tc, hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); diff --git a/firmware/transaction.c b/firmware/transaction.c index fd032067a2..45e33cd005 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -286,6 +286,31 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin // tx methods +uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) +{ + int i; + for (i = 0; i < 32; i++) { + sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1); + } + sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4); + return 36; +} + +uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input) +{ + sha256_Update(ctx, (const uint8_t *)&input->sequence, 4); + return 4; +} + +uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output) +{ + uint32_t r = 0; + sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8; + r += ser_length_hash(ctx, output->script_pubkey.size); + sha256_Update(ctx, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + return r; +} + uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->version), 4); @@ -326,7 +351,6 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) { - int i; if (tx->have_inputs >= tx->inputs_len) { // already got all inputs return 0; @@ -335,14 +359,10 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) if (tx->have_inputs == 0) { r += tx_serialize_header_hash(tx); } - for (i = 0; i < 32; i++) { - sha256_Update(&(tx->ctx), &(input->prev_hash.bytes[31 - i]), 1); - } - r += 32; - sha256_Update(&(tx->ctx), (const uint8_t *)&input->prev_index, 4); r += 4; + r += tx_prevout_hash(&(tx->ctx), input); r += ser_length_hash(&(tx->ctx), input->script_sig.size); sha256_Update(&(tx->ctx), input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; - sha256_Update(&(tx->ctx), (const uint8_t *)&input->sequence, 4); r += 4; + r += tx_sequence_hash(&(tx->ctx), input); tx->have_inputs++; tx->size += r; @@ -423,9 +443,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) if (tx->have_outputs == 0) { r += tx_serialize_middle_hash(tx); } - sha256_Update(&(tx->ctx), (const uint8_t *)&output->amount, 8); r += 8; - r += ser_length_hash(&(tx->ctx), output->script_pubkey.size); - sha256_Update(&(tx->ctx), output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + r += tx_output_hash(&(tx->ctx), output); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len) { r += tx_serialize_footer_hash(tx); diff --git a/firmware/transaction.h b/firmware/transaction.h index 71ec1c1137..c03b9fdd84 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -51,6 +51,11 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); + +uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); +uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input); +uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output); + uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); From e5000fb196875b29bd6026eafe074c4968920a76 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 29 Apr 2016 22:15:55 +0200 Subject: [PATCH 0350/1154] segwit sign (completely untested) --- firmware/protob/types.pb.h | 6 +- firmware/signing.c | 397 +++++++++++++++++++++++++++---------- firmware/transaction.c | 42 +++- firmware/transaction.h | 4 +- 4 files changed, 333 insertions(+), 116 deletions(-) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 39ddfe3d70..16d1a6e3a7 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -387,10 +387,10 @@ extern const pb_field_t IdentityType_fields[7]; #define CoinType_size 99 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5508 -#define TxOutputType_size 3934 +#define TxOutputType_size 3947 #define TxOutputBinType_size 534 -#define TransactionType_size 11042 -#define TxRequestDetailsType_size 52 +#define TransactionType_size 10022 +#define TxRequestDetailsType_size 40 #define TxRequestSerializedType_size 2132 #define IdentityType_size 416 diff --git a/firmware/signing.c b/firmware/signing.c index cc3228e79e..23300e511c 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -42,20 +42,23 @@ enum { STAGE_REQUEST_3_OUTPUT, STAGE_REQUEST_4_INPUT, STAGE_REQUEST_4_OUTPUT, - STAGE_REQUEST_5_OUTPUT + STAGE_REQUEST_SEGWIT_INPUT, + STAGE_REQUEST_5_OUTPUT, + STAGE_REQUEST_SEGWIT_WITNESS } signing_stage; static uint32_t idx1, idx2; static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; -static SHA256_CTX tc; -static SHA256_CTX hashers[2]; -static uint8_t hash_check[32], privkey[32], pubkey[33], sig[64]; +static SHA256_CTX hashers[3]; +static uint8_t privkey[32], pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; -static uint64_t to_spend, spending, change_spend; +static uint8_t hash_check[32]; +static uint64_t to_spend, segwit_to_spend, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; +static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; @@ -226,6 +229,28 @@ void send_req_4_output(void) msg_write(MessageType_MessageType_TxRequest, &resp); } +void send_req_segwit_input(void) +{ + signing_stage = STAGE_REQUEST_SEGWIT_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + +void send_req_segwit_witness(void) +{ + signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + void send_req_5_output(void) { signing_stage = STAGE_REQUEST_5_OUTPUT; @@ -244,6 +269,63 @@ void send_req_finished(void) msg_write(MessageType_MessageType_TxRequest, &resp); } +void phase1_request_next_input(void) +{ + if (idx1 < inputs_count - 1) { + idx1++; + send_req_1_input(); + } else { + // compute segwit hashPrevouts & hashSequence + sha256_Final(&hashers[0], hash_prevouts); + sha256_Raw(hash_prevouts, 32, hash_prevouts); + sha256_Final(&hashers[1], hash_sequence); + sha256_Raw(hash_sequence, 32, hash_sequence); + sha256_Final(&hashers[2], hash_check); + // init hashOutputs + sha256_Init(&hashers[0]); + idx1 = 0; + send_req_3_output(); + } +} + +void phase2_request_next_input(void) +{ + if (idx1 == next_nonsegwit_input) { + idx2 = 0; + send_req_4_input(); + } else { + send_req_segwit_input(); + } +} + +bool compile_input_script_sig(TxInputType *tinput) +{ + if (!multisig_fp_mismatch) { + // check that this is still multisig + uint8_t h[32]; + if (tinput->script_type != InputScriptType_SPENDMULTISIG + || cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 + || memcmp(multisig_fp, h, 32) != 0) { + // Transaction has changed during signing + return false; + } + } + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count) == 0) { + // Failed to derive private key + return false; + } + if (tinput->script_type == InputScriptType_SPENDMULTISIG + || tinput->script_type == InputScriptType_SPENDWMULTISIG) { + tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); + } else { // SPENDADDRESS + uint8_t hash[20]; + ecdsa_get_pubkeyhash(node.public_key, hash); + tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); + } + return tinput->script_sig.size > 0; +} + void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time) { inputs_count = _inputs_count; @@ -257,6 +339,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp to_spend = 0; spending = 0; change_spend = 0; + segwit_to_spend = 0; memset(&input, 0, sizeof(TxInputType)); memset(&resp, 0, sizeof(TxRequest)); @@ -268,16 +351,13 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp multisig_fp_set = false; multisig_fp_mismatch = false; + next_nonsegwit_input = 0xffffffff; tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, false); - sha256_Init(&tc); - sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); - sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); - sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); - sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); // segwit hashes for hashPrevouts and hashSequence sha256_Init(&hashers[0]); sha256_Init(&hashers[1]); + sha256_Init(&hashers[2]); layoutProgressSwipe("Signing transaction", 0); @@ -307,36 +387,53 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { - if (tx->inputs[0].has_multisig && !multisig_fp_mismatch) { - if (multisig_fp_set) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), multisig_fp) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); - signing_abort(); - return; - } - multisig_fp_set = true; - } + if ((tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG) + && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); + signing_abort(); + return; } - } else { // InputScriptType_SPENDADDRESS + if (multisig_fp_set) { + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + memcpy(multisig_fp, h, 32); + multisig_fp_set = true; + } + } else { // InputScriptType_SPENDADDRESS or SPENDWADDRESS multisig_fp_mismatch = true; } - // compute segwit hashPrevouts & hashSequence - tx_prevout_hash(&hashers[0], tx->inputs); - tx_sequence_hash(&hashers[1], tx->inputs); - sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); - memcpy(&input, tx->inputs, sizeof(TxInputType)); - send_req_2_prev_meta(); + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hashers[0], &tx->inputs[0]); + tx_sequence_hash(&hashers[1], &tx->inputs[0]); + // hash prevout and script type to check it later (relevant for fee computation) + tx_prevout_hash(&hashers[2], &tx->inputs[0]); + sha256_Update(&hashers[2], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + if (next_nonsegwit_input == 0xffffffff) + next_nonsegwit_input = idx1; + memcpy(&input, tx->inputs, sizeof(TxInputType)); + send_req_2_prev_meta(); + } else if (tx->inputs[0].has_amount + && (tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS)) { + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + signing_abort(); + } + to_spend += tx->inputs[0].amount; + segwit_to_spend += tx->inputs[0].amount; + to.is_segwit = true; + phase1_request_next_input(); + } else { + fsm_sendFailure(FailureType_Failure_Other, "Wrong input script type"); + signing_abort(); + } return; case STAGE_REQUEST_2_PREV_META: tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, false); @@ -372,6 +469,10 @@ void signing_txack(TransactionType *tx) return; } if (idx2 == input.prev_index) { + if (to_spend + tx->bin_outputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + signing_abort(); + } to_spend += tx->bin_outputs[0].amount; } if (idx2 < tp.outputs_len - 1) { @@ -415,20 +516,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx1 < inputs_count - 1) { - idx1++; - send_req_1_input(); - } else { - // compute segwit hashPrevouts & hashSequence - sha256_Final(&hashers[0], hash_prevouts); - sha256_Raw(hash_prevouts, 32, hash_prevouts); - sha256_Final(&hashers[1], hash_sequence); - sha256_Raw(hash_sequence, 32, hash_sequence); - // init hashOutputs - sha256_Init(&hashers[0]); - idx1 = 0; - send_req_3_output(); - } + phase1_request_next_input(); } return; case STAGE_REQUEST_3_OUTPUT: @@ -438,24 +526,21 @@ void signing_txack(TransactionType *tx) * Ask for permission. */ bool is_change = false; - if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG && - tx->outputs[0].has_multisig && - multisig_fp_set && !multisig_fp_mismatch) { + if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG) { uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingeprint"); + if (!multisig_fp_set || multisig_fp_mismatch + || cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0 + || memcmp(multisig_fp, h, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); signing_abort(); return; } - if (memcmp(multisig_fp, h, 32) == 0) { - is_change = true; - } - } else - if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && - tx->outputs[0].address_n_count > 0) { + is_change = true; + } else if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && + tx->outputs[0].address_n_count > 0) { is_change = true; } - + if (is_change) { if (change_spend == 0) { // not set change_spend = tx->outputs[0].amount; @@ -466,6 +551,10 @@ void signing_txack(TransactionType *tx) } } + if (spending + tx->inputs[0].amount < spending) { + fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + signing_abort(); + } spending += tx->outputs[0].amount; co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); if (!is_change) { @@ -482,14 +571,12 @@ void signing_txack(TransactionType *tx) } // compute segwit hashOuts tx_output_hash(&hashers[0], &bin_output); - sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); if (idx1 < outputs_count - 1) { idx1++; send_req_3_output(); } else { sha256_Final(&hashers[0], hash_outputs); - sha256_Raw(hash_sequence, 32, hash_outputs); - sha256_Final(&tc, hash_check); + sha256_Raw(hash_outputs, 32, hash_outputs); // check fees if (spending > to_spend) { fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); @@ -518,8 +605,7 @@ void signing_txack(TransactionType *tx) progress_meta_step = progress_step / (inputs_count + outputs_count); layoutProgress("Signing transaction", progress); idx1 = 0; - idx2 = 0; - send_req_4_input(); + phase2_request_next_input(); } return; } @@ -527,44 +613,26 @@ void signing_txack(TransactionType *tx) progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, true); - sha256_Init(&tc); - sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); - sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); - sha256_Update(&tc, (const uint8_t *)&version, sizeof(version)); - sha256_Update(&tc, (const uint8_t *)&lock_time, sizeof(lock_time)); - memset(privkey, 0, 32); - memset(pubkey, 0, 33); + sha256_Init(&hashers[0]); } - sha256_Update(&tc, (const uint8_t *)tx->inputs, sizeof(TxInputType)); + // check prevouts and script type + tx_prevout_hash(&hashers[0], tx->inputs); + sha256_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { - memcpy(&input, tx->inputs, sizeof(TxInputType)); - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); - signing_abort(); - return; - } - hdnode_fill_public_key(&node); - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { - if (!tx->inputs[0].has_multisig) { - fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); - signing_abort(); - return; - } - tx->inputs[0].script_sig.size = compile_script_multisig(&(tx->inputs[0].multisig), tx->inputs[0].script_sig.bytes); - } else { // SPENDADDRESS - uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, hash); - tx->inputs[0].script_sig.size = compile_script_sig(coin->address_type, hash, tx->inputs[0].script_sig.bytes); - } - if (tx->inputs[0].script_sig.size == 0) { + if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); return; } + memcpy(&input, &tx->inputs[0], sizeof(input)); memcpy(privkey, node.private_key, 32); memcpy(pubkey, node.public_key, 33); } else { + if (next_nonsegwit_input == idx1 && idx2 > idx1 + && (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS + || tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG)) { + next_nonsegwit_input = idx2; + } tx->inputs[0].script_sig.size = 0; } if (!tx_serialize_input_hash(&ti, tx->inputs)) { @@ -576,6 +644,14 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_input(); } else { + uint8_t hash[32]; + sha256_Final(&hashers[0], hash); + if (memcmp(hash, hash_check, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return; + } + sha256_Init(&hashers[0]); idx2 = 0; send_req_4_output(); } @@ -592,7 +668,8 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - sha256_Update(&tc, (const uint8_t *)&bin_output, sizeof(TxOutputBinType)); + // check hashOutputs + tx_output_hash(&hashers[0], &bin_output); if (!tx_serialize_output_hash(&ti, &bin_output)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); signing_abort(); @@ -603,8 +680,9 @@ void signing_txack(TransactionType *tx) send_req_4_output(); } else { uint8_t hash[32]; - sha256_Final(&tc, hash); - if (memcmp(hash, hash_check, 32) != 0) { + sha256_Final(&hashers[0], hash); + sha256_Raw(hash, 32, hash); + if (memcmp(hash, hash_outputs, 32) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); signing_abort(); return; @@ -617,6 +695,7 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + if (input.script_type == InputScriptType_SPENDMULTISIG) { if (!input.has_multisig) { fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); @@ -647,14 +726,33 @@ void signing_txack(TransactionType *tx) update_ctr = 0; if (idx1 < inputs_count - 1) { idx1++; - idx2 = 0; - send_req_4_input(); + phase2_request_next_input(); } else { idx1 = 0; send_req_5_output(); } } return; + + case STAGE_REQUEST_SEGWIT_INPUT: + progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); + + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + tx->inputs[0].script_sig.size = 0; + resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + phase2_request_next_input(); + } else { + idx1 = 0; + send_req_5_output(); + } + return; + case STAGE_REQUEST_5_OUTPUT: if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); @@ -667,11 +765,106 @@ void signing_txack(TransactionType *tx) if (idx1 < outputs_count - 1) { idx1++; send_req_5_output(); + } else if (to.is_segwit) { + idx1 = 0; + send_req_segwit_witness(); } else { send_req_finished(); signing_abort(); } return; + + case STAGE_REQUEST_SEGWIT_WITNESS: + { + uint8_t hash[32]; + uint32_t sighash = 1; + progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); + + if (tx->inputs[0].script_type != InputScriptType_SPENDWADDRESS + && tx->inputs[0].script_type != InputScriptType_SPENDWMULTISIG) { + // empty witness + resp.serialized.serialized_tx.bytes[0] = 0; + resp.serialized.serialized_tx.size = 1; + } else { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + signing_abort(); + return; + } + if (tx->inputs[0].amount > segwit_to_spend) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return; + } + segwit_to_spend -= tx->inputs[0].amount; + + sha256_Init(&hashers[0]); + sha256_Update(&hashers[0], (const uint8_t *)&version, 4); + sha256_Update(&hashers[0], hash_prevouts, 32); + sha256_Update(&hashers[0], hash_sequence, 32); + tx_prevout_hash(&hashers[0], &tx->inputs[0]); + tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes); + sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8); + sha256_Update(&hashers[0], hash_outputs, 32); + sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); + sha256_Update(&hashers[0], (const uint8_t*) &sighash, 4); + sha256_Final(&hashers[0], hash); + + resp.has_serialized = true; + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + if (input.script_type == InputScriptType_SPENDWMULTISIG) { + uint32_t r, i, script_len; + if (!input.has_multisig) { + fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); + signing_abort(); + return; + } + // fill in the signature + int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + signing_abort(); + return; + } + memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + + r = 0; + r += ser_length(input.multisig.signatures_count + 2, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.bytes[r] = 0; r++; + for (i = 0; i < input.multisig.signatures_count; i++) { + r += tx_serialize_script(input.multisig.signatures[i].size, input.multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); + } + script_len = compile_script_multisig(&input.multisig, 0); + r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(&input.multisig, resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(resp.serialized.signature.size, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } else { // SPENDWADDRESS + uint32_t r = 0; + r += ser_length(2, resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(resp.serialized.signature.size, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + } + // since this took a longer time, update progress + layoutProgress("Signing transaction", progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_segwit_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; + } } fsm_sendFailure(FailureType_Failure_Other, "Signing error"); diff --git a/firmware/transaction.c b/firmware/transaction.c index 45e33cd005..62be8638a8 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -32,6 +32,8 @@ #include "messages.pb.h" #include "types.pb.h" +static const uint8_t segwit_header[2] = {0,1}; + uint32_t op_push(uint32_t i, uint8_t *out) { if (i < 0x4C) { out[0] = i & 0xFF; @@ -296,6 +298,13 @@ uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) return 36; } +uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data) +{ + int r = ser_length_hash(ctx, size); + sha256_Update(ctx, data, size); + return r + size; +} + uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input) { sha256_Update(ctx, (const uint8_t *)&input->sequence, 4); @@ -306,21 +315,37 @@ uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output) { uint32_t r = 0; sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8; - r += ser_length_hash(ctx, output->script_pubkey.size); - sha256_Update(ctx, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + r += tx_script_hash(ctx, output->script_pubkey.size, output->script_pubkey.bytes); return r; } +uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) +{ + int r = ser_length(size, out); + memcpy(out + r, data, size); + return r + size; +} + uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { + int r = 4; memcpy(out, &(tx->version), 4); - return 4 + ser_length(tx->inputs_len, out + 4); + if (tx->is_segwit) { + memcpy(out + r, segwit_header, 2); + r += 2; + } + return r + ser_length(tx->inputs_len, out + r); } uint32_t tx_serialize_header_hash(TxStruct *tx) { + int r = 4; sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4); - return 4 + ser_length_hash(&(tx->ctx), tx->inputs_len); + if (tx->is_segwit) { + sha256_Update(&(tx->ctx), segwit_header, 2); + r += 2; + } + return r + ser_length_hash(&(tx->ctx), tx->inputs_len); } uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) @@ -339,8 +364,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out } r += 32; memcpy(out + r, &input->prev_index, 4); r += 4; - r += ser_length(input->script_sig.size, out + r); - memcpy(out + r, input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); memcpy(out + r, &input->sequence, 4); r += 4; tx->have_inputs++; @@ -360,8 +384,7 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) r += tx_serialize_header_hash(tx); } r += tx_prevout_hash(&(tx->ctx), input); - r += ser_length_hash(&(tx->ctx), input->script_sig.size); - sha256_Update(&(tx->ctx), input->script_sig.bytes, input->script_sig.size); r += input->script_sig.size; + r += tx_script_hash(&(tx->ctx), input->script_sig.size, input->script_sig.bytes); r += tx_sequence_hash(&(tx->ctx), input); tx->have_inputs++; @@ -419,8 +442,7 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_ r += tx_serialize_middle(tx, out + r); } memcpy(out + r, &output->amount, 8); r += 8; - r += ser_length(output->script_pubkey.size, out + r); - memcpy(out + r, output->script_pubkey.bytes, output->script_pubkey.size); r+= output->script_pubkey.size; + r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len) { r += tx_serialize_footer(tx, out + r); diff --git a/firmware/transaction.h b/firmware/transaction.h index c03b9fdd84..ef59a052e1 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -32,7 +32,7 @@ typedef struct { uint32_t version; uint32_t lock_time; - bool add_hash_type; + bool add_hash_type, is_segwit; uint32_t have_inputs; uint32_t have_outputs; @@ -53,8 +53,10 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); +uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data); uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input); uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output); +uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); From b7b9891cb49e8a674a9bd6cd024650d17dfb01a0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 1 May 2016 02:47:15 +0200 Subject: [PATCH 0351/1154] Signing for Segnet Transaction works see segnet4 txid: aa434a6ef4fcf350e319bacbd725fa7446f797cb3ed0cd0582826a49d3351ffa --- firmware/signing.c | 19 ++++++++++++++++--- firmware/transaction.c | 7 +++++-- firmware/transaction.h | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 23300e511c..7262138c87 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -783,6 +783,10 @@ void signing_txack(TransactionType *tx) if (tx->inputs[0].script_type != InputScriptType_SPENDWADDRESS && tx->inputs[0].script_type != InputScriptType_SPENDWMULTISIG) { // empty witness + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; resp.serialized.serialized_tx.bytes[0] = 0; resp.serialized.serialized_tx.size = 1; } else { @@ -805,10 +809,12 @@ void signing_txack(TransactionType *tx) tx_prevout_hash(&hashers[0], &tx->inputs[0]); tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes); sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8); + tx_sequence_hash(&hashers[0], &tx->inputs[0]); sha256_Update(&hashers[0], hash_outputs, 32); sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); sha256_Update(&hashers[0], (const uint8_t*) &sighash, 4); sha256_Final(&hashers[0], hash); + sha256_Raw(hash, 32, hash); resp.has_serialized = true; resp.serialized.has_signature_index = true; @@ -825,7 +831,7 @@ void signing_txack(TransactionType *tx) return; } // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); + int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), node.public_key); if (pubkey_idx < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); signing_abort(); @@ -838,7 +844,8 @@ void signing_txack(TransactionType *tx) r += ser_length(input.multisig.signatures_count + 2, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.bytes[r] = 0; r++; for (i = 0; i < input.multisig.signatures_count; i++) { - r += tx_serialize_script(input.multisig.signatures[i].size, input.multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); + input.multisig.signatures[i].bytes[input.multisig.signatures[i].size] = 1; + r += tx_serialize_script(input.multisig.signatures[i].size + 1, input.multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); } script_len = compile_script_multisig(&input.multisig, 0); r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); @@ -848,11 +855,17 @@ void signing_txack(TransactionType *tx) } else { // SPENDWADDRESS uint32_t r = 0; r += ser_length(2, resp.serialized.serialized_tx.bytes + r); - r += tx_serialize_script(resp.serialized.signature.size, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); + resp.serialized.signature.bytes[resp.serialized.signature.size] = 1; + r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.size = r; } } + if (idx1 == inputs_count - 1) { + uint32_t r = resp.serialized.serialized_tx.size; + r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } // since this took a longer time, update progress layoutProgress("Signing transaction", progress); update_ctr = 0; diff --git a/firmware/transaction.c b/firmware/transaction.c index 62be8638a8..9e63ce82d2 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -444,7 +444,8 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_ memcpy(out + r, &output->amount, 8); r += 8; r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len) { + if (tx->have_outputs == tx->outputs_len + && !tx->is_segwit) { r += tx_serialize_footer(tx, out + r); } tx->size += r; @@ -467,7 +468,8 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) } r += tx_output_hash(&(tx->ctx), output); tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len) { + if (tx->have_outputs == tx->outputs_len + && !tx->is_segwit) { r += tx_serialize_footer_hash(tx); } tx->size += r; @@ -506,6 +508,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->extra_data_len = extra_data_len; tx->extra_data_received = 0; tx->size = 0; + tx->is_segwit = false; sha256_Init(&(tx->ctx)); } diff --git a/firmware/transaction.h b/firmware/transaction.h index ef59a052e1..e100aeaa35 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -58,6 +58,7 @@ uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input); uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); +uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); From 388750f2d1e4965fd9404c5ca5a26338d91a132d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 3 Jul 2016 16:11:56 +0200 Subject: [PATCH 0352/1154] Support for P2SH compatible segwit --- firmware/signing.c | 59 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 7262138c87..f62340670a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -421,7 +421,9 @@ void signing_txack(TransactionType *tx) send_req_2_prev_meta(); } else if (tx->inputs[0].has_amount && (tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS)) { + || tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS)) { if (to_spend + tx->inputs[0].amount < to_spend) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); @@ -741,7 +743,35 @@ void signing_txack(TransactionType *tx) resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; resp.serialized.has_serialized_tx = true; - tx->inputs[0].script_sig.size = 0; + if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS) { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + signing_abort(); + return; + } + // fixup normal p2pkh script into witness 0 p2wpkh script for p2sh + // we convert 76 A9 14 88 AC to 16 00 14 + // P2SH input pushes witness 0 script + tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes. + tx->inputs[0].script_sig.bytes[0] = 0x16; // push 22 bytes; replaces OP_DUP + tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script ; replaces OP_HASH160 + // digest is already in right place. + } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) { + // Prepare P2SH witness script. + tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: + tx->inputs[0].script_sig.bytes[0] = 0x22; // push 34 bytes (full witness script) + tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script + tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) + // compute disgest of multisig script + if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + signing_abort(); + return; + } + } else { + // direct witness scripts require zero scriptSig + tx->inputs[0].script_sig.size = 0; + } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); update_ctr = 0; if (idx1 < inputs_count - 1) { @@ -780,16 +810,10 @@ void signing_txack(TransactionType *tx) uint32_t sighash = 1; progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); - if (tx->inputs[0].script_type != InputScriptType_SPENDWADDRESS - && tx->inputs[0].script_type != InputScriptType_SPENDWMULTISIG) { - // empty witness - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.bytes[0] = 0; - resp.serialized.serialized_tx.size = 1; - } else { + if (tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS + || tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -823,7 +847,8 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (input.script_type == InputScriptType_SPENDWMULTISIG) { + if (input.script_type == InputScriptType_SPENDWMULTISIG + || input.script_type == InputScriptType_SPENDP2SHWMULTISIG) { uint32_t r, i, script_len; if (!input.has_multisig) { fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); @@ -860,6 +885,14 @@ void signing_txack(TransactionType *tx) r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.size = r; } + } else { + // empty witness + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.bytes[0] = 0; + resp.serialized.serialized_tx.size = 1; } if (idx1 == inputs_count - 1) { uint32_t r = resp.serialized.serialized_tx.size; From 895da908e06ec74fc098310784706d989a776735 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 4 Jul 2016 23:04:40 +0200 Subject: [PATCH 0353/1154] Simplified InputScriptType Distinguish between single signature and multisig via has_multisig. --- firmware/signing.c | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index f62340670a..01488dc4cc 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -315,8 +315,7 @@ bool compile_input_script_sig(TxInputType *tinput) // Failed to derive private key return false; } - if (tinput->script_type == InputScriptType_SPENDMULTISIG - || tinput->script_type == InputScriptType_SPENDWMULTISIG) { + if (tinput->has_multisig) { tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS uint8_t hash[20]; @@ -387,9 +386,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if ((tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG) - && !multisig_fp_mismatch) { + if (tx->inputs[0].has_multisig && !multisig_fp_mismatch) { uint8_t h[32]; if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); @@ -404,7 +401,7 @@ void signing_txack(TransactionType *tx) memcpy(multisig_fp, h, 32); multisig_fp_set = true; } - } else { // InputScriptType_SPENDADDRESS or SPENDWADDRESS + } else { // single signature multisig_fp_mismatch = true; } // compute segwit hashPrevouts & hashSequence @@ -420,10 +417,8 @@ void signing_txack(TransactionType *tx) memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); } else if (tx->inputs[0].has_amount - && (tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS)) { + && (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS)) { if (to_spend + tx->inputs[0].amount < to_spend) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); @@ -698,12 +693,7 @@ void signing_txack(TransactionType *tx) ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (input.script_type == InputScriptType_SPENDMULTISIG) { - if (!input.has_multisig) { - fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); - signing_abort(); - return; - } + if (input.has_multisig) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); if (pubkey_idx < 0) { @@ -743,7 +733,8 @@ void signing_txack(TransactionType *tx) resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; resp.serialized.has_serialized_tx = true; - if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS) { + if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS + && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -756,13 +747,13 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[0] = 0x16; // push 22 bytes; replaces OP_DUP tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script ; replaces OP_HASH160 // digest is already in right place. - } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) { + } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { // Prepare P2SH witness script. tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: tx->inputs[0].script_sig.bytes[0] = 0x22; // push 34 bytes (full witness script) tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) - // compute disgest of multisig script + // compute digest of multisig script if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -810,10 +801,8 @@ void signing_txack(TransactionType *tx) uint32_t sighash = 1; progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); - if (tx->inputs[0].script_type == InputScriptType_SPENDWADDRESS - || tx->inputs[0].script_type == InputScriptType_SPENDWMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWADDRESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWMULTISIG) { + if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -847,14 +836,8 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (input.script_type == InputScriptType_SPENDWMULTISIG - || input.script_type == InputScriptType_SPENDP2SHWMULTISIG) { + if (input.has_multisig) { uint32_t r, i, script_len; - if (!input.has_multisig) { - fsm_sendFailure(FailureType_Failure_Other, "Multisig info not provided"); - signing_abort(); - return; - } // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), node.public_key); if (pubkey_idx < 0) { @@ -877,7 +860,7 @@ void signing_txack(TransactionType *tx) r += compile_script_multisig(&input.multisig, resp.serialized.serialized_tx.bytes + r); r += tx_serialize_script(resp.serialized.signature.size, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.size = r; - } else { // SPENDWADDRESS + } else { // single signature uint32_t r = 0; r += ser_length(2, resp.serialized.serialized_tx.bytes + r); resp.serialized.signature.bytes[resp.serialized.signature.size] = 1; From 2950588271cbb88343ca2bc4fbd570ea46066101 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 8 Jul 2016 00:41:59 +0200 Subject: [PATCH 0354/1154] Fix segwit multisig. Tested, see f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228 and c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc on testnet --- firmware/signing.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 01488dc4cc..641a2d01f8 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -386,7 +386,8 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_1_INPUT: /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (tx->inputs[0].has_multisig && !multisig_fp_mismatch) { + if (tx->inputs[0].has_multisig && !multisig_fp_mismatch + && tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { uint8_t h[32]; if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); @@ -836,29 +837,35 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (input.has_multisig) { + if (tx->inputs[0].has_multisig) { uint32_t r, i, script_len; + int nwitnesses; // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), node.public_key); + int pubkey_idx = cryptoMultisigPubkeyIndex(&(tx->inputs[0].multisig), node.public_key); if (pubkey_idx < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); signing_abort(); return; } - memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + memcpy(tx->inputs[0].multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + tx->inputs[0].multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - r = 0; - r += ser_length(input.multisig.signatures_count + 2, resp.serialized.serialized_tx.bytes + r); + + r = 1; // skip number of items (filled in later) resp.serialized.serialized_tx.bytes[r] = 0; r++; - for (i = 0; i < input.multisig.signatures_count; i++) { - input.multisig.signatures[i].bytes[input.multisig.signatures[i].size] = 1; - r += tx_serialize_script(input.multisig.signatures[i].size + 1, input.multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); + nwitnesses = 2; + for (i = 0; i < tx->inputs[0].multisig.signatures_count; i++) { + if (tx->inputs[0].multisig.signatures[i].size == 0) { + continue; + } + nwitnesses++; + tx->inputs[0].multisig.signatures[i].bytes[tx->inputs[0].multisig.signatures[i].size] = 1; + r += tx_serialize_script(tx->inputs[0].multisig.signatures[i].size + 1, tx->inputs[0].multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); } - script_len = compile_script_multisig(&input.multisig, 0); + script_len = compile_script_multisig(&tx->inputs[0].multisig, 0); r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); - r += compile_script_multisig(&input.multisig, resp.serialized.serialized_tx.bytes + r); - r += tx_serialize_script(resp.serialized.signature.size, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(&tx->inputs[0].multisig, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.bytes[0] = nwitnesses; resp.serialized.serialized_tx.size = r; } else { // single signature uint32_t r = 0; From 810d478f4c459a539d2bc4913f16faf0b0b3053b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 8 Nov 2016 15:48:44 +0100 Subject: [PATCH 0355/1154] check return values of ecdsa_sign calls --- firmware/signing.c | 6 +++++- firmware/u2f.c | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 3743092309..22dcd91b46 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -592,7 +592,11 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL); + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + signing_abort(); + return; + } resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (input.script_type == InputScriptType_SPENDMULTISIG) { if (!input.has_multisig) { diff --git a/firmware/u2f.c b/firmware/u2f.c index d8b93135fc..56ee8f76bf 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -624,8 +624,10 @@ void u2f_register(const APDU *a) memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); - ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, - sizeof(sig_base), sig, NULL, NULL); + if (ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } // Where to write the signature in the response uint8_t *resp_sig = resp->keyHandleCertSig + @@ -744,9 +746,10 @@ void u2f_authenticate(const APDU *a) sig_base.flags = resp->flags; memcpy(sig_base.ctr, resp->ctr, 4); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - ecdsa_sign(&nist256p1, node->private_key, - (uint8_t *)&sig_base, sizeof(sig_base), sig, - NULL, NULL); + if (ecdsa_sign(&nist256p1, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } // Copy DER encoded signature into response const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); From 4ce4cc560552c8265bb1ac6dfad36639a6a4e5dc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 9 Nov 2016 16:06:50 +0100 Subject: [PATCH 0356/1154] halt the device when encountered an invalid mnemonic (skip if device loaded or recovered without enforced wordlist) --- firmware/recovery.c | 45 +++++++++++++++++++++++++++------------------ firmware/storage.c | 10 +++++++++- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index daa2973fb9..e92fc1d5a3 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -139,27 +139,36 @@ void recovery_word(const char *word) strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); } - if (word_index + 1 == 24) { // last one - uint32_t i; - strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); - for (i = 1; i < word_count; i++) { - strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); - strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); - } - if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { - storage.has_mnemonic = true; - storage_commit(); - fsm_sendSuccess("Device recovered"); - } else { - storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); - } - awaiting_word = false; - layoutHome(); - } else { + if (word_index + 1 < 24) { // not the last one word_index++; next_word(); + return; } + + // the last one + strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + for (uint32_t i = 1; i < word_count; i++) { + strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); + strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + } + + awaiting_word = false; + layoutHome(); + + if (!mnemonic_check(storage.mnemonic)) { + if (enforce_wordlist) { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); + return; + } else { // not enforcing => mark storage as imported + storage.has_imported = true; + storage.imported = true; + } + } + + storage.has_mnemonic = true; + storage_commit(); + fsm_sendSuccess("Device recovered"); } void recovery_abort(void) diff --git a/firmware/storage.c b/firmware/storage.c index 5ec381f0ab..8ef55fce77 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -105,7 +105,7 @@ static char sessionPassphrase[51]; void storage_show_error(void) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) { } + system_halt(); } void storage_check_flash_errors(void) @@ -353,6 +353,14 @@ const uint8_t *storage_getSeed(bool usePassphrase) if (usePassphrase && !protectPassphrase()) { return NULL; } + // if storage was not imported (i.e. it was properly generated or recovered) + if (!storage.has_imported || !storage.imported) { + // test whether mnemonic is a valid BIP-0039 mnemonic + if (!mnemonic_check(storage.mnemonic)) { + // and if not then halt the device + storage_show_error(); + } + } mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 sessionSeedCached = true; sessionSeedUsesPassphrase = usePassphrase; From 9287dd7e04d3347403ea536a20de891e005e17a9 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 7 Jul 2016 18:37:37 +0200 Subject: [PATCH 0357/1154] Poll USB during BIP39 derivation. This patch adds calls to usbPoll in the progress callback. This should address #98. We call usbDelay instead of Poll, to call usbd_poll several times. Otherwise it would only handle one event instead of handling all events that were pending so far. The ugly magic number 5 is a guess. Note that we also need to set usbTiny, so that we don't recursively process messages. Since we don't know whether usbTiny is set, we need to store the old value (especially true for u2f). This fix also relies on another fix in libopencm3. --- firmware/storage.c | 4 ++++ firmware/usb.c | 4 +++- firmware/usb.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 8ef55fce77..7a13f41314 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -39,6 +39,7 @@ #include "debug.h" #include "protect.h" #include "layout2.h" +#include "usb.h" Storage storage; @@ -337,6 +338,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size) void get_root_node_callback(uint32_t iter, uint32_t total) { + usbDelay(10); // handle up to ten usb interrupts. layoutProgress("Waking up", 1000 * iter / total); } @@ -361,7 +363,9 @@ const uint8_t *storage_getSeed(bool usePassphrase) storage_show_error(); } } + char oldTiny = usbTiny(1); mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 + usbTiny(oldTiny); sessionSeedCached = true; sessionSeedUsesPassphrase = usePassphrase; return sessionSeed; diff --git a/firmware/usb.c b/firmware/usb.c index 56504deee8..241d05616a 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -419,9 +419,11 @@ void usbReconnect(void) usbd_disconnect(usbd_dev, 0); } -void usbTiny(char set) +char usbTiny(char set) { + char old = tiny; tiny = set; + return old; } void usbDelay(int cycles) diff --git a/firmware/usb.h b/firmware/usb.h index d1dc250187..286e3a4a4d 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -23,7 +23,7 @@ void usbInit(void); void usbPoll(void); void usbReconnect(void); -void usbTiny(char set); +char usbTiny(char set); void usbDelay(int cycles); #endif From f45454b5ce3349f4da21c14e4a14f6158d1c3e1d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Nov 2016 13:46:41 +0100 Subject: [PATCH 0358/1154] u2f: add fastmail to known providers --- firmware/u2f_knownapps.h | 9 +++++++++ gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_fastmail.png | Bin 0 -> 226 bytes 4 files changed, 12 insertions(+) create mode 100644 gen/bitmaps/u2f_fastmail.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 4b49046440..c39207b0d8 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -84,6 +84,15 @@ static const U2FWellKnown u2f_well_known[] = { 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, "GitLab", &bmp_u2f_gitlab + }, + { + // https://www.fastmail.com + { 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, + 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, + 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, + 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, + "FastMail", + &bmp_u2f_fastmail } }; diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 13faa549e9..8a3decc464 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -25,6 +25,7 @@ const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_fastmail_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x4f, 0xff, 0xff, 0xf2, 0x67, 0xff, 0xff, 0xe6, 0x73, 0xff, 0xff, 0xce, 0x79, 0xff, 0xff, 0x9e, 0x7c, 0xff, 0xff, 0x3e, 0x7e, 0x7f, 0xfe, 0x7e, 0x7f, 0x3f, 0xfc, 0xfe, 0x7f, 0x9f, 0xf9, 0xfe, 0x7f, 0xcf, 0xf3, 0xfe, 0x7f, 0xe7, 0xe7, 0xfe, 0x7f, 0xf3, 0xcf, 0xfe, 0x7f, 0xf8, 0x1f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; @@ -55,6 +56,7 @@ const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; +const BITMAP bmp_u2f_fastmail = {32, 32, bmp_u2f_fastmail_data}; const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index e109fd637d..dd26f5a74c 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -33,6 +33,7 @@ extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; extern const BITMAP bmp_u2f_bitbucket; extern const BITMAP bmp_u2f_dropbox; +extern const BITMAP bmp_u2f_fastmail; extern const BITMAP bmp_u2f_github; extern const BITMAP bmp_u2f_gitlab; extern const BITMAP bmp_u2f_google; diff --git a/gen/bitmaps/u2f_fastmail.png b/gen/bitmaps/u2f_fastmail.png new file mode 100644 index 0000000000000000000000000000000000000000..20d05d163046417c8516776966dd1c7fd378501d GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJm7Xq+ArXh)PInY)P~dPq`0-!( zHqo;g84g^!1y{FJuAlUumvMpP11*6)K?*SoF1cp!s}>aeZSG)h^Kd(Z?cR14!;Z*f z{slovE%s&)JvsT#`5ol!l&rC8vsMlJkjnRFLPhg_wu|DNoH0{c#5gr$WR6O4^2S_c z72?#5iFMQFc0Nobmr@l`|iP1`cJp8K)x*E!)pu0PHPKHFHZi9cH($>qWw ZGvi;Fn|RBFsX#|Fc)I$ztaD0e0swITP%8ic literal 0 HcmV?d00001 From 3cede26fbc1dd5194403f8694323c1efb2426be9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 15 Nov 2016 18:51:29 +0100 Subject: [PATCH 0359/1154] add yubico u2f demo to u2f known apps --- firmware/u2f_knownapps.h | 9 +++++++++ gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_yubico.png | Bin 0 -> 253 bytes 4 files changed, 12 insertions(+) create mode 100644 gen/bitmaps/u2f_yubico.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index c39207b0d8..2fda7630ce 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -93,6 +93,15 @@ static const U2FWellKnown u2f_well_known[] = { 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, "FastMail", &bmp_u2f_fastmail + }, + { + // https://demo.yubico.com + { 0x55, 0x67, 0x3b, 0x51, 0x38, 0xcc, 0x90, 0xd3, + 0xb7, 0xf3, 0x2b, 0xfd, 0xad, 0x6a, 0x38, 0xa8, + 0xed, 0xd7, 0xb3, 0x55, 0xb7, 0x7a, 0xb9, 0x79, + 0x21, 0x96, 0xf1, 0x06, 0xd1, 0x6c, 0xa3, 0x12 }, + "Yubico U2F Demo", + &bmp_u2f_yubico } }; diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 8a3decc464..4ee1a7e9e2 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -30,6 +30,7 @@ const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_yubico_data[] = { 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xfc, 0x3f, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0f, 0x80, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x78, 0x3e, 0x00, 0x00, 0x3c, 0x3c, 0x7c, 0x1f, 0x3c, 0x78, 0x7c, 0x1f, 0x1e, 0x78, 0x7c, 0x3e, 0x0e, 0xf0, 0x3e, 0x3e, 0x0f, 0xf0, 0x3e, 0x3c, 0x0f, 0xf0, 0x1f, 0x7c, 0x0f, 0xe0, 0x1f, 0x7c, 0x07, 0xe0, 0x1f, 0x78, 0x07, 0xe0, 0x0f, 0xf8, 0x07, 0xe0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x0f, 0x78, 0x03, 0xe0, 0x0e, 0x78, 0x07, 0xc0, 0x1e, 0x3c, 0x07, 0xc0, 0x3e, 0x3c, 0x0f, 0xc0, 0x3c, 0x1e, 0x0f, 0x80, 0x78, 0x0f, 0x8f, 0x81, 0xf0, 0x07, 0xc0, 0x03, 0xe0, 0x03, 0xfc, 0x3f, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00, }; const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data}; const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data}; @@ -61,3 +62,4 @@ const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data}; +const BITMAP bmp_u2f_yubico = {32, 32, bmp_u2f_yubico_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index dd26f5a74c..e6e1b0b479 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -38,5 +38,6 @@ extern const BITMAP bmp_u2f_github; extern const BITMAP bmp_u2f_gitlab; extern const BITMAP bmp_u2f_google; extern const BITMAP bmp_u2f_slushpool; +extern const BITMAP bmp_u2f_yubico; #endif diff --git a/gen/bitmaps/u2f_yubico.png b/gen/bitmaps/u2f_yubico.png new file mode 100644 index 0000000000000000000000000000000000000000..c4bc1f0a280ddee04f59b57898c707ecede0425d GIT binary patch literal 253 zcmVCz?)ilsvs_|?z(PRu*NGgGS^ z#zRDh20DqTSAVT=q+?d~9>yw+(x@gU_FBuG=SyQX?J+iHYJH4NckruYrU|iDU=000000NkvXXu0mjf D(wu7= literal 0 HcmV?d00001 From 25b9bfd97b0a1c03ae3a82db131df35a9561a2b5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 17 Nov 2016 19:07:41 +0000 Subject: [PATCH 0360/1154] timer: Use Cortex-M3 SysTick timers Removed `usbDelay(uint32_t cycles)`, added `usbSleep(uint32_t millis)` The same method signature could cause silent code breakage at runtime, as opposed to noisy code breakage at compile time which is the better kind. --- Makefile | 1 + firmware/protect.c | 4 +-- firmware/storage.c | 2 +- firmware/trezor.c | 8 ++++-- firmware/usb.c | 6 +++-- firmware/usb.h | 2 +- timer.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ timer.h | 28 +++++++++++++++++++++ 8 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 timer.c create mode 100644 timer.h diff --git a/Makefile b/Makefile index bbb79ccd01..747da6dc67 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ OBJS += serialno.o OBJS += setup.o OBJS += util.o OBJS += memory.o +OBJS += timer.o OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/firmware/protect.c b/firmware/protect.c index 715cf2116a..8ba3298c56 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -58,7 +58,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // button acked - check buttons if (acked) { - usbDelay(3300); + usbSleep(5); buttonUpdate(); if (button.YesUp) { result = true; @@ -165,7 +165,7 @@ bool protectPin(bool use_cached) } layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); // wait one second - usbDelay(800000); + usbSleep(1000); if (msg_tiny_id == MessageType_MessageType_Initialize) { protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; diff --git a/firmware/storage.c b/firmware/storage.c index 7a13f41314..97f5f6a5ef 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -338,7 +338,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size) void get_root_node_callback(uint32_t iter, uint32_t total) { - usbDelay(10); // handle up to ten usb interrupts. + usbSleep(1); layoutProgress("Waking up", 1000 * iter / total); } diff --git a/firmware/trezor.c b/firmware/trezor.c index 487a5e5c5a..a56e3d2e71 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -27,6 +27,7 @@ #include "layout.h" #include "layout2.h" #include "rng.h" +#include "timer.h" #include "buttons.h" uint32_t __stack_chk_guard; @@ -58,13 +59,13 @@ void check_lock_screen(void) // wait until NoButton is released usbTiny(1); do { - usbDelay(3300); + usbSleep(5); buttonUpdate(); } while (!button.NoUp); // wait for confirmation/cancellation of the dialog do { - usbDelay(3300); + usbSleep(5); buttonUpdate(); } while (!button.YesUp && !button.NoUp); usbTiny(0); @@ -102,6 +103,9 @@ int main(void) #else setupApp(); #endif + + timer_init(); + #if DEBUG_LINK oledSetDebug(1); storage_reset(); // wipe storage if debug link diff --git a/firmware/usb.c b/firmware/usb.c index 241d05616a..df50f1640e 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -27,6 +27,7 @@ #include "u2f.h" #include "storage.h" #include "util.h" +#include "timer.h" #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK @@ -426,9 +427,10 @@ char usbTiny(char set) return old; } -void usbDelay(int cycles) +void usbSleep(uint32_t millis) { - while (cycles--) { + uint32_t end = system_millis + millis; + while (end > system_millis) { usbd_poll(usbd_dev); } } diff --git a/firmware/usb.h b/firmware/usb.h index 286e3a4a4d..318a5a4ad2 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -24,6 +24,6 @@ void usbInit(void); void usbPoll(void); void usbReconnect(void); char usbTiny(char set); -void usbDelay(int cycles); +void usbSleep(uint32_t millis); #endif diff --git a/timer.c b/timer.c new file mode 100644 index 0000000000..2be93e8937 --- /dev/null +++ b/timer.c @@ -0,0 +1,61 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + + +#include "timer.h" + +#include +#include + +/* 1 tick = 1 ms */ +volatile uint32_t system_millis; + +/* + * Initialise the Cortex-M3 SysTick timer + */ +void timer_init(void) { + system_millis = 0; + + /* + * MCU clock (120 MHz) as source + * + * (120 MHz / 8) = 15 clock pulses + * + */ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + STK_CVR = 0; + + /* + * 1 tick = 1 ms @ 120 MHz + * + * (15 clock pulses * 1000 ms) = 15000 clock pulses + * + * Send an interrupt every (N - 1) clock pulses + */ + systick_set_reload(14999); + + /* SysTick as interrupt */ + systick_interrupt_enable(); + + systick_counter_enable(); +} + +void sys_tick_handler(void) { + system_millis++; +} diff --git a/timer.h b/timer.h new file mode 100644 index 0000000000..a69879c93d --- /dev/null +++ b/timer.h @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + + +#include + +/* 1 tick = 1 ms */ +extern volatile uint32_t system_millis; + +void timer_init(void); + +void sys_tick_handler(void); From 0ec32a61468efcbdf8a8a2e6e10a0b4c0ea76c9c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 17 Nov 2016 19:10:57 +0000 Subject: [PATCH 0361/1154] timer: Replace screen timeout with SysTick This provides an incredibly accurate screen timeout and removes the superfluous screen timeout counter --- firmware/layout2.c | 4 ++++ firmware/trezor.c | 9 +-------- timer.c | 3 +++ timer.h | 5 +++++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index e7d49262ab..91c409b6e6 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -28,6 +28,7 @@ #include "string.h" #include "util.h" #include "qr_encode.h" +#include "timer.h" void *layoutLast = layoutHome; @@ -81,6 +82,9 @@ void layoutHome(void) } } oledRefresh(); + + // Reset lock screen timeout + system_millis_lock = system_millis + SCREEN_TIMEOUT_MILLIS; } const char *str_amount(uint64_t amnt, const char *abbr, char *buf, int len) diff --git a/firmware/trezor.c b/firmware/trezor.c index a56e3d2e71..129fd61a4e 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -38,15 +38,12 @@ void __attribute__((noreturn)) __stack_chk_fail(void) for (;;) {} // loop forever } -static uint32_t saver_counter = 0; - void check_lock_screen(void) { buttonUpdate(); // wake from screensaver on any button if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { - saver_counter = 0; layoutHome(); return; } @@ -82,15 +79,11 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - saver_counter++; - if (saver_counter > 285000 * 60 * 10) { + if (system_millis >= system_millis_lock) { // lock the screen session_clear(true); layoutScreensaver(); - saver_counter = 0; } - } else { - saver_counter = 0; } } diff --git a/timer.c b/timer.c index 2be93e8937..e45ce740f0 100644 --- a/timer.c +++ b/timer.c @@ -26,6 +26,9 @@ /* 1 tick = 1 ms */ volatile uint32_t system_millis; +/* Screen timeout */ +uint32_t system_millis_lock; + /* * Initialise the Cortex-M3 SysTick timer */ diff --git a/timer.h b/timer.h index a69879c93d..53713cdfe5 100644 --- a/timer.h +++ b/timer.h @@ -23,6 +23,11 @@ /* 1 tick = 1 ms */ extern volatile uint32_t system_millis; +/* Screen timeout */ +extern uint32_t system_millis_lock; + +#define SCREEN_TIMEOUT_MILLIS (1000 * 60 * 10) /* 10 minutes */ + void timer_init(void); void sys_tick_handler(void); From 27a4e417079b0f023d0e1cf8e43438a2bac7c6e5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Nov 2016 20:00:22 +0100 Subject: [PATCH 0362/1154] refactor forgotten disabled coinByName usage --- firmware/fsm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ca3c997cdc..67c1141cf8 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -941,15 +941,11 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) bool display_only = msg->has_display_only && msg->display_only; bool signing = msg->address_n_count > 0; RESP_INIT(EncryptedMessage); - const CoinType *coin = 0; const HDNode *node = 0; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (signing) { - coin = coinByName(msg->coin_name); - if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); - return; - } + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; if (!protectPin(true)) { layoutHome(); return; From 0ef70164a59ef181f49a6de47b397498f41b2b96 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Nov 2016 20:57:45 +0100 Subject: [PATCH 0363/1154] extract CHECK_INITIALIZED and CHECK_NOT_INITIALIZED macros --- firmware/fsm.c | 89 ++++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 57 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 67c1141cf8..bd66d387b2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -53,10 +53,23 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); -#define RESP_INIT(TYPE) TYPE *resp = (TYPE *) (void *) msg_resp; \ +#define RESP_INIT(TYPE) \ + TYPE *resp = (TYPE *) (void *) msg_resp; \ _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ memset(resp, 0, sizeof(TYPE)); +#define CHECK_INITIALIZED \ + if (!storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ + return; \ + } + +#define CHECK_NOT_INITIALIZED \ + if (storage_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ + return; \ + } + void fsm_sendSuccess(const char *text) { RESP_INIT(Success); @@ -285,10 +298,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED if (!protectPin(true)) { layoutHome(); @@ -345,10 +355,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) void fsm_msgLoadDevice(LoadDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -373,10 +380,7 @@ void fsm_msgLoadDevice(LoadDevice *msg) void fsm_msgResetDevice(ResetDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED reset_init( msg->has_display_random && msg->display_random, @@ -391,10 +395,7 @@ void fsm_msgResetDevice(ResetDevice *msg) void fsm_msgSignTx(SignTx *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED if (msg->inputs_count < 1) { fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); @@ -441,10 +442,7 @@ void fsm_msgCancel(Cancel *msg) void fsm_msgEthereumSignTx(EthereumSignTx *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED if (!protectPin(true)) { layoutHome(); @@ -464,10 +462,8 @@ void fsm_msgEthereumTxAck(EthereumTxAck *msg) void fsm_msgCipherKeyValue(CipherKeyValue *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED + if (!msg->has_key) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); return; @@ -593,10 +589,7 @@ void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED if (!protectPin(true)) { layoutHome(); @@ -658,10 +651,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) { RESP_INIT(EthereumAddress); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED if (!protectPin(true)) { layoutHome(); @@ -708,10 +698,7 @@ void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -786,10 +773,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) { RESP_INIT(SignedIdentity); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -868,10 +852,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) { RESP_INIT(ECDHSessionKey); - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED layoutDecryptIdentity(&msg->identity); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -921,10 +902,8 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) /* ECIES disabled void fsm_msgEncryptMessage(EncryptMessage *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED + if (!msg->has_pubkey) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); return; @@ -975,10 +954,8 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) void fsm_msgDecryptMessage(DecryptMessage *msg) { - if (!storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); - return; - } + CHECK_INITIALIZED + if (!msg->has_nonce) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); return; @@ -1042,10 +1019,8 @@ void fsm_msgEstimateTxSize(EstimateTxSize *msg) void fsm_msgRecoveryDevice(RecoveryDevice *msg) { - if (storage_isInitialized()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); - return; - } + CHECK_NOT_INITIALIZED + recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, From a1226156636af92ec916179755261421de1de28c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Nov 2016 21:06:39 +0100 Subject: [PATCH 0364/1154] extract CHECK_PIN and CHECK_PIN_UNCACHED --- firmware/fsm.c | 92 ++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 56 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index bd66d387b2..5113ad12dc 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -70,6 +70,18 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); return; \ } +#define CHECK_PIN \ + if (!protectPin(true)) { \ + layoutHome(); \ + return; \ + } + +#define CHECK_PIN_UNCACHED \ + if (!protectPin(false)) { \ + layoutHome(); \ + return; \ + } + void fsm_sendSuccess(const char *text) { RESP_INIT(Success); @@ -184,10 +196,7 @@ void fsm_msgPing(Ping *msg) } if (msg->has_pin_protection && msg->pin_protection) { - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN } if (msg->has_passphrase_protection && msg->passphrase_protection) { @@ -227,10 +236,9 @@ void fsm_msgChangePin(ChangePin *msg) layoutHome(); return; } - if (!protectPin(false)) { - layoutHome(); - return; - } + + CHECK_PIN_UNCACHED + if (removal) { storage_setPin(0); fsm_sendSuccess("PIN removed"); @@ -300,10 +308,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const char *curve = SECP256K1_NAME; if (msg->has_ecdsa_curve_name) { @@ -409,10 +414,7 @@ void fsm_msgSignTx(SignTx *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -444,10 +446,7 @@ void fsm_msgEthereumSignTx(EthereumSignTx *msg) { CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -476,10 +475,9 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) fsm_sendFailure(FailureType_Failure_SyntaxError, "Value length must be a multiple of 16"); return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + + CHECK_PIN + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -564,10 +562,9 @@ void fsm_msgApplySettings(ApplySettings *msg) fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + + CHECK_PIN + if (msg->has_label) { storage_setLabel(msg->label); } @@ -591,10 +588,7 @@ void fsm_msgGetAddress(GetAddress *msg) CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -653,10 +647,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) CHECK_INITIALIZED - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -707,10 +698,7 @@ void fsm_msgSignMessage(SignMessage *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; @@ -782,10 +770,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { @@ -861,10 +846,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + CHECK_PIN uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { @@ -925,10 +907,9 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) if (signing) { const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; - if (!protectPin(true)) { - layoutHome(); - return; - } + + CHECK_PIN + node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; hdnode_get_address_raw(node, coin->address_type, address_raw); @@ -973,10 +954,9 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); return; } - if (!protectPin(true)) { - layoutHome(); - return; - } + + CHECK_PIN + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; From c4d144a82e00f964727b8ab97418196c552f2b39 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Nov 2016 21:39:33 +0100 Subject: [PATCH 0365/1154] extract CHECK_PARAM --- firmware/fsm.c | 107 +++++++++++++++----------------------------- firmware/recovery.c | 6 +-- firmware/reset.c | 6 +-- 3 files changed, 39 insertions(+), 80 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 5113ad12dc..c3adea3948 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -82,6 +82,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); return; \ } +#define CHECK_PARAM(cond, errormsg) \ + if (!(cond)) { \ + fsm_sendFailure(FailureType_Failure_SyntaxError, (errormsg)); \ + layoutHome(); \ + return; \ + } + void fsm_sendSuccess(const char *text) { RESP_INIT(Success); @@ -387,6 +394,8 @@ void fsm_msgResetDevice(ResetDevice *msg) { CHECK_NOT_INITIALIZED + CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, "Invalid seed strength"); + reset_init( msg->has_display_random && msg->display_random, msg->has_strength ? msg->strength : 128, @@ -402,17 +411,8 @@ void fsm_msgSignTx(SignTx *msg) { CHECK_INITIALIZED - if (msg->inputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); - layoutHome(); - return; - } - - if (msg->outputs_count < 1) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one output"); - layoutHome(); - return; - } + CHECK_PARAM(msg->inputs_count > 0, "Transaction must have at least one input"); + CHECK_PARAM(msg->outputs_count > 0, "Transaction must have at least one output"); CHECK_PIN @@ -426,11 +426,9 @@ void fsm_msgSignTx(SignTx *msg) void fsm_msgTxAck(TxAck *msg) { - if (msg->has_tx) { - signing_txack(&(msg->tx)); - } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No transaction provided"); - } + CHECK_PARAM(msg->has_tx, "No transaction provided"); + + signing_txack(&(msg->tx)); } void fsm_msgCancel(Cancel *msg) @@ -463,18 +461,9 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) { CHECK_INITIALIZED - if (!msg->has_key) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); - return; - } - if (!msg->has_value) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No value provided"); - return; - } - if (msg->value.size % 16) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Value length must be a multiple of 16"); - return; - } + CHECK_PARAM(msg->has_key, "No key provided"); + CHECK_PARAM(msg->has_value, "No value provided"); + CHECK_PARAM(msg->value.size % 16 == 0, "Value length must be a multiple of 16"); CHECK_PIN @@ -526,6 +515,10 @@ void fsm_msgClearSession(ClearSession *msg) void fsm_msgApplySettings(ApplySettings *msg) { + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen, "No setting provided"); + + CHECK_PIN + if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -558,12 +551,6 @@ void fsm_msgApplySettings(ApplySettings *msg) return; } } - if (!msg->has_label && !msg->has_language && !msg->has_use_passphrase && !msg->has_homescreen) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No setting provided"); - return; - } - - CHECK_PIN if (msg->has_label) { storage_setLabel(msg->label); @@ -720,14 +707,9 @@ void fsm_msgSignMessage(SignMessage *msg) void fsm_msgVerifyMessage(VerifyMessage *msg) { - if (!msg->has_address) { - fsm_sendFailure(FailureType_Failure_Other, "No address provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_Other, "No message provided"); - return; - } + CHECK_PARAM(msg->has_address, "No address provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; @@ -886,19 +868,12 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) { CHECK_INITIALIZED - if (!msg->has_pubkey) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); - return; - } + CHECK_PARAM(msg->has_pubkey, "No public key provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + CHECK_PARAM(msg->pubkey.size == 33, "Invalid public key provided"); curve_point pubkey; - if (msg->pubkey.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided"); - return; - } + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, "Invalid public key provided"); + bool display_only = msg->has_display_only && msg->display_only; bool signing = msg->address_n_count > 0; RESP_INIT(EncryptedMessage); @@ -937,23 +912,13 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) { CHECK_INITIALIZED - if (!msg->has_nonce) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); - return; - } - if (!msg->has_message) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); - return; - } - if (!msg->has_hmac) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided"); - return; - } + CHECK_PARAM(msg->has_nonce, "No nonce provided"); + CHECK_PARAM(msg->has_message, "No message provided"); + CHECK_PARAM(msg->has_hmac, "No message hmac provided"); + + CHECK_PARAM(msg->nonce.size == 33, "Invalid nonce key provided"); curve_point nonce_pubkey; - if (msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); - return; - } + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, "Invalid nonce provided"); CHECK_PIN @@ -1001,6 +966,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) { CHECK_NOT_INITIALIZED + CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, "Invalid word count"); + recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, diff --git a/firmware/recovery.c b/firmware/recovery.c index e92fc1d5a3..1ed7ab1eb9 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -69,11 +69,7 @@ void next_word(void) { void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter) { - if (_word_count != 12 && _word_count != 18 && _word_count != 24) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid word count (has to be 12, 18 or 24 bits)"); - layoutHome(); - return; - } + if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; word_count = _word_count; enforce_wordlist = _enforce_wordlist; diff --git a/firmware/reset.c b/firmware/reset.c index 0b7f228ede..49db53a719 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -35,11 +35,7 @@ static bool awaiting_entropy = false; void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter) { - if (_strength != 128 && _strength != 192 && _strength != 256) { - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid strength (has to be 128, 192 or 256 bits)"); - layoutHome(); - return; - } + if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; From e019b10642eeb4a898f1016629fbaaa8db7d5c92 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Nov 2016 11:48:52 +0100 Subject: [PATCH 0366/1154] update submodules --- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- vendor/trezor-qrenc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 0b4b667ff1..61af3d5e93 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0b4b667ff1e7cc15e40e983f17eef03ec62921d1 +Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index fa8772dfee..6aac03d2d8 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit fa8772dfee59f426fda238553f4613bcb7d30636 +Subproject commit 6aac03d2d853eadaf9e91452b15381594fcf09b1 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 9e0228f54d..566bcd028d 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380 +Subproject commit 566bcd028d51b615b6620bbb500e72041ae4c614 From a5e2fd9a55872390845aa5196d5ebbff8336e1b0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Nov 2016 11:50:14 +0100 Subject: [PATCH 0367/1154] add webhooks to travis --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5c4eaba755..5653ed0e19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,12 @@ script: - make -C firmware - make -C bootloader - make -C demo + +notifications: + webhooks: + urls: + - http://sway.gk2.sk:5000/travis + - http://163.172.132.178:5000/travis + on_success: always + on_failure: always + on_start: always From 14aa486fa65784c5dfb09a36cef94e2fbe6d9577 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Nov 2016 12:34:30 +0100 Subject: [PATCH 0368/1154] partially revert 4ce4cc560552c8265bb1ac6dfad36639a6a4e5dc for smoother merge --- firmware/recovery.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index 1ed7ab1eb9..088c1f63db 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -135,36 +135,27 @@ void recovery_word(const char *word) strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); } - if (word_index + 1 < 24) { // not the last one - word_index++; - next_word(); - return; - } - - // the last one - strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); - for (uint32_t i = 1; i < word_count; i++) { - strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); - strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); - } - - awaiting_word = false; - layoutHome(); - - if (!mnemonic_check(storage.mnemonic)) { - if (enforce_wordlist) { + if (word_index + 1 == 24) { // last one + uint32_t i; + strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + for (i = 1; i < word_count; i++) { + strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); + strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + } + if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { + storage.has_mnemonic = true; + storage_commit(); + fsm_sendSuccess("Device recovered"); + } else { storage_reset(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); - return; - } else { // not enforcing => mark storage as imported - storage.has_imported = true; - storage.imported = true; } + awaiting_word = false; + layoutHome(); + } else { + word_index++; + next_word(); } - - storage.has_mnemonic = true; - storage_commit(); - fsm_sendSuccess("Device recovered"); } void recovery_abort(void) From acfdb714ffbf4f4dbc0952350c794e16407b9dec Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 23 Nov 2016 12:56:42 +0100 Subject: [PATCH 0369/1154] New Matrix-based recovery --- firmware/fsm.c | 3 +- firmware/recovery-table.h | 112 +++++ firmware/recovery.c | 409 ++++++++++++++--- firmware/recovery.h | 2 +- gen/wordlist/build-recovery-table.pl | 110 +++++ gen/wordlist/recovery_english.txt | 630 +++++++++++++++++++++++++++ 6 files changed, 1210 insertions(+), 56 deletions(-) create mode 100644 firmware/recovery-table.h create mode 100644 gen/wordlist/build-recovery-table.pl create mode 100644 gen/wordlist/recovery_english.txt diff --git a/firmware/fsm.c b/firmware/fsm.c index c3adea3948..7369fee325 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -974,7 +974,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist ? msg->enforce_wordlist : false, + msg->has_enforce_wordlist && msg->enforce_wordlist, + msg->has_type ? msg->type : 0, msg->has_u2f_counter ? msg->u2f_counter : 0 ); } diff --git a/firmware/recovery-table.h b/firmware/recovery-table.h new file mode 100644 index 0000000000..ebf40753fd --- /dev/null +++ b/firmware/recovery-table.h @@ -0,0 +1,112 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* DO NOT EDIT: This file is automatically generated by + * cd ../gen/wordlist + * perl build-recoverytable.pl recovery_english.txt + */ + +static const uint16_t word_table1[82] = +{ + 8192, 8200, 8208, 8217, 8225, 8234, 8243, 8250, 8259, + 12361, 12367, 8280, 8285, 8292, 8297, 8302, 8311, 8318, + 8325, 12429, 12437, 8347, 8356, 8365, 8373, 8382, 8391, + 8400, 8409, 8412, 8417, 8426, 8432, 8439, 8447, 8455, + 8463, 8472, 8480, 8487, 8495, 4408, 4416, 8521, 8530, + 8539, 8548, 8557, 8564, 8573, 8582, 8589, 8597, 8601, + 8609, 8618, 8627, 8634, 4545, 8645, 12750, 12759, 8672, + 8681, 8690, 8695, 8703, 8712, 8721, 8730, 8738, 8746, + 8751, 8757, 8766, 8775, 8782, 4690, 4699, 8804, 8813, + 630, +}; + +static const uint16_t word_table2[631] = +{ + 12288, 12293, 12297, 12298, 12302, 12304, 12306, 12307, 12312, + 12313, 12316, 8225, 8226, 8229, 8233, 8234, 12334, 12337, + 12342, 12345, 8253, 12354, 12357, 12361, 12365, 8274, 12376, + 12378, 12380, 12381, 12385, 12386, 12390, 12394, 12396, 12400, + 8305, 12407, 12410, 8318, 8321, 8327, 12424, 12428, 12433, + 12439, 12443, 12448, 12451, 12456, 12459, 12463, 12465, 12468, + 12471, 12476, 12479, 12482, 12485, 12489, 12494, 12498, 12502, + 12507, 12509, 12515, 12521, 12522, 12527, 12530, 12532, 12535, + 12538, 12541, 12544, 12545, 12546, 12547, 12549, 16647, 16651, + 12559, 16658, 16662, 12569, 12574, 12579, 12582, 12583, 12584, + 12585, 12586, 12588, 16686, 16689, 12599, 12605, 12609, 12611, + 12612, 12615, 12616, 12617, 12618, 12620, 12621, 12626, 12629, + 12635, 12641, 12645, 12650, 12655, 16757, 16761, 12669, 12673, + 12679, 12684, 16782, 16786, 12695, 12699, 12703, 12707, 12713, + 12715, 12716, 12717, 12719, 12723, 12725, 8630, 12727, 12728, + 12730, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12740, + 12746, 12747, 12750, 12751, 12753, 12755, 12758, 12763, 12764, + 12770, 12772, 12775, 12779, 12782, 12786, 12788, 16886, 16891, + 12798, 12801, 12802, 12804, 12805, 12807, 12808, 12811, 12812, + 12813, 12814, 12815, 12820, 12822, 12827, 12830, 12832, 8741, + 8742, 12839, 12841, 8751, 8757, 12857, 12859, 12864, 12866, + 12870, 12874, 12876, 12879, 12884, 12887, 12891, 8799, 8802, + 8808, 8812, 8814, 12914, 12916, 12921, 12925, 12929, 12935, + 8841, 12939, 12942, 12943, 12945, 12947, 12950, 12953, 12955, + 12959, 12961, 12964, 12967, 12973, 12977, 12980, 12985, 12988, + 12993, 12998, 13001, 13005, 13008, 13012, 17112, 17116, 13023, + 13027, 13029, 13031, 13033, 13038, 8943, 13045, 13047, 13049, + 13051, 13056, 13058, 13060, 8966, 8972, 13069, 13070, 13071, + 13072, 13073, 13075, 13076, 13080, 13082, 13087, 13088, 13090, + 13093, 13096, 17194, 17197, 13105, 13107, 13110, 13113, 9018, + 9024, 13121, 13123, 13126, 13128, 13132, 13136, 13140, 13142, + 13145, 13147, 13149, 13151, 13154, 13156, 13160, 13164, 13167, + 13172, 13173, 13174, 13177, 13180, 13183, 9088, 9089, 9091, + 9094, 9095, 13194, 13195, 13196, 13198, 13202, 13206, 13210, + 13213, 13216, 13219, 13223, 13228, 9138, 9144, 9148, 9152, + 13253, 13254, 13255, 13256, 13259, 9164, 9165, 13265, 13266, + 13268, 13270, 13271, 13275, 9180, 13280, 13285, 13288, 13292, + 13295, 13300, 13304, 13309, 13314, 13318, 13322, 13326, 13330, + 13335, 13340, 13344, 9253, 9259, 13356, 13360, 13363, 13366, + 13372, 13373, 13379, 13382, 13387, 13389, 13393, 13394, 13396, + 13398, 13400, 13402, 13406, 13408, 13410, 13412, 13414, 13415, + 13419, 13421, 13424, 13427, 13432, 13436, 13440, 13444, 13448, + 13452, 13457, 9362, 13461, 13463, 13465, 13468, 13470, 13473, + 13475, 13477, 13480, 9387, 13485, 13489, 13491, 13492, 13496, + 9402, 9406, 13503, 13506, 9414, 9417, 9418, 9422, 9423, + 9424, 9427, 9428, 9433, 13534, 13540, 9447, 9448, 9449, + 9453, 9456, 9458, 13557, 13563, 13568, 13574, 13579, 13582, + 13586, 13591, 9500, 13600, 13604, 13609, 13614, 13619, 13624, + 13627, 13632, 13638, 13643, 13645, 17747, 17750, 17755, 17759, + 17764, 13672, 13674, 13677, 13679, 13681, 13685, 9592, 13689, + 13692, 13693, 13696, 13697, 13698, 13701, 13703, 13706, 13708, + 13711, 13713, 13715, 13718, 13721, 13723, 13728, 13729, 13732, + 13735, 13736, 13740, 13744, 13747, 13748, 13752, 13753, 13759, + 13762, 13763, 13765, 9670, 13767, 13773, 13778, 13783, 13788, + 13793, 13798, 13801, 13805, 13810, 13815, 13818, 13822, 13824, + 13828, 13831, 13835, 13839, 13843, 13847, 13853, 13856, 13862, + 13866, 13869, 17970, 17972, 13881, 13883, 13884, 13885, 13889, + 13895, 13899, 13904, 13906, 13911, 13915, 13919, 9827, 9832, + 13933, 13934, 13937, 13939, 13944, 13947, 13949, 13954, 13958, + 13963, 13964, 13969, 13970, 13975, 13978, 9883, 18078, 18084, + 13992, 13997, 14000, 14006, 14011, 14014, 14015, 14018, 14020, + 14024, 14026, 14029, 14032, 14038, 14040, 14044, 14046, 14050, + 9955, 14055, 14059, 14064, 14068, 14071, 14075, 14078, 14080, + 14085, 14088, 14091, 14093, 14095, 14099, 14101, 14104, 14108, + 14111, 14114, 14117, 14119, 14122, 14125, 14128, 18228, 18233, + 14142, 14145, 14151, 14153, 14159, 14160, 14165, 10072, 10078, + 10080, 14178, 14182, 14187, 14191, 10100, 10106, 10108, 10114, + 14211, 14217, 14223, 14228, 14234, 14239, 14245, 14250, 14253, + 14257, 14260, 14264, 14267, 14273, 14278, 14281, 14285, 14291, + 14293, 18394, 18399, 14305, 14310, 14315, 10224, 6134, 6140, + 2048, +}; diff --git a/firmware/recovery.c b/firmware/recovery.c index 088c1f63db..17e68385f7 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -2,6 +2,7 @@ * This file is part of the TREZOR project. * * Copyright (C) 2014 Pavol Rusnak + * Copyright (C) 2016 Jochen Hoenicke * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -17,6 +18,7 @@ * along with this library. If not, see . */ +#include #include "recovery.h" #include "fsm.h" #include "storage.h" @@ -26,16 +28,326 @@ #include "messages.h" #include "rng.h" #include "bip39.h" +#include "oled.h" +#include "usb.h" +#include "types.pb.h" +#include "recovery-table.h" +/* number of words expected in the new seed */ static uint32_t word_count; -static bool awaiting_word = false; + +/* recovery mode: + * 0: not recovering + * 1: recover by scrambled plain text words + * 2: recover by matrix entry + */ +static int awaiting_word = 0; + +/* True if we should check that seed corresponds to bip39. + */ static bool enforce_wordlist; + +/* For scrambled recovery Trezor may ask for faked words if + * seed is short. This contains the fake word. + */ static char fake_word[12]; + +/* Word position in the seed that we are currently asking for. + * This is 0 if we ask for a fake word. Only for scrambled recovery. + */ static uint32_t word_pos; + +/* Scrambled recovery: How many words has the user already entered. + * Matrix recovery: How many digits has the user already entered. + */ static uint32_t word_index; + +/* Order in which we ask for the words. It holds that + * word_order[word_index] == word_pos. Only for scrambled recovery. + */ static char word_order[24]; + +/* The recovered seed. This is filled during the recovery process. + */ static char words[24][12]; +/* The "pincode" of the current word. This is basically the "pin" + * that the user would have entered for the current word if the words + * were displayed in alphabetical order. Note that it is base 9, not + * base 10. Only for matrix recovery. + */ +static uint16_t word_pincode; + +/* The pinmatrix currently displayed on screen. + * Only for matrix recovery. + */ +static uint8_t word_matrix[9]; + +#define MASK_IDX(x) ((x) & 0xfff) +#define TABLE1(x) MASK_IDX(word_table1[x]) +#define TABLE2(x) MASK_IDX(word_table2[x]) + +/* Helper function to format a two digit number. + * Parameter dest is buffer containing the string. It should already + * start with "##th". The number is written in place. + * Parameter number gives the number that we should format. + */ +static void format_number(char *dest, int number) { + if (number < 10) { + dest[0] = ' '; + } else { + dest[0] = '0' + number / 10; + } + dest[1] = '0' + number % 10; + if (number == 1 || number == 21) { + dest[2] = 's'; dest[3] = 't'; + } else if (number == 2 || number == 22) { + dest[2] = 'n'; dest[3] = 'd'; + } else if (number == 3 || number == 23) { + dest[2] = 'r'; dest[3] = 'd'; + } +} + +/* Send a request for a new word/matrix code to the PC. + */ +static void recovery_request(void) { + WordRequest resp; + memset(&resp, 0, sizeof(WordRequest)); + resp.has_type = true; + resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain + : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 + : WordRequestType_WordRequestType_Matrix9; + msg_write(MessageType_MessageType_WordRequest, &resp); +} + +/* Called when the last word was entered. + * Check mnemonic and send success/failure. + */ +static void recovery_done(void) { + uint32_t i; + strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + for (i = 1; i < word_count; i++) { + strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); + strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + } + if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { + storage.has_mnemonic = true; + if (!enforce_wordlist) { + // not enforcing => mark storage as imported + storage.has_imported = true; + storage.imported = true; + } + storage_commit(); + fsm_sendSuccess("Device recovered"); + } else { + storage_reset(); + fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); + } + awaiting_word = 0; + layoutHome(); +} + +/* Helper function for matrix recovery: + * Formats a string describing the word range from first to last where + * prefixlen gives the number of characters in first and last that are + * significant, i.e. the word before first or the word after last differ + * exactly at the prefixlen-th character. + * + * Invariants: + * memcmp("first - 1", first, prefixlen) != 0 + * memcmp(last, "last + 1", prefixlen) != 0 + * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. + */ +static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { + // assert prefixlen < 4 + int i; + char *dest = choice; + for (i = 0; i < prefixlen; i++) { + *dest++ = toupper((int) first[i]); + } + if (first[0] != last[0]) { + /* special case WI-Z; also used for T-Z, etc. */ + *dest++ = '-'; + *dest++ = toupper((int) last[0]); + } else if (last[prefixlen-1] == first[prefixlen-1]) { + /* single prefix */ + } else if (prefixlen < 3) { + /* AB-AC, etc. */ + *dest++ = '-'; + for (i = 0; i < prefixlen; i++) { + *dest++ = toupper((int) last[i]); + } + } else { + /* RE[A-M] etc. */ + /* remove last and replace with space */ + dest[-1] = ' '; + if (first[prefixlen - 1]) { + /* handle special case: CAN[-D] */ + *dest++ = toupper((int)first[prefixlen - 1]); + } + *dest++ = '-'; + *dest++ = toupper((int) last[prefixlen - 1]); + } + *dest++ = 0; +} + +/* Helper function for matrix recovery: + * Display the recovery matrix given in choices. If twoColumn is set + * use 2x3 layout, otherwise 3x3 layout. Also generates a random + * scrambling and stores it in word_matrix. + */ +static void display_choices(bool twoColumn, char choices[9][12], int num) +{ + int i; + int nColumns = twoColumn ? 2 : 3; + int displayedChoices = nColumns * 3; + int row, col; + for (i = 0; i < displayedChoices; i++) { + word_matrix[i] = i; + } + /* scramble matrix */ + random_permute((char*)word_matrix, displayedChoices); + + if (word_index % 4 == 0) { + char desc[] = "##th word"; + int nr = (word_index / 4) + 1; + format_number(desc, nr); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL); + } else { + oledBox(0, 18, 127, 63, false); + } + + for (row = 0; row < 3; row ++) { + int y = 55 - row * 11; + for (col = 0; col < nColumns; col++) { + int x = twoColumn ? 64 * col + 32 : 42 * col + 22; + int choice = word_matrix[nColumns*row + col]; + const char *text = choice < num ? choices[choice] : "-"; + oledDrawString(x - oledStringWidth(text)/2, y, text); + } + } + oledRefresh(); + + /* avoid picking out of range numbers */ + for (i = 0; i < displayedChoices; i++) { + if (word_matrix[i] > num) + word_matrix[i] = 0; + } + /* two column layout: middle column = right column */ + if (twoColumn) { + static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 }; + for (i = 8; i >= 2; i--) { + word_matrix[i] = word_matrix[twolayout[i]]; + } + } +} + +/* Helper function for matrix recovery: + * Generates a new matrix and requests the next pin. + */ +static void next_matrix(void) { + const char * const *wl = mnemonic_wordlist(); + char word_choices[9][12]; + uint32_t i, idx, first, num; + bool last = (word_index % 4) == 3; + + switch (word_index % 4) { + case 3: + idx = TABLE1(word_pincode / 9) + word_pincode % 9; + first = word_table2[idx] & 0xfff; + num = (word_table2[idx+1] & 0xfff) - first; + for (i = 0; i < num; i++) { + strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); + } + break; + + case 2: + idx = TABLE1(word_pincode); + num = TABLE1(word_pincode + 1) - idx; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table2[idx + i] >> 12), + wl[TABLE2(idx + i)], + wl[TABLE2(idx + i + 1) - 1]); + } + break; + + case 1: + idx = word_pincode * 9; + num = 9; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table1[idx + i] >> 12), + wl[TABLE2(TABLE1(idx + i))], + wl[TABLE2(TABLE1(idx + i + 1)) - 1]); + } + break; + + case 0: + num = 9; + for (i = 0; i < num; i++) { + add_choice(word_choices[i], 1, + wl[TABLE2(TABLE1(9*i))], + wl[TABLE2(TABLE1(9*(i+1)))-1]); + } + break; + } + display_choices(last, word_choices, num); + + recovery_request(); +} + +/* Function called when a digit was entered by user. + * digit: ascii code of the entered digit ('1'-'9') or + * '\x08' for backspace. + */ +static void recovery_digit(const char digit) { + if (digit == 8) { + /* backspace: undo */ + if ((word_index % 4) == 0) { + /* undo complete word */ + if (word_index > 0) + word_index -= 4; + } else { + word_index--; + word_pincode /= 9; + } + next_matrix(); + return; + } + + if (digit < '1' || digit > '9') { + recovery_request(); + return; + } + + int choice = word_matrix[digit - '1']; + if ((word_index % 4) == 3) { + /* received final word */ + int y = 54 - ((digit - '1')/3)*11; + int x = 64 * (((digit - '1') % 3) > 0); + oledInvert(x, y, x + 63, y + 9); + oledRefresh(); + usbSleep(250); + + int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; + uint32_t widx = word_index / 4; + + word_pincode = 0; + strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx])); + if (widx + 1 == word_count) { + recovery_done(); + return; + } + /* next word */ + } else { + word_pincode = word_pincode * 9 + choice; + } + word_index++; + next_matrix(); +} + +/* Helper function for scrambled recovery: + * Ask the user for the next word. + */ void next_word(void) { word_pos = word_order[word_index]; if (word_pos == 0) { @@ -45,29 +357,13 @@ void next_word(void) { } else { fake_word[0] = 0; char desc[] = "##th word"; - if (word_pos < 10) { - desc[0] = ' '; - } else { - desc[0] = '0' + word_pos / 10; - } - desc[1] = '0' + word_pos % 10; - if (word_pos == 1 || word_pos == 21) { - desc[2] = 's'; desc[3] = 't'; - } else - if (word_pos == 2 || word_pos == 22) { - desc[2] = 'n'; desc[3] = 'd'; - } else - if (word_pos == 3 || word_pos == 23) { - desc[2] = 'r'; desc[3] = 'd'; - } + format_number(desc, word_pos); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); } - WordRequest resp; - memset(&resp, 0, sizeof(WordRequest)); - msg_write(MessageType_MessageType_WordRequest, &resp); + recovery_request(); } -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter) +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter) { if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; @@ -86,27 +382,27 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_setLabel(label); storage_setU2FCounter(u2f_counter); - uint32_t i; - for (i = 0; i < word_count; i++) { - word_order[i] = i + 1; + if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { + awaiting_word = 2; + word_index = 0; + next_matrix(); + } else { + uint32_t i; + for (i = 0; i < word_count; i++) { + word_order[i] = i + 1; + } + for (i = word_count; i < 24; i++) { + word_order[i] = 0; + } + random_permute(word_order, 24); + awaiting_word = 1; + word_index = 0; + next_word(); } - for (i = word_count; i < 24; i++) { - word_order[i] = 0; - } - random_permute(word_order, 24); - awaiting_word = true; - word_index = 0; - next_word(); } -void recovery_word(const char *word) +static void recovery_scrambledword(const char *word) { - if (!awaiting_word) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); - layoutHome(); - return; - } - if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { storage_reset(); @@ -136,33 +432,38 @@ void recovery_word(const char *word) } if (word_index + 1 == 24) { // last one - uint32_t i; - strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); - for (i = 1; i < word_count; i++) { - strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); - strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); - } - if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { - storage.has_mnemonic = true; - storage_commit(); - fsm_sendSuccess("Device recovered"); - } else { - storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); - } - awaiting_word = false; - layoutHome(); + recovery_done(); } else { word_index++; next_word(); } } +/* Function called when a word was entered by user. Used + * for scrambled recovery. + */ +void recovery_word(const char *word) +{ + switch (awaiting_word) { + case 2: + recovery_digit(word[0]); + break; + case 1: + recovery_scrambledword(word); + break; + default: + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); + break; + } +} + +/* Abort recovery. + */ void recovery_abort(void) { if (awaiting_word) { layoutHome(); - awaiting_word = false; + awaiting_word = 0; } } diff --git a/firmware/recovery.h b/firmware/recovery.h index e1de844c42..ac463d28e2 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -23,7 +23,7 @@ #include #include -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t u2f_counter); +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter); void recovery_word(const char *word); void recovery_abort(void); const char *recovery_get_fake_word(void); diff --git a/gen/wordlist/build-recovery-table.pl b/gen/wordlist/build-recovery-table.pl new file mode 100644 index 0000000000..c67325f532 --- /dev/null +++ b/gen/wordlist/build-recovery-table.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl +print <<'EOF'; +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2016 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +EOF + +my @arr1; +my @arr2; +my $x = 0; +my $l = "00"; +my @words; +while (<>) { + $_ =~ /([1-9]{2})[1-9] ([1-6]):(.*)/; + my $n = $1; + my $c = $2; + my @nw = split(",", $3); + die if $c != @nw; + die if $c > 6; + push @words, @nw; + if ($n ne $l) { + $len = @arr2; + die if $len - $arr1[-1] > 9; + push @arr1, $len; + } + push @arr2, $x; + $x += $c; + $l = $n; +} +$len = @arr2; +push @arr1, $len; +push @arr2, $x; + +sub computerange($$$) { + my ($i1, $i2, $entries) = @_; + $prev = $i1 == 0 ? "_" : $words[$i1 - 1]; + $first = $words[$i1]; + $last = $words[$i2-1]; + $next = $i2 == @words ? "_" : $words[$i2]; + my $j; + for ($j = 0; $j < 5; $j++) { + last if substr($first, 0, $j+1) ne substr($last, 0, $j+1); + last if substr($prev, 0, $j) ne substr($first, 0, $j) + && substr($next, 0, $j) ne substr($last, 0, $j); + } + $prefix = substr($first, 0, $j); + $range = ""; + $rng = 0; + if (substr($prev, 0, $j) eq substr($first, 0, $j) + || substr($last, 0, $j) eq substr($next, 0, $j)) { + $range = "[".substr($first, $j, 1) . "-". substr($last, $j, 1)."]"; + $rng++; + if ($j <= 1) { + $range = substr($first,0, $j+1)."-".substr($last,0,$j+1); + $prefix= ""; + } + } + if (substr($prev, 0, $j+1) eq substr($first, 0, $j+1) + || substr($last, 0, $j+1) eq substr($next, 0, $j+1)) { + $j = 0; $rng = 2; + } + #printf STDERR " # %1d: %9s - %9s = \U$prefix$range\E\n", $entries, $first, $last; + return $j + $rng; +} + +print << 'EOF'; +/* DO NOT EDIT: This file is automatically generated by + * cd ../gen/wordlist + * perl build-recoverytable.pl recovery_english.txt + */ + +EOF + +$len = @arr1; +print "static const uint16_t word_table1[$len] =\n"; +print "{"; +for ($i = 0; $i< @arr1; $i++) { + print "\n " if ($i % 9 == 0); + $prefixlen = computerange($arr2[$arr1[$i]], $arr2[$arr1[$i+1]], $arr1[$i+1]-$arr1[$i]); + $prefixlen = 0 if ($i == @arr1 - 1); + printf(" %5d,", $arr1[$i] + 4096 * $prefixlen); +} +print "\n};\n\n"; + +$len = @arr2; +print "static const uint16_t word_table2[$len] =\n"; +print "{"; +for ($i = 0; $i< @arr2; $i++) { + print "\n " if ($i % 9 == 0); + $prefixlen = computerange($arr2[$i], $arr2[$i+1], $arr2[$i+1]-$arr2[$i]); + $prefixlen = 0 if ($i == @arr2 - 1); + printf(" %5d,", $arr2[$i] + 4096 * $prefixlen); +} +print "\n};\n"; diff --git a/gen/wordlist/recovery_english.txt b/gen/wordlist/recovery_english.txt new file mode 100644 index 0000000000..ab85f326bf --- /dev/null +++ b/gen/wordlist/recovery_english.txt @@ -0,0 +1,630 @@ +111 5:abandon,ability,able,about,above +112 4:absent,absorb,abstract,absurd +113 1:abuse +114 4:access,accident,account,accuse +115 2:achieve,acid +116 2:acoustic,acquire +117 1:across +118 5:act,action,actor,actress,actual +121 1:adapt +122 3:add,addict,address +123 5:adjust,admit,adult,advance,advice +124 1:aerobic +125 3:affair,afford,afraid +126 4:again,age,agent,agree +127 1:ahead +128 4:aim,air,airport,aisle +131 3:alarm,album,alcohol +132 5:alert,alien,all,alley,allow +133 3:almost,alone,alpha +134 4:already,also,alter,always +135 5:amateur,amazing,among,amount,amused +136 3:analyst,anchor,ancient +137 4:anger,angle,angry,animal +138 4:ankle,announce,annual,another +139 5:answer,antenna,antique,anxiety,any +141 6:apart,apology,appear,apple,approve,april +142 2:arch,arctic +143 2:area,arena +144 1:argue +145 4:arm,armed,armor,army +146 1:around +147 4:arrange,arrest,arrive,arrow +148 4:art,artefact,artist,artwork +151 2:ask,aspect +152 4:assault,asset,assist,assume +153 1:asthma +154 6:athlete,atom,attack,attend,attitude,attract +155 3:auction,audit,august +156 4:aunt,author,auto,autumn +157 3:average,avocado,avoid +158 6:awake,aware,away,awesome,awful,awkward +159 1:axis +161 4:baby,bachelor,bacon,badge +162 5:bag,balance,balcony,ball,bamboo +163 6:banana,banner,bar,barely,bargain,barrel +164 4:base,basic,basket,battle +165 5:beach,bean,beauty,because,become +166 3:beef,before,begin +167 5:behave,behind,believe,below,belt +168 3:bench,benefit,best +169 4:betray,better,between,beyond +171 2:bicycle,bid +172 3:bike,bind,biology +173 3:bird,birth,bitter +174 5:black,blade,blame,blanket,blast +175 3:bleak,bless,blind +176 3:blood,blossom,blouse +177 3:blue,blur,blush +181 4:board,boat,body,boil +182 5:bomb,bone,bonus,book,boost +183 4:border,boring,borrow,boss +184 4:bottom,bounce,box,boy +185 5:bracket,brain,brand,brass,brave +186 2:bread,breeze +187 6:brick,bridge,brief,bright,bring,brisk +188 6:broccoli,broken,bronze,broom,brother,brown +189 1:brush +191 5:bubble,buddy,budget,buffalo,build +192 3:bulb,bulk,bullet +193 2:bundle,bunker +194 3:burden,burger,burst +195 3:bus,business,busy +196 3:butter,buyer,buzz +211 3:cabbage,cabin,cable +212 1:cactus +213 1:cage +214 1:cake +215 2:call,calm +216 2:camera,camp +221 4:can,canal,cancel,candy +222 4:cannon,canoe,canvas,canyon +223 3:capable,capital,captain +224 4:car,carbon,card,cargo +225 3:carpet,carry,cart +226 5:case,cash,casino,castle,casual +227 5:cat,catalog,catch,category,cattle +228 3:caught,cause,caution +229 1:cave +231 1:ceiling +232 1:celery +233 1:cement +234 2:census,century +235 2:cereal,certain +241 3:chair,chalk,champion +243 6:change,chaos,chapter,charge,chase,chat +245 6:cheap,check,cheese,chef,cherry,chest +246 4:chicken,chief,child,chimney +247 2:choice,choose +248 1:chronic +249 3:chuckle,chunk,churn +251 1:cigar +252 1:cinnamon +253 1:circle +254 2:citizen,city +255 1:civil +261 5:claim,clap,clarify,claw,clay +262 3:clean,clerk,clever +263 6:click,client,cliff,climb,clinic,clip +264 6:clock,clog,close,cloth,cloud,clown +265 4:club,clump,cluster,clutch +271 5:coach,coast,coconut,code,coffee +272 5:coil,coin,collect,color,column +273 6:combine,come,comfort,comic,common,company +274 4:concert,conduct,confirm,congress +275 4:connect,consider,control,convince +276 4:cook,cool,copper,copy +277 6:coral,core,corn,correct,cost,cotton +278 5:couch,country,couple,course,cousin +279 2:cover,coyote +281 4:crack,cradle,craft,cram +283 5:crane,crash,crater,crawl,crazy +285 4:cream,credit,creek,crew +286 4:cricket,crime,crisp,critic +287 4:crop,cross,crouch,crowd +288 6:crucial,cruel,cruise,crumble,crunch,crush +289 2:cry,crystal +291 1:cube +292 1:culture +293 2:cup,cupboard +294 4:curious,current,curtain,curve +295 2:cushion,custom +296 1:cute +299 1:cycle +311 1:dad +312 2:damage,damp +313 2:dance,danger +314 1:daring +315 1:dash +316 1:daughter +317 1:dawn +318 1:day +321 1:deal +322 2:debate,debris +323 6:decade,december,decide,decline,decorate,decrease +324 1:deer +325 3:defense,define,defy +326 1:degree +327 2:delay,deliver +328 2:demand,demise +331 3:denial,dentist,deny +332 5:depart,depend,deposit,depth,deputy +333 1:derive +334 6:describe,desert,design,desk,despair,destroy +335 2:detail,detect +336 3:develop,device,devote +341 4:diagram,dial,diamond,diary +342 3:dice,diesel,diet +343 4:differ,digital,dignity,dilemma +344 2:dinner,dinosaur +345 2:direct,dirt +346 5:disagree,discover,disease,dish,dismiss +347 3:disorder,display,distance +348 3:divert,divide,divorce +349 1:dizzy +351 2:doctor,document +352 1:dog +353 2:doll,dolphin +354 1:domain +355 3:donate,donkey,donor +356 1:door +357 1:dose +358 1:double +359 1:dove +361 5:draft,dragon,drama,drastic,draw +362 2:dream,dress +363 5:drift,drill,drink,drip,drive +364 3:drop,drum,dry +365 2:duck,dumb +366 5:dune,during,dust,dutch,duty +368 1:dwarf +369 1:dynamic +371 2:eager,eagle +372 6:early,earn,earth,easily,east,easy +373 6:echo,ecology,economy,edge,edit,educate +374 4:effort,egg,eight,either +375 2:elbow,elder +376 5:electric,elegant,element,elephant,elevator +377 2:elite,else +378 4:embark,embody,embrace,emerge +379 4:emotion,employ,empower,empty +381 2:enable,enact +382 3:end,endless,endorse +383 5:enemy,energy,enforce,engage,engine +384 3:enhance,enjoy,enlist +385 4:enough,enrich,enroll,ensure +386 4:enter,entire,entry,envelope +387 3:episode,equal,equip +388 6:era,erase,erode,erosion,error,erupt +389 4:escape,essay,essence,estate +391 2:eternal,ethics +392 4:evidence,evil,evoke,evolve +393 2:exact,example +394 5:excess,exchange,excite,exclude,excuse +395 4:execute,exercise,exhaust,exhibit +396 4:exile,exist,exit,exotic +397 6:expand,expect,expire,explain,expose,express +398 2:extend,extra +399 2:eye,eyebrow +411 3:fabric,face,faculty +412 1:fade +413 2:faint,faith +414 2:fall,false +415 3:fame,family,famous +416 3:fan,fancy,fantasy +417 2:farm,fashion +418 4:fat,fatal,father,fatigue +419 2:fault,favorite +421 3:feature,february,federal +422 3:fee,feed,feel +423 6:female,fence,festival,fetch,fever,few +431 4:fiber,fiction,field,figure +432 3:file,film,filter +433 5:final,find,fine,finger,finish +434 3:fire,firm,first +435 5:fiscal,fish,fit,fitness,fix +441 5:flag,flame,flash,flat,flavor +442 3:flee,flight,flip +443 4:float,flock,floor,flower +444 3:fluid,flush,fly +445 4:foam,focus,fog,foil +446 4:fold,follow,food,foot +447 4:force,forest,forget,fork +448 3:fortune,forum,forward +449 4:fossil,foster,found,fox +451 2:fragile,frame +452 2:frequent,fresh +453 2:friend,fringe +454 5:frog,front,frost,frown,frozen +455 1:fruit +458 6:fuel,fun,funny,furnace,fury,future +461 2:gadget,gain +462 2:galaxy,gallery +463 2:game,gap +464 5:garage,garbage,garden,garlic,garment +465 2:gas,gasp +466 2:gate,gather +467 2:gauge,gaze +471 6:general,genius,genre,gentle,genuine,gesture +472 1:ghost +473 1:giant +474 1:gift +475 1:giggle +476 1:ginger +477 2:giraffe,girl +478 1:give +481 4:glad,glance,glare,glass +482 2:glide,glimpse +483 5:globe,gloom,glory,glove,glow +484 1:glue +486 2:goat,goddess +487 3:gold,good,goose +488 3:gorilla,gospel,gossip +489 2:govern,gown +491 3:grab,grace,grain +492 4:grant,grape,grass,gravity +493 2:great,green +494 3:grid,grief,grit +495 3:grocery,group,grow +496 1:grunt +497 6:guard,guess,guide,guilt,guitar,gun +498 1:gym +511 2:habit,hair +512 3:half,hammer,hamster +513 2:hand,happy +514 4:harbor,hard,harsh,harvest +515 4:hat,have,hawk,hazard +516 4:head,health,heart,heavy +517 2:hedgehog,height +518 3:hello,helmet,help +519 2:hen,hero +521 2:hidden,high +522 2:hill,hint +523 3:hip,hire,history +524 2:hobby,hockey +525 4:hold,hole,holiday,hollow +526 4:home,honey,hood,hope +527 3:horn,horror,horse +528 5:hospital,host,hotel,hour,hover +531 1:hub +532 1:huge +533 3:human,humble,humor +534 3:hundred,hungry,hunt +535 3:hurdle,hurry,hurt +536 1:husband +539 1:hybrid +541 2:ice,icon +542 3:idea,identify,idle +543 1:ignore +544 3:ill,illegal,illness +545 1:image +546 1:imitate +547 2:immense,immune +548 4:impact,impose,improve,impulse +551 4:inch,include,income,increase +552 4:index,indicate,indoor,industry +553 3:infant,inflict,inform +554 3:inhale,inherit,initial +555 3:inject,injury,inmate +556 4:inner,innocent,input,inquiry +557 5:insane,insect,inside,inspire,install +558 6:intact,interest,into,invest,invite,involve +559 6:iron,island,isolate,issue,item,ivory +561 4:jacket,jaguar,jar,jazz +562 4:jealous,jeans,jelly,jewel +563 5:job,join,joke,journey,joy +564 1:judge +565 1:juice +566 1:jump +567 3:jungle,junior,junk +568 1:just +571 1:kangaroo +572 4:keen,keep,ketchup,key +573 1:kick +574 2:kid,kidney +575 2:kind,kingdom +576 1:kiss +577 4:kit,kitchen,kite,kitten +578 1:kiwi +579 4:knee,knife,knock,know +581 5:lab,label,labor,ladder,lady +582 3:lake,lamp,language +583 4:laptop,large,later,latin +584 3:laugh,laundry,lava +585 5:law,lawn,lawsuit,layer,lazy +586 4:leader,leaf,learn,leave +587 5:lecture,left,leg,legal,legend +588 5:leisure,lemon,lend,length,lens +589 4:leopard,lesson,letter,level +591 4:liar,liberty,library,license +592 4:life,lift,light,like +593 4:limb,limit,link,lion +594 5:liquid,list,little,live,lizard +595 5:load,loan,lobster,local,lock +596 4:logic,lonely,long,loop +597 5:lottery,loud,lounge,love,loyal +598 6:lucky,luggage,lumber,lunar,lunch,luxury +599 1:lyrics +611 4:machine,mad,magic,magnet +612 3:maid,mail,main +613 3:major,make,mammal +614 6:man,manage,mandate,mango,mansion,manual +615 1:maple +616 6:marble,march,margin,marine,market,marriage +617 3:mask,mass,master +618 5:match,material,math,matrix,matter +619 2:maximum,maze +621 4:meadow,mean,measure,meat +622 1:mechanic +623 2:medal,media +624 2:melody,melt +625 2:member,memory +626 2:mention,menu +627 4:mercy,merge,merit,merry +628 2:mesh,message +629 2:metal,method +631 2:middle,midnight +632 2:milk,million +633 1:mimic +634 4:mind,minimum,minor,minute +635 2:miracle,mirror +636 3:misery,miss,mistake +637 3:mix,mixed,mixture +641 5:mobile,model,modify,mom,moment +642 4:monitor,monkey,monster,month +643 4:moon,moral,more,morning +644 4:mosquito,mother,motion,motor +645 4:mountain,mouse,move,movie +646 4:much,muffin,mule,multiply +647 5:muscle,museum,mushroom,music,must +648 1:mutual +649 3:myself,mystery,myth +651 2:naive,name +652 2:napkin,narrow +653 3:nasty,nation,nature +654 2:near,neck +655 3:need,negative,neglect +656 2:neither,nephew +657 2:nerve,nest +658 3:net,network,neutral +659 3:never,news,next +661 2:nice,night +662 4:noble,noise,nominee,noodle +663 2:normal,north +664 1:nose +665 4:notable,note,nothing,notice +666 2:novel,now +669 4:nuclear,number,nurse,nut +671 1:oak +672 3:obey,object,oblige +673 4:obscure,observe,obtain,obvious +675 3:occur,ocean,october +676 1:odor +677 4:off,offer,office,often +678 1:oil +679 1:okay +681 3:old,olive,olympic +682 1:omit +683 5:once,one,onion,online,only +684 5:open,opera,opinion,oppose,option +691 6:orange,orbit,orchard,order,ordinary,organ +692 3:orient,original,orphan +693 1:ostrich +694 1:other +695 4:outdoor,outer,output,outside +696 3:oval,oven,over +697 2:own,owner +698 3:oxygen,oyster,ozone +711 6:pact,paddle,page,pair,palace,palm +712 5:panda,panel,panic,panther,paper +713 6:parade,parent,park,parrot,party,pass +714 5:patch,path,patient,patrol,pattern +715 3:pause,pave,payment +716 4:peace,peanut,pear,peasant +717 5:pelican,pen,penalty,pencil,people +718 5:pepper,perfect,permit,person,pet +719 4:phone,photo,phrase,physical +721 4:piano,picnic,picture,piece +722 5:pig,pigeon,pill,pilot,pink +723 5:pioneer,pipe,pistol,pitch,pizza +724 5:place,planet,plastic,plate,play +725 5:please,pledge,pluck,plug,plunge +726 3:poem,poet,point +727 5:polar,pole,police,pond,pony +728 6:pool,popular,portion,position,possible,post +729 5:potato,pottery,poverty,powder,power +731 2:practice,praise +732 6:predict,prefer,prepare,present,pretty,prevent +733 3:price,pride,primary +735 5:print,priority,prison,private,prize +736 4:problem,process,produce,profit +737 5:program,project,promote,proof,property +739 4:prosper,protect,proud,provide +741 2:public,pudding +742 3:pull,pulp,pulse +743 2:pumpkin,punch +744 2:pupil,puppy +745 4:purchase,purity,purpose,purse +746 3:push,put,puzzle +749 1:pyramid +751 3:quality,quantum,quarter +752 1:question +753 3:quick,quit,quiz +754 1:quote +761 1:rabbit +762 3:raccoon,race,rack +763 2:radar,radio +764 3:rail,rain,raise +765 2:rally,ramp +766 3:ranch,random,range +767 2:rapid,rare +768 2:rate,rather +769 3:raven,raw,razor +771 3:ready,real,reason +772 2:rebel,rebuild +773 5:recall,receive,recipe,record,recycle +774 1:reduce +775 3:reflect,reform,refuse +776 3:region,regret,regular +777 1:reject +778 4:relax,release,relief,rely +779 4:remain,remember,remind,remove +781 3:render,renew,rent +782 1:reopen +783 4:repair,repeat,replace,report +784 1:require +785 6:rescue,resemble,resist,resource,response,result +786 3:retire,retreat,return +787 1:reunion +788 2:reveal,review +789 1:reward +791 1:rhythm +792 6:rib,ribbon,rice,rich,ride,ridge +793 5:rifle,right,rigid,ring,riot +794 5:ripple,risk,ritual,rival,river +795 5:road,roast,robot,robust,rocket +796 5:romance,roof,rookie,room,rose +797 5:rotate,rough,round,route,royal +798 3:rubber,rude,rug +799 4:rule,run,runway,rural +811 5:sad,saddle,sadness,safe,sail +812 5:salad,salmon,salon,salt,salute +813 3:same,sample,sand +814 4:satisfy,satoshi,sauce,sausage +815 2:save,say +816 4:scale,scan,scare,scatter +817 3:scene,scheme,school +818 4:science,scissors,scorpion,scout +819 4:scrap,screen,script,scrub +821 4:sea,search,season,seat +822 4:second,secret,section,security +823 6:seed,seek,segment,select,sell,seminar +824 3:senior,sense,sentence +825 6:series,service,session,settle,setup,seven +831 4:shadow,shaft,shallow,share +832 3:shed,shell,sheriff +833 5:shield,shift,shine,ship,shiver +834 2:shock,shoe +836 5:shoot,shop,short,shoulder,shove +837 2:shrimp,shrug +838 1:shuffle +839 1:shy +841 4:sibling,sick,side,siege +842 6:sight,sign,silent,silk,silly,silver +843 4:similar,simple,since,sing +844 5:siren,sister,situate,six,size +845 2:skate,sketch +846 5:ski,skill,skin,skirt,skull +847 4:slab,slam,sleep,slender +848 4:slice,slide,slight,slim +849 4:slogan,slot,slow,slush +851 5:small,smart,smile,smoke,smooth +852 5:snack,snake,snap,sniff,snow +853 1:soap +854 3:soccer,social,sock +855 2:soda,soft +856 5:solar,soldier,solid,solution,solve +857 3:someone,song,soon +858 2:sorry,sort +859 5:soul,sound,soup,source,south +861 4:space,spare,spatial,spawn +862 5:speak,special,speed,spell,spend +863 1:sphere +864 5:spice,spider,spike,spin,spirit +865 1:split +866 5:spoil,sponsor,spoon,sport,spot +867 3:spray,spread,spring +868 1:spy +869 3:square,squeeze,squirrel +871 6:stable,stadium,staff,stage,stairs,stamp +872 4:stand,start,state,stay +873 5:steak,steel,stem,step,stereo +874 3:stick,still,sting +875 6:stock,stomach,stone,stool,story,stove +876 5:strategy,street,strike,strong,struggle +877 3:student,stuff,stumble +878 1:style +881 3:subject,submit,subway +882 2:success,such +883 4:sudden,suffer,sugar,suggest +884 2:suit,summer +885 3:sun,sunny,sunset +886 3:super,supply,supreme +887 6:sure,surface,surge,surprise,surround,survey +888 2:suspect,sustain +891 4:swallow,swamp,swap,swarm +892 2:swear,sweet +893 4:swift,swim,swing,switch +894 1:sword +898 4:symbol,symptom,syrup,system +911 4:table,tackle,tag,tail, +912 5:talent,talk,tank,tape,target +913 4:task,taste,tattoo,taxi +914 3:teach,team,tell +915 4:ten,tenant,tennis,tent +916 3:term,test,text +921 2:thank,that +922 5:theme,then,theory,there,they +923 3:thing,this,thought +924 3:three,thrive,throw +925 2:thumb,thunder +926 2:ticket,tide +927 4:tiger,tilt,timber,time +928 2:tiny,tip +929 3:tired,tissue,title +931 4:toast,tobacco,today,toddler +932 3:toe,together,toilet +933 3:token,tomato,tomorrow +934 3:tone,tongue,tonight +935 2:tool,tooth +936 3:top,topic,topple +937 3:torch,tornado,tortoise +938 3:toss,total,tourist +939 4:toward,tower,town,toy +941 5:track,trade,traffic,tragic,train +942 5:transfer,trap,trash,travel,tray +943 3:treat,tree,trend +944 6:trial,tribe,trick,trigger,trim,trip +945 2:trophy,trouble +946 6:truck,true,truly,trumpet,trust,truth +947 1:try +951 5:tube,tuition,tumble,tuna,tunnel +952 3:turkey,turn,turtle +953 6:twelve,twenty,twice,twin,twist,two +954 2:type,typical +961 2:ugly,umbrella +962 4:unable,unaware,uncle,uncover +963 5:under,undo,unfair,unfold,unhappy +964 4:uniform,unique,unit,universe +965 5:unknown,unlock,until,unusual,unveil +966 6:update,upgrade,uphold,upon,upper,upset +967 2:urban,urge +968 6:usage,use,used,useful,useless,usual +969 1:utility +971 6:vacant,vacuum,vague,valid,valley,valve +972 6:van,vanish,vapor,various,vast,vault +973 5:vehicle,velvet,vendor,venture,venue +974 6:verb,verify,version,very,vessel,veteran +975 5:viable,vibrant,vicious,victory,video +976 6:view,village,vintage,violin,virtual,virus +977 5:visa,visit,visual,vital,vivid +978 3:vocal,voice,void +979 4:volcano,volume,vote,voyage +981 3:wage,wagon,wait +982 4:walk,wall,walnut,want +983 3:warfare,warm,warrior +984 6:wash,wasp,waste,water,wave,way +985 5:wealth,weapon,wear,weasel,weather +986 3:web,wedding,weekend +987 4:weird,welcome,west,wet +988 6:whale,what,wheat,wheel,when,where +989 2:whip,whisper +991 5:wide,width,wife,wild,will +992 5:win,window,wine,wing,wink +993 2:winner,winter +994 5:wire,wisdom,wise,wish,witness +995 5:wolf,woman,wonder,wood,wool +996 5:word,work,world,worry,worth +997 6:wrap,wreck,wrestle,wrist,write,wrong +998 6:yard,year,yellow,you,young,youth +999 4:zebra,zero,zone,zoo From 15fcda21ce0597281cada810dac785258414aac1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Nov 2016 13:12:15 +0100 Subject: [PATCH 0370/1154] update protobuf --- firmware/protob/messages.pb.c | 8 +++++--- firmware/protob/messages.pb.h | 31 ++++++++++++++++++------------- firmware/protob/types.pb.h | 11 +++++++++++ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 7193d53704..7decf55dc0 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -204,18 +204,20 @@ const pb_field_t EntropyAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t RecoveryDevice_fields[8] = { +const pb_field_t RecoveryDevice_fields[9] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, enforce_wordlist, 0), + PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, type, enforce_wordlist, 0), + PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, type, 0), PB_LAST_FIELD }; -const pb_field_t WordRequest_fields[1] = { +const pb_field_t WordRequest_fields[2] = { + PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, WordRequest, type, type, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 7123f4495b..55950650ac 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -125,10 +125,6 @@ typedef struct _WipeDevice { uint8_t dummy_field; } WipeDevice; -typedef struct _WordRequest { - uint8_t dummy_field; -} WordRequest; - typedef struct _Address { char address[41]; } Address; @@ -676,6 +672,8 @@ typedef struct _RecoveryDevice { char label[33]; bool has_enforce_wordlist; bool enforce_wordlist; + bool has_type; + uint32_t type; bool has_u2f_counter; uint32_t u2f_counter; } RecoveryDevice; @@ -825,6 +823,11 @@ typedef struct _WordAck { char word[12]; } WordAck; +typedef struct _WordRequest { + bool has_type; + WordRequestType type; +} WordRequest; + /* Default values for struct fields */ extern const char GetAddress_coin_name_default[17]; extern const InputScriptType GetAddress_script_type_default; @@ -873,8 +876,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} -#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0} -#define WordRequest_init_default {0} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0} +#define WordRequest_init_default {false, (WordRequestType)0} #define WordAck_init_default {""} #define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} #define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} @@ -939,8 +942,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0} #define EntropyRequest_init_zero {0} #define EntropyAck_init_zero {false, {0, {0}}} -#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} -#define WordRequest_init_zero {0} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} +#define WordRequest_init_zero {false, (WordRequestType)0} #define WordAck_init_zero {""} #define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} #define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} @@ -1109,7 +1112,8 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define RecoveryDevice_language_tag 4 #define RecoveryDevice_label_tag 5 #define RecoveryDevice_enforce_wordlist_tag 6 -#define RecoveryDevice_u2f_counter_tag 7 +#define RecoveryDevice_type_tag 8 +#define RecoveryDevice_u2f_counter_tag 9 #define ResetDevice_display_random_tag 1 #define ResetDevice_strength_tag 2 #define ResetDevice_passphrase_protection_tag 3 @@ -1150,6 +1154,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define VerifyMessage_message_tag 3 #define VerifyMessage_coin_name_tag 4 #define WordAck_word_tag 1 +#define WordRequest_type_tag 1 /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; @@ -1181,8 +1186,8 @@ extern const pb_field_t LoadDevice_fields[9]; extern const pb_field_t ResetDevice_fields[8]; extern const pb_field_t EntropyRequest_fields[1]; extern const pb_field_t EntropyAck_fields[2]; -extern const pb_field_t RecoveryDevice_fields[8]; -extern const pb_field_t WordRequest_fields[1]; +extern const pb_field_t RecoveryDevice_fields[9]; +extern const pb_field_t WordRequest_fields[2]; extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[5]; @@ -1249,8 +1254,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define ResetDevice_size 72 #define EntropyRequest_size 0 #define EntropyAck_size 131 -#define RecoveryDevice_size 72 -#define WordRequest_size 0 +#define RecoveryDevice_size 78 +#define WordRequest_size 6 #define WordAck_size 14 #define SignMessage_size 1094 #define VerifyMessage_size 1156 diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index a7dd51e8a2..68b5ec6a55 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -69,6 +69,17 @@ typedef enum _PinMatrixRequestType { PinMatrixRequestType_PinMatrixRequestType_NewSecond = 3 } PinMatrixRequestType; +typedef enum _RecoveryDeviceType { + RecoveryDeviceType_RecoveryDeviceType_ScrambledWords = 0, + RecoveryDeviceType_RecoveryDeviceType_Matrix = 1 +} RecoveryDeviceType; + +typedef enum _WordRequestType { + WordRequestType_WordRequestType_Plain = 0, + WordRequestType_WordRequestType_Matrix9 = 1, + WordRequestType_WordRequestType_Matrix6 = 2 +} WordRequestType; + /* Struct definitions */ typedef struct _CoinType { bool has_coin_name; From b4eaf7dbafbe66b8f0de1c6a292c7b4271b94697 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 23 Nov 2016 19:22:28 +0000 Subject: [PATCH 0371/1154] timer: Fix non-critical integer overflow (#129) Every 4294967295 milliseconds (2 ^ 32 - 1), system_millis will overflow. This means that every 49.71 days, system_millis will reset to zero. Comparisons like `system_millis < (system_millis + 1)` would fail if the latter had overflown and the former had not. This is non-critical because the worst case is that one second could be skipped or the screen could lock early. This poses no threat to the exponential backoff used for protection against brute force. --- firmware/layout2.c | 2 +- firmware/trezor.c | 2 +- firmware/usb.c | 5 +++-- timer.c | 2 +- timer.h | 4 +--- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 91c409b6e6..cac754c6b8 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -84,7 +84,7 @@ void layoutHome(void) oledRefresh(); // Reset lock screen timeout - system_millis_lock = system_millis + SCREEN_TIMEOUT_MILLIS; + system_millis_lock_start = system_millis; } const char *str_amount(uint64_t amnt, const char *abbr, char *buf, int len) diff --git a/firmware/trezor.c b/firmware/trezor.c index 129fd61a4e..f5a64ae83d 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -79,7 +79,7 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - if (system_millis >= system_millis_lock) { + if ((system_millis - system_millis_lock_start) >= 60000) { // lock the screen session_clear(true); layoutScreensaver(); diff --git a/firmware/usb.c b/firmware/usb.c index df50f1640e..e15dd49798 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -429,8 +429,9 @@ char usbTiny(char set) void usbSleep(uint32_t millis) { - uint32_t end = system_millis + millis; - while (end > system_millis) { + uint32_t start = system_millis; + + while ((system_millis - start) < millis) { usbd_poll(usbd_dev); } } diff --git a/timer.c b/timer.c index e45ce740f0..aad29663f9 100644 --- a/timer.c +++ b/timer.c @@ -27,7 +27,7 @@ volatile uint32_t system_millis; /* Screen timeout */ -uint32_t system_millis_lock; +uint32_t system_millis_lock_start; /* * Initialise the Cortex-M3 SysTick timer diff --git a/timer.h b/timer.h index 53713cdfe5..69759c33ff 100644 --- a/timer.h +++ b/timer.h @@ -24,9 +24,7 @@ extern volatile uint32_t system_millis; /* Screen timeout */ -extern uint32_t system_millis_lock; - -#define SCREEN_TIMEOUT_MILLIS (1000 * 60 * 10) /* 10 minutes */ +extern uint32_t system_millis_lock_start; void timer_init(void); From 5c00b24307a567b0e63a33cfa2595eab43b6f1b4 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 26 Nov 2016 07:48:04 -0500 Subject: [PATCH 0372/1154] trezor: Fix screen timeout (#131) --- firmware/trezor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index f5a64ae83d..f3b31403ab 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -79,7 +79,7 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - if ((system_millis - system_millis_lock_start) >= 60000) { + if ((system_millis - system_millis_lock_start) >= 600000) { // lock the screen session_clear(true); layoutScreensaver(); From 5f203d0a0cca7f12939fbb21688d26daadc7e8a5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 4 Dec 2016 22:24:01 +0000 Subject: [PATCH 0373/1154] debug: Improve debugging API (#134) * Allow DEBUG_LOG without DEBUG_LINK * Move debugInt() to debug.c --- firmware/debug.c | 12 ++++++++++++ firmware/debug.h | 3 +++ firmware/trezor.c | 5 ++++- firmware/u2f.c | 16 ---------------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/firmware/debug.c b/firmware/debug.c index 3bb5dcfec9..09d55db7fa 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -20,6 +20,7 @@ #include "trezor.h" #include "debug.h" #include "oled.h" +#include "util.h" #if DEBUG_LOG @@ -50,4 +51,15 @@ void debugLog(int level, const char *bucket, const char *text) oledDebug(text); } +char *debugInt(const uint32_t i) +{ + static uint8_t n = 0; + static char id[8][9]; + uint32hex(i, id[n]); + debugLog(0, "", id[n]); + char *ret = (char *)id[n]; + n = (n + 1) % 8; + return ret; +} + #endif diff --git a/firmware/debug.h b/firmware/debug.h index 4b71db3a5b..93cfd0f36b 100644 --- a/firmware/debug.h +++ b/firmware/debug.h @@ -21,14 +21,17 @@ #define __DEBUG_H__ #include "trezor.h" +#include #if DEBUG_LOG void debugLog(int level, const char *bucket, const char *text); +char *debugInt(const uint32_t i); #else #define debugLog(L, B, T) do{}while(0) +#define debugInt(I) do{}while(0) #endif diff --git a/firmware/trezor.c b/firmware/trezor.c index f3b31403ab..6e491691a7 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -99,8 +99,11 @@ int main(void) timer_init(); -#if DEBUG_LINK +#if DEBUG_LOG oledSetDebug(1); +#endif + +#if DEBUG_LINK storage_reset(); // wipe storage if debug link storage_reset_uuid(); storage_commit(); diff --git a/firmware/u2f.c b/firmware/u2f.c index 56ee8f76bf..e52364e0d8 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -92,22 +92,6 @@ typedef struct { uint8_t chal[U2F_CHAL_SIZE]; } U2F_AUTHENTICATE_SIG_STR; - -#if DEBUG_LOG -char *debugInt(const uint32_t i) -{ - static uint8_t n = 0; - static char id[8][9]; - uint32hex(i, id[n]); - debugLog(0, "", id[n]); - char *ret = (char *)id[n]; - n = (n + 1) % 8; - return ret; -} -#else -#define debugInt(I) do{}while(0) -#endif - static uint32_t dialog_timeout = 0; uint32_t next_cid(void) From ee3a7cbcfa3b17c093efd4be20635f034d3ee7a8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 6 Dec 2016 16:09:09 +0100 Subject: [PATCH 0374/1154] fix bug when long press of buttons breaks usb communication in bootloader, bump bl version to 1.3.1 --- bootloader/bootloader.h | 4 ++-- bootloader/usb.c | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 687c3fffbf..a1f505eb44 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x03" -#define VERSION_PATCH_CHAR "\x00" +#define VERSION_PATCH_CHAR "\x01" #include "memory.h" diff --git a/bootloader/usb.c b/bootloader/usb.c index 51172ca2c0..de9373a901 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -485,23 +485,38 @@ void usbInit(void) void checkButtons(void) { + static bool btn_left = false, btn_right = false, btn_final = false; + if (btn_final) { + return; + } uint16_t state = gpio_port_read(BTN_PORT); if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { if ((state & BTN_PIN_NO) != BTN_PIN_NO) { - oledInvert(0, 0, 3, 3); + btn_left = true; } if ((state & BTN_PIN_YES) != BTN_PIN_YES) { - oledInvert(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3); + btn_right = true; } + } + if (btn_left) { + oledBox(0, 0, 3, 3, true); + } + if (btn_right) { + oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true); + } + if (btn_left || btn_right) { oledRefresh(); } + if (btn_left && btn_right) { + btn_final = true; + } } void usbLoop(void) { for (;;) { usbd_poll(usbd_dev); - if (flash_state == STATE_READY || flash_state == STATE_OPEN) { + if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { checkButtons(); } } From 1763a5b64768c28d54e1d0125c4c45467036df64 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Dec 2016 12:16:48 +0100 Subject: [PATCH 0375/1154] use new hdnode_private_ckd_cached API --- firmware/fsm.c | 2 +- firmware/signing.c | 2 +- firmware/transaction.c | 2 +- firmware/u2f.c | 2 +- vendor/trezor-crypto | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 7369fee325..3cea7f2331 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -138,7 +138,7 @@ HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t addres if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); layoutHome(); return 0; diff --git a/firmware/signing.c b/firmware/signing.c index 22dcd91b46..0a00cf3532 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -518,7 +518,7 @@ void signing_txack(TransactionType *tx) if (idx2 == idx1) { memcpy(&input, tx->inputs, sizeof(TxInputType)); memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, tx->inputs[0].address_n, tx->inputs[0].address_n_count, NULL) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); signing_abort(); return; diff --git a/firmware/transaction.c b/firmware/transaction.c index c4667b963b..36a8bdc90b 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -68,7 +68,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T if (in->address_n_count > 0) { HDNode node; memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { return 0; } layoutProgressUpdate(true); diff --git a/firmware/u2f.c b/firmware/u2f.c index e52364e0d8..ddf560209e 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -460,7 +460,7 @@ const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) { + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { layoutHome(); debugLog(0, "", "ERR: Derive private failed"); return 0; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 6aac03d2d8..b55473a01e 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 6aac03d2d853eadaf9e91452b15381594fcf09b1 +Subproject commit b55473a01ecfd095d1f4bd068c8d3385b993b986 From 9eb87245ba3d963e9e6e953a8ea5863d76676389 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Mon, 2 Jan 2017 14:12:48 +0200 Subject: [PATCH 0376/1154] usb: exclude hid_report_descriptor_debug from non-debug build (#135) --- firmware/usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/usb.c b/firmware/usb.c index e15dd49798..7691b1f74f 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -80,6 +80,7 @@ static const uint8_t hid_report_descriptor[] = { 0xc0 // END_COLLECTION }; +#if DEBUG_LINK static const uint8_t hid_report_descriptor_debug[] = { 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) 0x09, 0x01, // USAGE (1) @@ -98,6 +99,7 @@ static const uint8_t hid_report_descriptor_debug[] = { 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; +#endif static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) From 52da2fc5e798144ae08cd3aa40d954e5d31f46e7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 10 Nov 2016 18:06:00 +0100 Subject: [PATCH 0377/1154] Segwit: Fix problems introduced by rebase --- firmware/signing.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 641a2d01f8..6fe29cdd22 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -315,6 +315,7 @@ bool compile_input_script_sig(TxInputType *tinput) // Failed to derive private key return false; } + hdnode_fill_public_key(&node); if (tinput->has_multisig) { tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS @@ -478,6 +479,7 @@ void signing_txack(TransactionType *tx) idx2++; send_req_2_prev_output(); } else { // last output + uint8_t hash[32]; if (tp.extra_data_len > 0) { // has extra data send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); return; @@ -488,13 +490,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - if (idx1 < inputs_count - 1) { - idx1++; - send_req_1_input(); - } else { - idx1 = 0; - send_req_3_output(); - } + phase1_request_next_input(); } return; case STAGE_REQUEST_2_PREV_EXTRADATA: @@ -821,7 +817,7 @@ void signing_txack(TransactionType *tx) sha256_Update(&hashers[0], hash_prevouts, 32); sha256_Update(&hashers[0], hash_sequence, 32); tx_prevout_hash(&hashers[0], &tx->inputs[0]); - tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes); + tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes); sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8); tx_sequence_hash(&hashers[0], &tx->inputs[0]); sha256_Update(&hashers[0], hash_outputs, 32); @@ -835,7 +831,7 @@ void signing_txack(TransactionType *tx) resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, 0); + ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL); resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (tx->inputs[0].has_multisig) { uint32_t r, i, script_len; From 32f3c54cc43262125401f1538acbf3d301bab672 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Jan 2017 18:52:55 +0100 Subject: [PATCH 0378/1154] fix whitespace --- firmware/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 7691b1f74f..77576e48e8 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -265,8 +265,8 @@ static const struct usb_interface ifaces[] = {{ .altsetting = hid_iface_debug, #endif }, { - .num_altsetting = 1, - .altsetting = hid_iface_u2f, + .num_altsetting = 1, + .altsetting = hid_iface_u2f, }}; static const struct usb_config_descriptor config = { @@ -344,7 +344,7 @@ static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) static uint8_t buf[64] __attribute__ ((aligned(4))); debugLog(0, "", "hid_u2f_rx_callback"); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } From e67f13ef4bcb0c9bede8f94cede70654098c5051 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 28 Dec 2016 19:16:50 +0100 Subject: [PATCH 0379/1154] Multi-byte address prefixes for segwit --- firmware/transaction.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index 9e63ce82d2..3cbdd1c3a5 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -63,7 +63,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int addr_raw_len; + size_t addr_raw_len; if (in->has_address) { // address provided -> regular output addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); @@ -76,36 +76,37 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } } - if (addr_raw_len == 21 && - addr_raw[0] == coin->address_type) { // p2pkh + size_t prefix_len; + if (address_check_prefix(addr_raw, coin->address_type) // p2pkh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; - } else if (addr_raw_len == 21 - && addr_raw[0] == coin->address_type_p2sh) { // p2sh + } else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; - } else if (addr_raw_len == 23 - && addr_raw[0] == coin->address_type_p2wpkh - && addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wpkh v0 + } else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh) + && addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh)) + && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wpkh v0 out->script_pubkey.bytes[0] = 0x00; // version 0 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 20); out->script_pubkey.size = 22; - } else if (addr_raw_len == 35 - && addr_raw[0] == coin->address_type_p2wsh - && addr_raw[1] == 0 && addr_raw[2] == 0) { // p2wsh v0 + } else if (address_check_prefix(addr_raw, coin->address_type_p2wsh) + && addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh)) + && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wsh v0 out->script_pubkey.bytes[0] = 0x00; // version 0 out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 3, 32); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 32); out->script_pubkey.size = 34; } else { return 0; From f9a203431ec3b4d3e16b246769da889ac8a38fa8 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 2 Jan 2017 21:22:59 +0100 Subject: [PATCH 0380/1154] Display SegWit address on Trezor --- firmware/fsm.c | 44 ++++++++++++++++++++++++++++++++ firmware/layout2.c | 15 +++++++++++ firmware/layout2.h | 1 + firmware/protob/messages.options | 2 +- 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ca3c997cdc..4740c93d92 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -31,6 +31,8 @@ #include "protect.h" #include "pinmatrix.h" #include "layout2.h" +#include "address.h" +#include "base58.h" #include "ecdsa.h" #include "reset.h" #include "recovery.h" @@ -608,6 +610,7 @@ void fsm_msgGetAddress(GetAddress *msg) HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; hdnode_fill_public_key(node); + int is_segwit = 0; if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); @@ -625,11 +628,52 @@ void fsm_msgGetAddress(GetAddress *msg) ripemd160(buf, 32, buf + 1); buf[0] = coin->address_type_p2sh; // multisig cointype base58_encode_check(buf, 21, resp->address, sizeof(resp->address)); + } else if (msg->has_script_type + && msg->script_type == InputScriptType_SPENDWITNESS + && coin->has_address_type_p2wpkh) { + uint8_t raw[22+4]; + int prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); + address_write_prefix_bytes(coin->address_type_p2wpkh, raw); + raw[prelen] = 0; // version byte + raw[prelen + 1] = 0; // always 0, see bip-142 + ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2); + if (!base58_encode_check(raw, prelen + 22, resp->address, sizeof(resp->address))) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); + layoutHome(); + return; + } + is_segwit = 1; + } else if (msg->has_script_type + && msg->script_type == InputScriptType_SPENDP2SHWITNESS + && coin->has_address_type_p2sh) { + uint8_t script[22]; + uint8_t digest[32]; + int prelen = address_prefix_bytes_len(coin->address_type_p2sh); + script[0] = 0; // version byte + script[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(node->public_key, script + 2); + sha256_Raw(script, 22, digest); + ripemd160(digest, 32, digest + prelen); + address_write_prefix_bytes(coin->address_type_p2sh, digest); + if (!base58_encode_check(digest, 21, resp->address, sizeof(resp->address))) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); + layoutHome(); + return; + } + is_segwit = 1; } else { ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address)); } if (msg->has_show_display && msg->show_display) { + if (is_segwit) { + layoutSegwitWarning(); + if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + layoutHome(); + return; + } + } char desc[16]; if (msg->has_multisig) { strlcpy(desc, "Msig __ of __:", sizeof(desc)); diff --git a/firmware/layout2.c b/firmware/layout2.c index e7d49262ab..6a7612062b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -391,3 +391,18 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico } layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL); } + +void layoutSegwitWarning() +{ + layoutDialogSwipe(&bmp_icon_info, + "Cancel", + "Understood", + NULL, + "The following address", + "is for SegWit soft fork.", + NULL, + "It is unsafe to use", + "until segwit activates.", + NULL + ); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 458fa55fda..95633fa722 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -45,5 +45,6 @@ void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); +void layoutSegwitWarning(void); #endif diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 9164ce6dba..66c8456bd4 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -32,7 +32,7 @@ PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 GetAddress.coin_name max_size:17 -Address.address max_size:41 +Address.address max_size:60 EthereumGetAddress.address_n max_count:8 EthereumAddress.address max_size:20 From e9eaad2fcfddd2dac4821caee1d453b5116811d5 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 6 Jan 2017 16:18:28 +0100 Subject: [PATCH 0381/1154] Segwit: Show multisig segwit address changed layout for very large addresses. --- firmware/fsm.c | 60 +++++++++++++++++++++++++---------- firmware/layout2.c | 24 +++++++++++--- firmware/protob/messages.pb.h | 4 +-- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4740c93d92..4a97c39b33 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -611,6 +611,9 @@ void fsm_msgGetAddress(GetAddress *msg) if (!node) return; hdnode_fill_public_key(node); int is_segwit = 0; + uint8_t digest[32]; + uint8_t raw[32+2+4]; + size_t prelen; if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); @@ -619,20 +622,45 @@ void fsm_msgGetAddress(GetAddress *msg) layoutHome(); return; } - uint8_t buf[32]; - if (compile_script_multisig_hash(&(msg->multisig), buf) == 0) { + if (compile_script_multisig_hash(&(msg->multisig), digest) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script"); layoutHome(); return; } - ripemd160(buf, 32, buf + 1); - buf[0] = coin->address_type_p2sh; // multisig cointype - base58_encode_check(buf, 21, resp->address, sizeof(resp->address)); + if (msg->has_script_type + && (msg->script_type == InputScriptType_SPENDWITNESS + || msg->script_type == InputScriptType_SPENDP2SHWITNESS)) { + is_segwit = 1; + // segwit p2wsh: script hash is single sha256 + if (msg->script_type == InputScriptType_SPENDWITNESS) { + prelen = address_prefix_bytes_len(coin->address_type_p2wsh); + address_write_prefix_bytes(coin->address_type_p2wsh, raw); + raw[prelen] = 0; // version byte + raw[prelen + 1] = 0; // always 0, see bip-142 + memcpy(raw+prelen+2, digest, 32); + base58_encode_check(raw, prelen + 34, resp->address, sizeof(resp->address)); + } else { + // segwit p2wsh encapsuled in p2sh address + raw[0] = 0; // push version + raw[1] = 32; // push 32 bytes + memcpy(raw+2, digest, 32); // push hash + sha256_Raw(raw, 34, digest); + prelen = address_prefix_bytes_len(coin->address_type_p2wsh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + base58_encode_check(raw, prelen + 20, resp->address, sizeof(resp->address)); + } + } else { + // non-segwit p2sh multisig + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + base58_encode_check(raw, prelen + 20, resp->address, sizeof(resp->address)); + } } else if (msg->has_script_type && msg->script_type == InputScriptType_SPENDWITNESS && coin->has_address_type_p2wpkh) { - uint8_t raw[22+4]; - int prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); + prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); address_write_prefix_bytes(coin->address_type_p2wpkh, raw); raw[prelen] = 0; // version byte raw[prelen + 1] = 0; // always 0, see bip-142 @@ -646,16 +674,14 @@ void fsm_msgGetAddress(GetAddress *msg) } else if (msg->has_script_type && msg->script_type == InputScriptType_SPENDP2SHWITNESS && coin->has_address_type_p2sh) { - uint8_t script[22]; - uint8_t digest[32]; - int prelen = address_prefix_bytes_len(coin->address_type_p2sh); - script[0] = 0; // version byte - script[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(node->public_key, script + 2); - sha256_Raw(script, 22, digest); - ripemd160(digest, 32, digest + prelen); - address_write_prefix_bytes(coin->address_type_p2sh, digest); - if (!base58_encode_check(digest, 21, resp->address, sizeof(resp->address))) { + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + raw[0] = 0; // version byte + raw[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(node->public_key, raw + 2); + sha256_Raw(raw, 22, digest); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, 21, resp->address, sizeof(resp->address))) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); layoutHome(); return; diff --git a/firmware/layout2.c b/firmware/layout2.c index 6a7612062b..5862a95ade 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -245,6 +245,7 @@ void layoutAddress(const char *address, const char *desc) static unsigned char bitdata[QR_MAX_BITDATA]; int a, i, j; int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata); + int startx; if (side > 0 && side <= 29) { oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); @@ -259,6 +260,20 @@ void layoutAddress(const char *address, const char *desc) } } } + startx = 68; + } else if (side > 0 && side <= 60) { + oledInvert(0, 0, (side + 3), (side + 3)); + for (i = 0; i < side; i++) { + for (j = 0; j< side; j++) { + a = j * side + i; + if (bitdata[a / 8] & (1 << (7 - a % 8))) { + oledClearPixel(2 + i, 2 + j); + } + } + } + startx = side + 6; + } else { + startx = 0; } uint32_t addrlen = strlen(address); @@ -269,12 +284,11 @@ void layoutAddress(const char *address, const char *desc) const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { - oledDrawString(68, 0 * 9, desc); + oledDrawString(startx, 0 * 9, desc); + } + for (i = 0; i < 4; i++) { + oledDrawString(startx, (i+1) * 9 + 4, str[i]); } - oledDrawString(68, 1 * 9 + 4, str[0]); - oledDrawString(68, 2 * 9 + 4, str[1]); - oledDrawString(68, 3 * 9 + 4, str[2]); - oledDrawString(68, 4 * 9 + 4, str[3]); static const char *btnYes = "Continue"; oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 7123f4495b..2b19e7edaf 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -130,7 +130,7 @@ typedef struct _WordRequest { } WordRequest; typedef struct _Address { - char address[41]; + char address[60]; } Address; typedef struct { @@ -1242,7 +1242,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size (81 + MultisigRedeemScriptType_size) #define EthereumGetAddress_size 50 -#define Address_size 43 +#define Address_size 62 #define EthereumAddress_size 22 #define WipeDevice_size 0 #define LoadDevice_size (326 + HDNodeType_size) From b1723fef5bf16ea54a9bb847aea9e002654558bd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Jan 2017 15:55:46 +0100 Subject: [PATCH 0382/1154] change binary name of nanopb generator (to follow upstream name) --- firmware/protob/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index f9dd9c718a..5b8d69e038 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,7 +1,7 @@ all: messages.pb.c storage.pb.c types.pb.c %.pb.c: %.pb %.options - nanopb $< -L '#include "%s"' -T + nanopb_generator.py $< -L '#include "%s"' -T %.pb: %.proto protoc -I/usr/include -I. $< -o $@ From 1e297c68fa0e70d00167005edf408fa93a95ef2b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jan 2017 14:58:28 +0100 Subject: [PATCH 0383/1154] cosmetic changes to matrix recovery --- Makefile.include | 2 +- firmware/recovery.c | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index 7651370950..84406a8d8a 100644 --- a/Makefile.include +++ b/Makefile.include @@ -91,7 +91,7 @@ flash2: $(NAME).hex -c "shutdown" upload: - ../../python-trezor/trezorctl firmware_update -f $(NAME).bin + trezorctl firmware_update -f $(NAME).bin sign: $(NAME).bin ../bootloader/firmware_sign.py -f $(NAME).bin diff --git a/firmware/recovery.c b/firmware/recovery.c index 17e68385f7..41083dd23e 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -214,7 +214,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) format_number(desc, nr); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL); } else { - oledBox(0, 18, 127, 63, false); + oledBox(0, 27, 127, 63, false); } for (row = 0; row < 3; row ++) { @@ -224,6 +224,11 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) int choice = word_matrix[nColumns*row + col]; const char *text = choice < num ? choices[choice] : "-"; oledDrawString(x - oledStringWidth(text)/2, y, text); + if (twoColumn) { + oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); + } else { + oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8); + } } } oledRefresh(); @@ -324,7 +329,7 @@ static void recovery_digit(const char digit) { /* received final word */ int y = 54 - ((digit - '1')/3)*11; int x = 64 * (((digit - '1') % 3) > 0); - oledInvert(x, y, x + 63, y + 9); + oledInvert(x + 1, y, x + 62, y + 9); oledRefresh(); usbSleep(250); From ab006262e865b9c1bf3ccde4a27496d89ca7bd70 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jan 2017 15:08:08 +0100 Subject: [PATCH 0384/1154] mytrezor.com -> trezor.io/start --- bootloader/bootloader.c | 2 +- bootloader/usb.c | 2 +- firmware/layout2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index cf1e7d1e0e..a87135917a 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -50,7 +50,7 @@ void layoutFirmwareHash(uint8_t *hash) void show_halt(void) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com"); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL); system_halt(); } diff --git a/bootloader/usb.c b/bootloader/usb.c index de9373a901..e4dc998e36 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -335,7 +335,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } sha256_Init(&ctx); diff --git a/firmware/layout2.c b/firmware/layout2.c index cac754c6b8..ca20dbbcce 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -65,7 +65,7 @@ void layoutHome(void) oledSwipeLeft(); } layoutLast = layoutHome; - const char *label = storage_isInitialized() ? storage_getLabel() : "Go to mytrezor.com"; + const char *label = storage_isInitialized() ? storage_getLabel() : "Go to trezor.io/start"; const uint8_t *homescreen = storage_getHomescreen(); if (homescreen) { BITMAP b; From cc01b86ab72c1b0801e057c8271863bd665db3a7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jan 2017 15:14:29 +0100 Subject: [PATCH 0385/1154] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e198cd421e..0b1c82d7a9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) -http://bitcointrezor.com/ +https://trezor.io/ ## How to build TREZOR firmware? @@ -24,8 +24,8 @@ This creates file `output/bootloader.bin` and prints its fingerprint and size at ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? -1. Pick version of firmware binary listed on https://wallet.mytrezor.com/data/firmware/releases.json -2. Download it: `wget -O trezor.signed.bin https://wallet.mytrezor.com/data/firmware/trezor-1.3.6.bin` +1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/releases.json +2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/trezor-1.3.6.bin` 3. `./firmware-fingerprint.sh trezor.signed.bin` Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). From 1cceec0ae2fd8324b97e0908c292b92a0e0d4aab Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 10 Jan 2017 21:51:57 +0100 Subject: [PATCH 0386/1154] Check that U2F key only uses hardened derivation (#139) We generate only U2F keys with hardened derivation. However, we didn't check incoming keys if they used hardened derivation. This patch fixes this. --- firmware/u2f.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/u2f.c b/firmware/u2f.c index ddf560209e..6c246175c7 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -505,6 +505,12 @@ const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle uint32_t key_path[KEY_PATH_ENTRIES]; key_path[0] = U2F_KEY_PATH; memcpy(&key_path[1], key_handle, KEY_PATH_LEN); + for (unsigned int i = 1; i < KEY_PATH_ENTRIES; i++) { + // check high bit for hardened keys + if (! (key_path[i] & 0x80000000)) { + return NULL; + } + } const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); if (!node) From 2dcef5cf045ee546995a421108f59f429809dac2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 13 Jan 2017 18:04:59 +0000 Subject: [PATCH 0387/1154] Makefile: Build and sign before uploading (#140) --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 84406a8d8a..87eeeb643b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -90,7 +90,7 @@ flash2: $(NAME).hex -c "reset" \ -c "shutdown" -upload: +upload: sign trezorctl firmware_update -f $(NAME).bin sign: $(NAME).bin From 466155270ba0b356ffb1938f5bcccbaf1a6f7e20 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 26 Nov 2016 21:16:15 +0200 Subject: [PATCH 0388/1154] layout: split "First Last " GPG user ID for readability --- firmware/layout2.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index ca20dbbcce..971b7f9f9b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -305,10 +305,12 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) char row_hostport[64 + 6 + 1]; char row_user[64 + 8 + 1]; + bool is_gpg = (strcmp(identity->proto, "gpg") == 0); + if (identity->has_proto && identity->proto[0]) { if (strcmp(identity->proto, "https") == 0) { strlcpy(row_proto, "Web sign in to:", sizeof(row_proto)); - } else if (strcmp(identity->proto, "gpg") == 0) { + } else if (is_gpg) { strlcpy(row_proto, "GPG sign for:", sizeof(row_proto)); } else { strlcpy(row_proto, identity->proto, sizeof(row_proto)); @@ -337,6 +339,21 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) row_user[0] = 0; } + if (is_gpg) { + // Split "First Last " into 2 lines: + // "First Last" + // "first@last.com" + char *email_start = strchr(row_hostport, '<'); + if (email_start) { + strlcpy(row_user, email_start + 1, sizeof(row_user)); + *email_start = 0; + char *email_end = strchr(row_user, '>'); + if (email_end) { + *email_end = 0; + } + } + } + layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", "Do you want to sign in?", row_proto[0] ? row_proto : NULL, From 11d37c87cd2ede9e227582eca34d607428384473 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 15 Jan 2017 13:49:36 +0000 Subject: [PATCH 0389/1154] Makefile: Generate dependency files (#141) --- Makefile.include | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index 87eeeb643b..7f4d4f1ed9 100644 --- a/Makefile.include +++ b/Makefile.include @@ -118,10 +118,10 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP $(LD) -o $(NAME).elf $(OBJS) -ltrezor -lopencm3_stm32f2 $(LDFLAGS) %.o: %.c Makefile - $(CC) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -MMD -o $@ -c $< %.small.o: %.c Makefile - $(CC) $(CFLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -MMD -o $@ -c $< clean: rm -f $(OBJS) @@ -133,3 +133,5 @@ clean: rm -f *.list rm -f *.log rm -f *.srec + +-include $(OBJS:.o=.d) From 3b109581133c0b62c75149c6188599bf2cded7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20B=C3=ADlek?= Date: Tue, 17 Jan 2017 16:22:11 +0100 Subject: [PATCH 0390/1154] Correcting 1.3.3 changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8e2842eb8d..f6ffc0571d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -36,7 +36,7 @@ Version 1.3.4 * Updated maxfee per kb for coins Version 1.3.3 -* Stable release, optional update +* Stable release, required update * Ask for PIN on GetAddress and GetPublicKey * Signing speed improved From 505df38a84b157d1f4d893db303a19cbe8926f32 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 19 Jan 2017 16:16:57 +0100 Subject: [PATCH 0391/1154] fix when oled triangle is shown --- firmware/trezor.c | 5 +---- oled.c | 10 +++++----- oled.h | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index 6e491691a7..56c74d491a 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -99,11 +99,8 @@ int main(void) timer_init(); -#if DEBUG_LOG - oledSetDebug(1); -#endif - #if DEBUG_LINK + oledSetDebugLink(1); storage_reset(); // wipe storage if debug link storage_reset_uuid(); storage_commit(); diff --git a/oled.c b/oled.c index 926428e775..095bb02fda 100644 --- a/oled.c +++ b/oled.c @@ -74,7 +74,7 @@ #define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8)) static uint8_t _oledbuffer[OLED_BUFSIZE]; -static bool is_debug_mode = 0; +static bool is_debug_link = 0; /* * Send a block of data via the SPI bus. @@ -161,7 +161,7 @@ void oledRefresh() static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; // draw triangle in upper right corner - if (is_debug_mode) { + if (is_debug_link) { OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); @@ -180,7 +180,7 @@ void oledRefresh() gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD // return it back - if (is_debug_mode) { + if (is_debug_link) { OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); @@ -194,9 +194,9 @@ const uint8_t *oledGetBuffer() return _oledbuffer; } -void oledSetDebug(bool set) +void oledSetDebugLink(bool set) { - is_debug_mode = set; + is_debug_link = set; oledRefresh(); } diff --git a/oled.h b/oled.h index 6fccc363ad..05b8b0b376 100644 --- a/oled.h +++ b/oled.h @@ -34,7 +34,7 @@ void oledInit(void); void oledClear(void); void oledRefresh(void); -void oledSetDebug(bool set); +void oledSetDebugLink(bool set); void oledSetBuffer(uint8_t *buf); const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); From f36cf5c10c26e610f31cb1206df2d7d3e34022b1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 21 Jan 2017 18:00:01 +0100 Subject: [PATCH 0392/1154] Handle edge cases for ethereum txs. Treat the case where a field is omitted identical to the case where an empty array is given. In particular - data_length == 0 is allowed now and identical to giving no data. - nonce can be omitted to indicate nonce value 0. I still do not allow to omit gas_limit and gas_price; gas_limit cannot be zero and transactions with zero gas_price will not be mined. You can still set it explicitly to zero by giving the empty array, though. See trezor/trezor-mcu#143. --- firmware/ethereum.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 5284795b84..654fdcdef5 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -383,7 +383,7 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, static bool ethereum_signing_check(EthereumSignTx *msg) { - if (!msg->has_nonce || !msg->has_gas_price || !msg->has_gas_limit) { + if (!msg->has_gas_price || !msg->has_gas_limit) { return false; } @@ -418,13 +418,10 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->data_initial_chunk.size = 0; if (!msg->has_to) msg->to.size = 0; + if (!msg->has_nonce) + msg->nonce.size = 0; - if (msg->has_data_length) { - if (msg->data_length == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided"); - ethereum_signing_abort(); - return; - } + if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); ethereum_signing_abort(); From 5b40f6d90b8ebe7d8ccc0a369aba5e35ecc60aa4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 22 Jan 2017 17:52:33 +0100 Subject: [PATCH 0393/1154] Updated trezor-common --- firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 11 +++++++---- vendor/trezor-common | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 7decf55dc0..7011ece5d2 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -336,7 +336,7 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t EthereumSignTx_fields[9] = { +const pb_field_t EthereumSignTx_fields[10] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0), PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0), @@ -345,6 +345,7 @@ const pb_field_t EthereumSignTx_fields[9] = { PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, value, to, 0), PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0), PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), + PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 55950650ac..f5b5893b61 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -460,6 +460,8 @@ typedef struct _EthereumSignTx { EthereumSignTx_data_initial_chunk_t data_initial_chunk; bool has_data_length; uint32_t data_length; + bool has_chain_id; + uint32_t chain_id; } EthereumSignTx; typedef struct { @@ -894,7 +896,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} -#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0} +#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_default {false, {0, {0}}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} @@ -960,7 +962,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} -#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0} +#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_zero {false, {0, {0}}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} @@ -1049,6 +1051,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define EthereumSignTx_value_tag 6 #define EthereumSignTx_data_initial_chunk_tag 7 #define EthereumSignTx_data_length_tag 8 +#define EthereumSignTx_chain_id_tag 9 #define EthereumTxAck_data_chunk_tag 1 #define EthereumTxRequest_data_length_tag 1 #define EthereumTxRequest_signature_v_tag 2 @@ -1204,7 +1207,7 @@ extern const pb_field_t SignTx_fields[6]; extern const pb_field_t SimpleSignTx_fields[7]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; -extern const pb_field_t EthereumSignTx_fields[9]; +extern const pb_field_t EthereumSignTx_fields[10]; extern const pb_field_t EthereumTxRequest_fields[5]; extern const pb_field_t EthereumTxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; @@ -1272,7 +1275,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) -#define EthereumSignTx_size 1239 +#define EthereumSignTx_size 1245 #define EthereumTxRequest_size 80 #define EthereumTxAck_size 1027 #define SignIdentity_size (558 + IdentityType_size) diff --git a/vendor/trezor-common b/vendor/trezor-common index 61af3d5e93..9d2ab7318d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4 +Subproject commit 9d2ab7318db08a47b35588b0593fb66129214f8d From 32fb7e96cca591f7d1cbb98bf79ad8cf3a58b627 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 22 Jan 2017 17:53:48 +0100 Subject: [PATCH 0394/1154] Ethereum EIP-155 replay protection Added chain_id field in sign transaction. If chain_id is set use hashing as specified in EIP-155. --- firmware/ethereum.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 654fdcdef5..50deb8df95 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -35,6 +35,7 @@ static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest resp; static uint8_t privkey[32]; +static uint8_t chain_id; struct SHA3_CTX keccak_ctx; static inline void hash_data(const uint8_t *buf, size_t size) @@ -150,6 +151,15 @@ static void send_signature(void) uint8_t hash[32], sig[64]; uint8_t v; layoutProgress("Signing", 1000); + + /* eip-155 replay protection */ + if (chain_id != 0) { + /* hash v=chain_id, r=0, s=0 */ + hash_rlp_field(&chain_id, 1); + hash_rlp_length(0, 0); + hash_rlp_length(0, 0); + } + keccak_Final(&keccak_ctx, hash); if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); @@ -163,7 +173,11 @@ static void send_signature(void) resp.has_data_length = false; resp.has_signature_v = true; - resp.signature_v = v + 27; + if (chain_id) { + resp.signature_v = v + 2*chain_id + 35; + } else { + resp.signature_v = v + 27; + } resp.has_signature_r = true; resp.signature_r.size = 32; @@ -421,6 +435,18 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (!msg->has_nonce) msg->nonce.size = 0; + /* eip-155 chain id */ + if (msg->has_chain_id) { + if (msg->chain_id < 1 || msg->chain_id > 109) { + fsm_sendFailure(FailureType_Failure_Other, "Chain Id out of bounds"); + ethereum_signing_abort(); + return; + } + chain_id = (uint8_t) msg->chain_id; + } else { + chain_id = 0; + } + if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); @@ -488,6 +514,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); + if (chain_id) { + rlp_length += rlp_calculate_length(1, chain_id); + rlp_length += rlp_calculate_length(0, 0); + rlp_length += rlp_calculate_length(0, 0); + } /* Stage 2: Store header fields */ hash_rlp_list_length(rlp_length); From a3a05ae248cbe1a9057de606f0663384c2b3f8b6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Jan 2017 15:17:02 +0100 Subject: [PATCH 0395/1154] add changelog --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index f6ffc0571d..9627710d08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Version 1.4.2 +* Stable release, optional update +* New Matrix-based recovery method +* Minor Ethereum fixes (including EIP-155 replay protection) +* Minor USB, U2F and GPG fixes + Version 1.4.1 * Stable release, optional update * Support for Zcash JoinSplit transactions From 323e7443a43711fe3234a8dd747cebac98ad9ecc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Jan 2017 15:19:15 +0100 Subject: [PATCH 0396/1154] add _attic to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e0baf9ab7d..02982714d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +_attic/ *.o *.a *.d From 5c54edf54e4fcaebb5552e04d76088038c7e9fa9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 24 Jan 2017 17:27:11 +0100 Subject: [PATCH 0397/1154] differentiate between ETH and ETC using chain_id --- firmware/ethereum.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 50deb8df95..a7342391ad 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -174,7 +174,7 @@ static void send_signature(void) resp.has_signature_v = true; if (chain_id) { - resp.signature_v = v + 2*chain_id + 35; + resp.signature_v = v + 2 * chain_id + 35; } else { resp.signature_v = v + 27; } @@ -242,7 +242,11 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25]) // remove trailing dot. if (value_ptr[-1] == '.') value_ptr--; - strcpy(value_ptr, " ETH"); + if (chain_id == 61 || chain_id == 62) { + strcpy(value_ptr, " ETC"); + } else { + strcpy(value_ptr, " ETH"); + } // value is at most 16 + 4 + 1 characters long } else { // value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik) From 14399f100e862608c24a7e214e9ce971c4d32457 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 25 Jan 2017 14:04:20 +0100 Subject: [PATCH 0398/1154] bump version --- firmware/trezor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index 72cc0fb9ce..4303afc601 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 4 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) From 228a109e5f98ca01b15142f594fa40c9c5f2eb22 Mon Sep 17 00:00:00 2001 From: mruddy Date: Thu, 26 Jan 2017 10:07:45 -0500 Subject: [PATCH 0399/1154] memory protection: do not write reserved bits (#138) --- memory.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/memory.c b/memory.c index c9ed483a6f..f779c2037c 100644 --- a/memory.c +++ b/memory.c @@ -27,13 +27,23 @@ void memory_protect(void) { + // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf + // Section 2.6 Option bytes // set RDP level 2 WRP for sectors 0 and 1 - if ((((*OPTION_BYTES_1) & 0xFFFF) == 0xCCFF) && (((*OPTION_BYTES_2) & 0xFFFF) == 0xFFFC)) { + if ((((*OPTION_BYTES_1) & 0xFFEC) == 0xCCEC) && (((*OPTION_BYTES_2) & 0xFFF) == 0xFFC)) { return; // already set up correctly - bail out } flash_unlock_option_bytes(); - // WRP + RDP - flash_program_option_bytes(0xFFFC0000 + 0xCCFF); + // Section 2.8.6 Flash option control register (FLASH_OPTCR) + // Bits 31:28 Reserved, must be kept cleared. + // Bits 27:16 nWRP: Not write protect: write protect bootloader code in flash main memory sectors 0 and 1 (Section 2.3; table 2) + // Bits 15:8 RDP: Read protect: level 2 chip read protection active + // Bits 7:5 USER: User option bytes: no reset on standby, no reset on stop, software watchdog + // Bit 4 Reserved, must be kept cleared. + // Bits 3:2 BOR_LEV: BOR reset Level: BOR off + // Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes + // Bit 0 OPTLOCK: Option lock: ignored by flash_program_option_bytes + flash_program_option_bytes(0x0FFCCCEC); flash_lock_option_bytes(); } From 0c039b3e14963744ea6cef00e91836ffc0ad87e9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 29 Jan 2017 18:05:36 +0000 Subject: [PATCH 0400/1154] USB: Compile-time USB string checking Generate `enum` for USB string indexes, this is far more robust --- firmware/usb.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 77576e48e8..39a528c0a2 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -44,6 +44,24 @@ #define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_OUT (0x03) +#define USB_STRINGS \ + X(MANUFACTURER, "SatoshiLabs") \ + X(PRODUCT, "TREZOR") \ + X(SERIAL_NUMBER, storage_uuid_str) + +#define X(name, value) USB_STRING_##name, +enum { + USB_STRING_LANGID_CODES, // LANGID code array + USB_STRINGS +}; +#undef X + +#define X(name, value) value, +static const char *usb_strings[] = { + USB_STRINGS +}; +#undef X + static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -55,9 +73,9 @@ static const struct usb_device_descriptor dev_descr = { .idVendor = 0x534c, .idProduct = 0x0001, .bcdDevice = 0x0100, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, + .iManufacturer = USB_STRING_MANUFACTURER, + .iProduct = USB_STRING_PRODUCT, + .iSerialNumber = USB_STRING_SERIAL_NUMBER, .bNumConfigurations = 1, }; @@ -285,12 +303,6 @@ static const struct usb_config_descriptor config = { .interface = ifaces, }; -static const char *usb_strings[] = { - "SatoshiLabs", - "TREZOR", - (const char *)storage_uuid_str, -}; - static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; @@ -388,7 +400,7 @@ static uint8_t usbd_control_buffer[128]; void usbInit(void) { - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, hid_set_config); } From bd167dcdf202f8c4ae4cb419a9e13d7551d36ae7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 29 Jan 2017 18:30:06 +0000 Subject: [PATCH 0401/1154] USB: Annotate USB interfaces with iInterface --- firmware/usb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 39a528c0a2..0bd7aed821 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -47,7 +47,10 @@ #define USB_STRINGS \ X(MANUFACTURER, "SatoshiLabs") \ X(PRODUCT, "TREZOR") \ - X(SERIAL_NUMBER, storage_uuid_str) + X(SERIAL_NUMBER, storage_uuid_str) \ + X(INTERFACE_MAIN, "TREZOR Interface") \ + X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ + X(INTERFACE_U2F, "U2F Interface") #define X(name, value) USB_STRING_##name, enum { @@ -204,7 +207,7 @@ static const struct usb_interface_descriptor hid_iface[] = {{ .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, - .iInterface = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, .endpoint = hid_endpoints, .extra = &hid_function, .extralen = sizeof(hid_function), @@ -235,7 +238,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, - .iInterface = 0, + .iInterface = USB_STRING_INTERFACE_U2F, .endpoint = hid_endpoints_u2f, .extra = &hid_function_u2f, .extralen = sizeof(hid_function_u2f), @@ -267,7 +270,7 @@ static const struct usb_interface_descriptor hid_iface_debug[] = {{ .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, - .iInterface = 0, + .iInterface = USB_STRING_INTERFACE_DEBUG, .endpoint = hid_endpoints_debug, .extra = &hid_function, .extralen = sizeof(hid_function), From 1943d840e3a2ec531075dca1d82de3924a87166e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 1 Feb 2017 14:50:16 +0100 Subject: [PATCH 0402/1154] add ChangeLog for bootloader, move firmware ChangeLog --- bootloader/ChangeLog | 19 +++++++++++++++++++ ChangeLog => firmware/ChangeLog | 0 2 files changed, 19 insertions(+) create mode 100644 bootloader/ChangeLog rename ChangeLog => firmware/ChangeLog (100%) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog new file mode 100644 index 0000000000..15453e7ac1 --- /dev/null +++ b/bootloader/ChangeLog @@ -0,0 +1,19 @@ +Version 1.3.1 +* Fix button testing so it does not break USB communication + +Version 1.3.0 +* Add test for buttons +* Clean USB descriptor +* Return firmware_present in Features response +* Don't halt on broken firware, stay in bootloader + +Version 1.2.7 +* Optimize speed of firmware update + +Version 1.2.6 +* Show hash of unofficial firmware +* Use stack protector +* Clean USB descriptor + +Version 1.2.5 +* Initial import of code diff --git a/ChangeLog b/firmware/ChangeLog similarity index 100% rename from ChangeLog rename to firmware/ChangeLog From 801ca6e64454cc6f94808e964e5f0167dd38e0d2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 1 Feb 2017 18:07:47 +0100 Subject: [PATCH 0403/1154] adapt python scripts to Python3 --- bootloader/firmware_align.py | 2 +- bootloader/firmware_sign.py | 71 +++++++++++++++++-------------- bootloader/firmware_sign_split.py | 26 ++++++----- gen/bitmaps/generate.py | 7 +-- gen/fonts/generate.py | 9 ++-- gen/handlers/handlers.py | 4 +- 6 files changed, 68 insertions(+), 51 deletions(-) diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index d0376784fa..5be6e7163d 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import sys import os diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 7ccd8e99a3..09650a6ab7 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -1,10 +1,16 @@ -#!/usr/bin/env python2 +#!/usr/bin/python +from __future__ import print_function import argparse import hashlib import struct import binascii import ecdsa +try: + raw_input +except: + raw_input = input + SLOTS = 3 pubkeys = { @@ -31,17 +37,17 @@ def prepare(data): # Takes raw OR signed firmware and clean out metadata structure # This produces 'clean' data for signing - meta = 'TRZR' # magic - if data[:4] == 'TRZR': + meta = b'TRZR' # magic + if data[:4] == b'TRZR': meta += data[4:4 + struct.calcsize(' 384 and '1' or '0') for x in img] - for i in range(len(img) / 8): + for i in range(len(img) // 8): c = ''.join(img[i * 8 : i * 8 + 8]) r += '0x%02x, ' % int(c, 2) return r cnt = 0 for fn in sorted(glob.glob('*.png')): - print 'Processing:', fn + print('Processing:', fn) im = Image.open(fn) name = os.path.splitext(fn)[0] w, h = im.size diff --git a/gen/fonts/generate.py b/gen/fonts/generate.py index 8f166f82a7..ec8b0aa4bf 100755 --- a/gen/fonts/generate.py +++ b/gen/fonts/generate.py @@ -1,4 +1,5 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python +from __future__ import print_function from PIL import Image class Img(object): @@ -23,12 +24,12 @@ cur = '' for i in range(256): x = (i % 16) * 10 - y = (i / 16) * 10 + y = (i // 16) * 10 cur = '' while img.pixel(x, y) != None: val = ''.join(img.pixel(x, y + j) for j in range(8)) x += 1 cur += '\\x%02x' % int(val, 2) - cur = '\\x%02x' % (len(cur) / 4) + cur + cur = '\\x%02x' % (len(cur) // 4) + cur ch = chr(i) if i >= 32 and i <= 126 else '_' - print '\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur) + print('\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur)) diff --git a/gen/handlers/handlers.py b/gen/handlers/handlers.py index ae1635b5f5..5e79610675 100755 --- a/gen/handlers/handlers.py +++ b/gen/handlers/handlers.py @@ -1,4 +1,6 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python +from __future__ import print_function + handlers = [ 'hard_fault_handler', 'mem_manage_handler', From 2a22d9f0ede6794174fcf8ce326bcf5c7963dc63 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 4 Feb 2017 11:20:58 +0100 Subject: [PATCH 0404/1154] fix combine/prepare script for python3 --- bootloader/combine/prepare.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bootloader/combine/prepare.py b/bootloader/combine/prepare.py index 0d463117c2..eb073e9820 100755 --- a/bootloader/combine/prepare.py +++ b/bootloader/combine/prepare.py @@ -1,10 +1,12 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python +from __future__ import print_function + bl = open('bl.bin').read() fw = open('fw.bin').read() combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:] open('combined.bin', 'w').write(combined) -print 'bootloader : %d bytes' % len(bl) -print 'firmware : %d bytes' % len(fw) -print 'combined : %d bytes' % len(combined) +print('bootloader : %d bytes' % len(bl)) +print('firmware : %d bytes' % len(fw)) +print('combined : %d bytes' % len(combined)) From c8c85424b629e4790f0745d15a1d4368046dff33 Mon Sep 17 00:00:00 2001 From: mruddy Date: Fri, 17 Feb 2017 07:18:50 -0500 Subject: [PATCH 0405/1154] fix usage of RNG before setup (#150/#151) --- bootloader/bootloader.c | 2 +- demo/demo.c | 6 +++++- firmware/trezor.c | 3 ++- setup.c | 10 ++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index a87135917a..c502e42b06 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -139,8 +139,8 @@ void __attribute__((noreturn)) __stack_chk_fail(void) int main(void) { - __stack_chk_guard = random32(); setup(); + __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks memory_protect(); oledInit(); diff --git a/demo/demo.c b/demo/demo.c index f4ee18ac22..d6f75c74b0 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -248,11 +248,15 @@ void __attribute__((noreturn)) __stack_chk_fail(void) int main(void) { - __stack_chk_guard = random32(); #ifndef APPVER setup(); + __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks oledInit(); +#else + setupApp(); + __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif + usbInit(); passlen = strlen((char *)pass); diff --git a/firmware/trezor.c b/firmware/trezor.c index 56c74d491a..87c1928527 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -89,12 +89,13 @@ void check_lock_screen(void) int main(void) { - __stack_chk_guard = random32(); #ifndef APPVER setup(); + __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks oledInit(); #else setupApp(); + __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif timer_init(); diff --git a/setup.c b/setup.c index b91c2d6933..2537a01436 100644 --- a/setup.c +++ b/setup.c @@ -21,6 +21,7 @@ #include #include #include +#include "rng.h" void setup(void) { @@ -42,6 +43,9 @@ void setup(void) // enable RNG rcc_periph_clock_enable(RCC_RNG); RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; + // to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1 + // we don't use the first random number generated after setting the RNGEN bit in setup + random32(); // set GPIO for buttons gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5); @@ -69,6 +73,12 @@ void setup(void) void setupApp(void) { + // the static variables in random32 are separate between the bootloader and firmware. + // therefore, they need to be initialized here so that we can be sure to avoid dupes. + // this is to try to comply with STM32F205xx Reference manual - Section 20.3.1: + // "Each subsequent generated random number has to be compared with the previously generated + // number. The test fails if any two compared numbers are equal (continuous random number generator test)." + random32(); // hotfix for old bootloader gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); From d03356fab1cb9a5c485dd118198e5a4cfc90b1f0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Feb 2017 21:01:00 +0100 Subject: [PATCH 0406/1154] raising the maxfee --- firmware/coins.c | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index e6056da420..094f2d5ed9 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,7 +26,7 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", }, + {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", }, {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", }, {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", }, {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", }, diff --git a/vendor/trezor-common b/vendor/trezor-common index 9d2ab7318d..80c7b666a2 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 9d2ab7318db08a47b35588b0593fb66129214f8d +Subproject commit 80c7b666a204c74be1d1ed6b019d1fad2d2fe909 From dfe783d7299940db81893dd84c9bd5b7afb69645 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 5 Mar 2017 13:43:22 +0000 Subject: [PATCH 0407/1154] firmware_sign: Python 3 compatibility (#156) --- bootloader/firmware_sign.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 09650a6ab7..a14bfaf6dc 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -189,7 +189,7 @@ def main(args): data = sign(data, args.pem) check_signatures(data) - fp = open(args.path, 'w') + fp = open(args.path, 'wb') fp.write(data) fp.close() From d7d3d0490ef4d6562ef1dcf8dfc9cc66f1d9158b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 28 Mar 2017 23:19:59 +0200 Subject: [PATCH 0408/1154] update trezor-crypto --- Makefile.include | 1 - firmware/Makefile | 3 --- vendor/trezor-crypto | 2 +- vendor/trezor-qrenc | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile.include b/Makefile.include index 7f4d4f1ed9..7e71499fd4 100644 --- a/Makefile.include +++ b/Makefile.include @@ -49,7 +49,6 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ - -I$(TOP_DIR)vendor/trezor-crypto/curve25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc ifdef APPVER diff --git a/firmware/Makefile b/firmware/Makefile index 4fe85288d1..1638b857be 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,6 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o -OBJS += ../vendor/trezor-crypto/curve25519-donna/curve25519.o OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o @@ -61,6 +60,4 @@ CFLAGS += -DQR_MAX_VERSION=0 CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' -CFLAGS += -DED25519_CUSTOMRANDOM=1 -CFLAGS += -DED25519_CUSTOMHASH=1 CFLAGS += -DUSE_ETHEREUM=1 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b55473a01e..df2524e35b 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b55473a01ecfd095d1f4bd068c8d3385b993b986 +Subproject commit df2524e35bc7d10129b965be017277ce46d2cae0 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 566bcd028d..9344f23d86 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 566bcd028d51b615b6620bbb500e72041ae4c614 +Subproject commit 9344f23d869030fbe7261d3361862eaba12b9975 From 7b1381766f3c1e2f9b5d9d1935f032219f9d3431 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 29 Mar 2017 16:43:48 +0200 Subject: [PATCH 0409/1154] Change address support for segwit. Rewrote change address support for segwit. Also checks the bip32 path of change address. --- firmware/signing.c | 70 +++++++++-- firmware/transaction.c | 267 ++++++++++++++++++++++++++--------------- firmware/transaction.h | 1 + 3 files changed, 228 insertions(+), 110 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index e8eebad2b5..f398aaa52a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -62,6 +62,9 @@ static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; +static uint32_t in_address_n[8]; +static size_t in_address_n_count; + /* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. @@ -298,6 +301,40 @@ void phase2_request_next_input(void) } } +void set_input_bip32_path(const TxInputType *tinput) +{ + size_t count = tinput->address_n_count; + if (count < 2) { + // no change address allowed + in_address_n_count = (size_t) -1; + } else if (in_address_n_count == 0) { + // initialize in_address_n on first input seen + in_address_n_count = count; + memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); + } else if (in_address_n_count != count + || memcmp(in_address_n, tinput->address_n, (count-2) * sizeof(uint32_t)) != 0) { + // mismatch -> no change address allowed + in_address_n_count = (size_t) -1; + } +} + +bool check_change_bip32_path(const TxOutputType *toutput) +{ + size_t count = toutput->address_n_count; + // check that the last two components specify a sane address on the change chain + if (count < 2 + || toutput->address_n[count-2] != 1 + || toutput->address_n[count-1] > 1000000) + return 0; + + // check that the other components exactly match input. + if (in_address_n_count != count + || memcmp(in_address_n, toutput->address_n, (count-2) * sizeof(uint32_t)) != 0) + return 0; + + return 1; +} + bool compile_input_script_sig(TxInputType *tinput) { if (!multisig_fp_mismatch) { @@ -349,6 +386,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp // this means 50 % per phase. progress_step = (500 << PROGRESS_PRECISION) / inputs_count; + in_address_n_count = 0; multisig_fp_set = false; multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; @@ -406,6 +444,7 @@ void signing_txack(TransactionType *tx) } else { // single signature multisig_fp_mismatch = true; } + set_input_bip32_path(&tx->inputs[0]); // compute segwit hashPrevouts & hashSequence tx_prevout_hash(&hashers[0], &tx->inputs[0]); tx_sequence_hash(&hashers[1], &tx->inputs[0]); @@ -520,19 +559,28 @@ void signing_txack(TransactionType *tx) * Ask for permission. */ bool is_change = false; - if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG) { - uint8_t h[32]; - if (!multisig_fp_set || multisig_fp_mismatch - || cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0 - || memcmp(multisig_fp, h, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); + if (tx->outputs[0].address_n_count > 0) { + if (tx->outputs[0].has_address) { + fsm_sendFailure(FailureType_Failure_Other, "Address in change output"); signing_abort(); return; } - is_change = true; - } else if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS && - tx->outputs[0].address_n_count > 0) { - is_change = true; + if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG) { + uint8_t h[32]; + if (!multisig_fp_set || multisig_fp_mismatch + || cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0 + || memcmp(multisig_fp, h, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); + signing_abort(); + return; + } + is_change = check_change_bip32_path(&tx->outputs[0]); + } else if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS + || ((tx->outputs[0].script_type == OutputScriptType_PAYTOWITNESS + || tx->outputs[0].script_type == OutputScriptType_PAYTOP2SHWITNESS) + && tx->outputs[0].amount < segwit_to_spend)) { + is_change = check_change_bip32_path(&tx->outputs[0]); + } } if (is_change) { @@ -545,7 +593,7 @@ void signing_txack(TransactionType *tx) } } - if (spending + tx->inputs[0].amount < spending) { + if (spending + tx->outputs[0].amount < spending) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); } diff --git a/firmware/transaction.c b/firmware/transaction.c index d19899f63e..a844c16505 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -58,132 +58,201 @@ uint32_t op_push(uint32_t i, uint8_t *out) { return 5; } +bool compute_address(const CoinType *coin, + InputScriptType script_type, + const HDNode *node, + bool has_multisig, const MultisigRedeemScriptType *multisig, + char address[MAX_ADDR_SIZE], + bool *is_segwit) { + + uint8_t raw[32]; + uint8_t digest[MAX_ADDR_RAW_SIZE]; + size_t prelen; + + if (has_multisig) { + if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) { + return 0; + } + if (compile_script_multisig_hash(multisig, digest) == 0) { + return 0; + } + if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wsh: script hash is single sha256 + *is_segwit = 1; + if (!coin->has_address_type_p2wsh) { + return 0; + } + prelen = address_prefix_bytes_len(coin->address_type_p2wsh); + address_write_prefix_bytes(coin->address_type_p2wsh, raw); + raw[prelen] = 0; // version byte + raw[prelen + 1] = 0; // always 0, see bip-142 + memcpy(raw+prelen+2, digest, 32); + if (!base58_encode_check(raw, prelen + 34, address, MAX_ADDR_SIZE)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wsh encapsuled in p2sh address + *is_segwit = 1; + if (!coin->has_address_type_p2sh) { + return 0; + } + raw[0] = 0; // push version + raw[1] = 32; // push 32 bytes + memcpy(raw+2, digest, 32); // push hash + sha256_Raw(raw, 34, digest); + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { + return 0; + } + } else { + // non-segwit p2sh multisig + *is_segwit = 0; + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { + return 0; + } + } + } else if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wpkh: pubkey hash is ripemd160 of sha256 + *is_segwit = 1; + if (!coin->has_address_type_p2wpkh) { + return 0; + } + prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); + address_write_prefix_bytes(coin->address_type_p2wpkh, raw); + raw[prelen] = 0; // version byte + raw[prelen + 1] = 0; // always 0, see bip-142 + ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2); + if (!base58_encode_check(raw, prelen + 22, address, MAX_ADDR_SIZE)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wpkh embedded in p2sh + *is_segwit = 1; + if (!coin->has_address_type_p2sh) { + return 0; + } + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + raw[0] = 0; // version byte + raw[1] = 20; // push 20 bytes + ecdsa_get_pubkeyhash(node->public_key, raw + 2); + sha256_Raw(raw, 22, digest); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { + return 0; + } + } else { + *is_segwit = 0; + ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE); + } + return 1; +} + int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) { memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; size_t addr_raw_len; + bool is_segwit; - if (in->has_address) { // address provided -> regular output - addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); - if (in->script_type != OutputScriptType_PAYTOADDRESS) { - // allow for p2sh (backward compatibility only) - if (in->script_type != OutputScriptType_PAYTOSCRIPTHASH - || addr_raw_len != 21 - || addr_raw[0] != coin->address_type_p2sh) { - return 0; - } + if (in->address_n_count > 0) { + HDNode node; + InputScriptType input_script_type; + + switch (in->script_type) { + + case OutputScriptType_PAYTOOPRETURN: + // only 0 satoshi allowed for OP_RETURN + if (in->amount != 0) + return 0; // failed to compile output + uint32_t r = 0; + out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN + r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); + memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; + out->script_pubkey.size = r; + return r; + + case OutputScriptType_PAYTOADDRESS: + input_script_type = InputScriptType_SPENDADDRESS; + break; + case OutputScriptType_PAYTOMULTISIG: + input_script_type = InputScriptType_SPENDMULTISIG; + break; + case OutputScriptType_PAYTOWITNESS: + input_script_type = InputScriptType_SPENDWITNESS; + break; + case OutputScriptType_PAYTOP2SHWITNESS: + input_script_type = InputScriptType_SPENDP2SHWITNESS; + break; + + default: + return 0; // failed to compile output } - - size_t prefix_len; - if (address_check_prefix(addr_raw, coin->address_type) // p2pkh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { - - out->script_pubkey.bytes[0] = 0x76; // OP_DUP - out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY - out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG - out->script_pubkey.size = 25; - } else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) { - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - } else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh) - && addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh)) - && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wpkh v0 - out->script_pubkey.bytes[0] = 0x00; // version 0 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 20); - out->script_pubkey.size = 22; - } else if (address_check_prefix(addr_raw, coin->address_type_p2wsh) - && addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh)) - && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wsh v0 - out->script_pubkey.bytes[0] = 0x00; // version 0 - out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 32); - out->script_pubkey.size = 34; - } else { - return 0; + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { + return 0; // failed to compile output } - - if (needs_confirm) { - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; - } + hdnode_fill_public_key(&node); + if (!compute_address(coin, input_script_type, &node, + in->has_multisig, &in->multisig, + in->address, &is_segwit)) { + return 0; // failed to compile output } - - return out->script_pubkey.size; + } else if (!in->has_address) { + return 0; // failed to compile output } - if (in->script_type == OutputScriptType_PAYTOADDRESS) { - // address_n provided-> change address -> calculate from address_n - if (in->script_type == OutputScriptType_PAYTOADDRESS && - in->address_n_count > 0) { - HDNode node; - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { - return 0; - } - layoutProgressUpdate(true); - hdnode_get_address_raw(&node, coin->address_type, addr_raw); - } else { // does not have address_n neither address -> error - return 0; - } + addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); + size_t prefix_len; + if (address_check_prefix(addr_raw, coin->address_type) // p2pkh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + address_prefix_bytes_len(coin->address_type), 20); + memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; - return 25; - } - - if (in->script_type == OutputScriptType_PAYTOMULTISIG) { - uint8_t buf[32]; - size_t prefix_bytes = address_prefix_bytes_len(coin->address_type_p2sh); - if (!in->has_multisig) { - return 0; - } - if (compile_script_multisig_hash(&(in->multisig), buf) == 0) { - return 0; - } - address_write_prefix_bytes(coin->address_type_p2sh, addr_raw); - ripemd160(buf, 32, addr_raw + prefix_bytes); - if (needs_confirm) { - base58_encode_check(addr_raw, prefix_bytes + 20, in->address, sizeof(in->address)); - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; - } - } + } else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_bytes, 20); + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; - return 23; + } else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh) + && addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh)) + && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wpkh v0 + out->script_pubkey.bytes[0] = 0x00; // version 0 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 20); + out->script_pubkey.size = 22; + } else if (address_check_prefix(addr_raw, coin->address_type_p2wsh) + && addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh)) + && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wsh v0 + out->script_pubkey.bytes[0] = 0x00; // version 0 + out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 32); + out->script_pubkey.size = 34; + } else { + return 0; } - if (in->script_type == OutputScriptType_PAYTOOPRETURN) { - if (in->amount != 0) return 0; // only 0 satoshi allowed for OP_RETURN - uint32_t r = 0; - out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN - r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); - memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; - out->script_pubkey.size = r; - return r; + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; // user aborted + } } - return 0; + return out->script_pubkey.size; } uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out) diff --git a/firmware/transaction.h b/firmware/transaction.h index e100aeaa35..808ccbca2e 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -45,6 +45,7 @@ typedef struct { SHA256_CTX ctx; } TxStruct; +bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE], bool *is_segwit); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); From 99fc6d31d138a59e042c9a1d099e04dc14954afa Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 29 Mar 2017 16:53:45 +0200 Subject: [PATCH 0410/1154] [refactor] Use compute_address in msgGetAddress. --- firmware/fsm.c | 81 ++------------------------------------------------ 1 file changed, 3 insertions(+), 78 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index f04afc6e94..4df6911236 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -584,85 +584,10 @@ void fsm_msgGetAddress(GetAddress *msg) HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; hdnode_fill_public_key(node); - int is_segwit = 0; - uint8_t digest[32]; - uint8_t raw[32+2+4]; - size_t prelen; + bool is_segwit = 0; - if (msg->has_multisig) { - layoutProgressSwipe("Preparing", 0); - if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); - layoutHome(); - return; - } - if (compile_script_multisig_hash(&(msg->multisig), digest) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script"); - layoutHome(); - return; - } - if (msg->has_script_type - && (msg->script_type == InputScriptType_SPENDWITNESS - || msg->script_type == InputScriptType_SPENDP2SHWITNESS)) { - is_segwit = 1; - // segwit p2wsh: script hash is single sha256 - if (msg->script_type == InputScriptType_SPENDWITNESS) { - prelen = address_prefix_bytes_len(coin->address_type_p2wsh); - address_write_prefix_bytes(coin->address_type_p2wsh, raw); - raw[prelen] = 0; // version byte - raw[prelen + 1] = 0; // always 0, see bip-142 - memcpy(raw+prelen+2, digest, 32); - base58_encode_check(raw, prelen + 34, resp->address, sizeof(resp->address)); - } else { - // segwit p2wsh encapsuled in p2sh address - raw[0] = 0; // push version - raw[1] = 32; // push 32 bytes - memcpy(raw+2, digest, 32); // push hash - sha256_Raw(raw, 34, digest); - prelen = address_prefix_bytes_len(coin->address_type_p2wsh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - base58_encode_check(raw, prelen + 20, resp->address, sizeof(resp->address)); - } - } else { - // non-segwit p2sh multisig - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - base58_encode_check(raw, prelen + 20, resp->address, sizeof(resp->address)); - } - } else if (msg->has_script_type - && msg->script_type == InputScriptType_SPENDWITNESS - && coin->has_address_type_p2wpkh) { - prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); - address_write_prefix_bytes(coin->address_type_p2wpkh, raw); - raw[prelen] = 0; // version byte - raw[prelen + 1] = 0; // always 0, see bip-142 - ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2); - if (!base58_encode_check(raw, prelen + 22, resp->address, sizeof(resp->address))) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); - layoutHome(); - return; - } - is_segwit = 1; - } else if (msg->has_script_type - && msg->script_type == InputScriptType_SPENDP2SHWITNESS - && coin->has_address_type_p2sh) { - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - raw[0] = 0; // version byte - raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(node->public_key, raw + 2); - sha256_Raw(raw, 22, digest); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, 21, resp->address, sizeof(resp->address))) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); - layoutHome(); - return; - } - is_segwit = 1; - } else { - ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address)); + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address, &is_segwit)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); } if (msg->has_show_display && msg->show_display) { From 49645ba2778c4bf0070bf8232f9933692fd6474d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 30 Mar 2017 02:24:53 +0200 Subject: [PATCH 0411/1154] Compute hash before checking signatures. (#158) This fixes the problem where an invalid hash is shown, if the firmware contains no signing key indices. --- bootloader/signatures.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bootloader/signatures.c b/bootloader/signatures.c index a4bca418ba..bbe96fd0ad 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -47,6 +47,12 @@ int signatures_ok(uint8_t *store_hash) sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2); sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3); + uint8_t hash[32]; + sha256_Raw((uint8_t *)FLASH_APP_START, codelen, hash); + if (store_hash) { + memcpy(store_hash, hash, 32); + } + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return 0; // invalid index if (sigindex2 < 1 || sigindex2 > PUBKEYS) return 0; // invalid index if (sigindex3 < 1 || sigindex3 > PUBKEYS) return 0; // invalid index @@ -55,12 +61,6 @@ int signatures_ok(uint8_t *store_hash) if (sigindex1 == sigindex3) return 0; // duplicate use if (sigindex2 == sigindex3) return 0; // duplicate use - uint8_t hash[32]; - sha256_Raw((uint8_t *)FLASH_APP_START, codelen, hash); - if (store_hash) { - memcpy(store_hash, hash, 32); - } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure return 0; } From 81d226a29b84e475bad3ac167a9b396a035f391f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 1 Apr 2017 23:43:39 +0200 Subject: [PATCH 0412/1154] build: modify travis to not use sudo --- .travis.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5653ed0e19..4275c03c3a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,14 @@ +sudo: false +dist: trusty language: c -install: - - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - - sudo apt-get update - - sudo apt-get install -y build-essential git gcc-arm-embedded +addons: + apt: + packages: + - build-essential + - git + - gcc-arm-none-eabi + - libnewlib-arm-none-eabi script: - make -C vendor/libopencm3 From e5c9b361d3e7d77c2135ff931d8e58809421cfe3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 8 Apr 2017 20:29:58 +0200 Subject: [PATCH 0413/1154] Better error message for segwit without amount --- firmware/signing.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index f398aaa52a..4a5dd9f3ac 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -444,6 +444,8 @@ void signing_txack(TransactionType *tx) } else { // single signature multisig_fp_mismatch = true; } + // remember the input bip32 path + // change addresses must use the same bip32 path as all inputs set_input_bip32_path(&tx->inputs[0]); // compute segwit hashPrevouts & hashSequence tx_prevout_hash(&hashers[0], &tx->inputs[0]); @@ -457,9 +459,12 @@ void signing_txack(TransactionType *tx) next_nonsegwit_input = idx1; memcpy(&input, tx->inputs, sizeof(TxInputType)); send_req_2_prev_meta(); - } else if (tx->inputs[0].has_amount - && (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS)) { + } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS + || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_Other, "Segwit input without amount"); + signing_abort(); + } if (to_spend + tx->inputs[0].amount < to_spend) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); From 9d9377438c58e90b1951c62aff83df44cef72de8 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 8 Apr 2017 20:32:14 +0200 Subject: [PATCH 0414/1154] Fix missing returns after signing_abort --- firmware/signing.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/signing.c b/firmware/signing.c index 4a5dd9f3ac..3359a42a0e 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -464,10 +464,12 @@ void signing_txack(TransactionType *tx) if (!tx->inputs[0].has_amount) { fsm_sendFailure(FailureType_Failure_Other, "Segwit input without amount"); signing_abort(); + return; } if (to_spend + tx->inputs[0].amount < to_spend) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); + return; } to_spend += tx->inputs[0].amount; segwit_to_spend += tx->inputs[0].amount; @@ -476,6 +478,7 @@ void signing_txack(TransactionType *tx) } else { fsm_sendFailure(FailureType_Failure_Other, "Wrong input script type"); signing_abort(); + return; } return; case STAGE_REQUEST_2_PREV_META: @@ -515,6 +518,7 @@ void signing_txack(TransactionType *tx) if (to_spend + tx->bin_outputs[0].amount < to_spend) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); + return; } to_spend += tx->bin_outputs[0].amount; } @@ -601,6 +605,7 @@ void signing_txack(TransactionType *tx) if (spending + tx->outputs[0].amount < spending) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); + return; } spending += tx->outputs[0].amount; co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); From 420471889d173ffa0b67643e33195fb9286b1207 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 8 Apr 2017 21:46:43 +0200 Subject: [PATCH 0415/1154] Refactored signing method. Put larger pieces of codes into functions of their own. No changes to this code. --- firmware/signing.c | 661 ++++++++++++++++++++++++--------------------- 1 file changed, 356 insertions(+), 305 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 3359a42a0e..91c4bfd548 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -66,7 +66,7 @@ static uint32_t in_address_n[8]; static size_t in_address_n_count; -/* progress_step/meta_step are fixed point numbers, giving the +/* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. */ #define PROGRESS_PRECISION 16 @@ -86,8 +86,9 @@ Phase1 - check inputs, previous transactions, and outputs foreach I (idx1): Request I STAGE_REQUEST_1_INPUT - Add I to TransactionChecksum - Calculate amount of I: + Add I to segwit hash_prevouts, hash_sequence + Add I to TransactionChecksum (prevout and type) + If not segwit, Calculate amount of I: Request prevhash I, META STAGE_REQUEST_2_PREV_META foreach prevhash I (idx2): Request prevhash I STAGE_REQUEST_2_PREV_INPUT @@ -109,27 +110,43 @@ Phase2: sign inputs, check that nothing changed =============================================== foreach I (idx1): // input to sign - foreach I (idx2): - Request I STAGE_REQUEST_4_INPUT - If idx1 == idx2 - Remember key for signing - Fill scriptsig - Add I to StreamTransactionSign - Add I to TransactionChecksum - foreach O (idx2): - Request O STAGE_REQUEST_4_OUTPUT - Add O to StreamTransactionSign - Add O to TransactionChecksum + if (idx1 is segwit) + Request I STAGE_REQUEST_SEGWIT_INPUT + Return serialized input chunk + + else + foreach I (idx2): + Request I STAGE_REQUEST_4_INPUT + If idx1 == idx2 + Remember key for signing + Fill scriptsig + Add I to StreamTransactionSign + Add I to TransactionChecksum + foreach O (idx2): + Request O STAGE_REQUEST_4_OUTPUT + Add O to StreamTransactionSign + Add O to TransactionChecksum + + Compare TransactionChecksum with checksum computed in Phase 1 + If different: + Failure + Sign StreamTransactionSign + Return signed chunk - Compare TransactionChecksum with checksum computed in Phase 1 - If different: - Failure - Sign StreamTransactionSign - Return signed chunk foreach O (idx1): Request O STAGE_REQUEST_5_OUTPUT Rewrite change address Return O + + +Phase3: sign segwit inputs, check that nothing changed +=============================================== + +foreach I (idx1): // input to sign + Request I STAGE_REQUEST_SEGWIT_WITNESS + Check amount + Sign segwit prevhash, sequence, amount, outputs + Return witness */ void send_req_1_input(void) @@ -404,6 +421,309 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp #define MIN(a,b) (((a)<(b))?(a):(b)) +static bool signing_check_input(TxInputType *txinput) { + /* compute multisig fingerprint */ + /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ + if (txinput->has_multisig && !multisig_fp_mismatch + && txinput->script_type == InputScriptType_SPENDMULTISIG) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); + signing_abort(); + return false; + } + if (multisig_fp_set) { + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + memcpy(multisig_fp, h, 32); + multisig_fp_set = true; + } + } else { // single signature + multisig_fp_mismatch = true; + } + // remember the input bip32 path + // change addresses must use the same bip32 path as all inputs + set_input_bip32_path(txinput); + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hashers[0], txinput); + tx_sequence_hash(&hashers[1], txinput); + // hash prevout and script type to check it later (relevant for fee computation) + tx_prevout_hash(&hashers[2], txinput); + sha256_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); + return true; +} + +// check if the hash of the prevtx matches +static bool signing_check_prevtx_hash(void) { + uint8_t hash[32]; + tx_hash_final(&tp, hash, true); + if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); + signing_abort(); + return false; + } + phase1_request_next_input(); + return true; +} + +static bool signing_check_output(TxOutputType *txoutput) { + // Phase1: Check outputs + // add it to hash_outputs + // ask user for permission + + // check for change address + bool is_change = false; + if (txoutput->address_n_count > 0) { + if (txoutput->has_address) { + fsm_sendFailure(FailureType_Failure_Other, "Address in change output"); + signing_abort(); + return false; + } + if (txoutput->script_type == OutputScriptType_PAYTOMULTISIG) { + uint8_t h[32]; + if (!multisig_fp_set || multisig_fp_mismatch + || cryptoMultisigFingerprint(&(txoutput->multisig), h) == 0 + || memcmp(multisig_fp, h, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); + signing_abort(); + return false; + } + is_change = check_change_bip32_path(txoutput); + } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS + || ((txoutput->script_type == OutputScriptType_PAYTOWITNESS + || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) + && txoutput->amount < segwit_to_spend)) { + is_change = check_change_bip32_path(txoutput); + } + } + + if (is_change) { + if (change_spend == 0) { // not set + change_spend = txoutput->amount; + } else { + fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + signing_abort(); + return false; + } + } + + if (spending + txoutput->amount < spending) { + fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + signing_abort(); + return false; + } + spending += txoutput->amount; + int co = compile_output(coin, root, txoutput, &bin_output, !is_change); + if (!is_change) { + layoutProgress("Signing transaction", progress); + } + if (co < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); + signing_abort(); + return false; + } else if (co == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + signing_abort(); + return false; + } + // compute segwit hashOuts + tx_output_hash(&hashers[0], &bin_output); + return true; +} + +static bool signing_check_fee(void) { + // check fees + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); + layoutHome(); + return false; + } + uint64_t fee = to_spend - spending; + uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); + if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee, tx_est_size); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); + layoutHome(); + return false; + } + layoutProgress("Signing transaction", progress); + } + // last confirmation + layoutConfirmTx(coin, to_spend - change_spend, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + signing_abort(); + return false; + } + return true; +} + +static void phase1_request_next_output(void) { + if (idx1 < outputs_count - 1) { + idx1++; + send_req_3_output(); + } else { + sha256_Final(&hashers[0], hash_outputs); + sha256_Raw(hash_outputs, 32, hash_outputs); + if (!signing_check_fee()) { + return; + } + // Everything was checked, now phase 2 begins and the transaction is signed. + progress_meta_step = progress_step / (inputs_count + outputs_count); + layoutProgress("Signing transaction", progress); + idx1 = 0; + phase2_request_next_input(); + } +} + +static bool signing_sign_input(void) { + uint8_t hash[32]; + sha256_Final(&hashers[0], hash); + sha256_Raw(hash, 32, hash); + if (memcmp(hash, hash_outputs, 32) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return false; + } + tx_hash_final(&ti, hash, false); + resp.has_serialized = true; + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + signing_abort(); + return false; + } + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + + if (input.has_multisig) { + // fill in the signature + int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + signing_abort(); + return false; + } + memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); + if (input.script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize multisig script"); + signing_abort(); + return false; + } + } else { // SPENDADDRESS + input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); + } + resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); + return true; +} + +static bool signing_sign_segwit_input(TxInputType *txinput) { + // idx1: index to sign + uint8_t hash[32]; + uint32_t sighash = 1; + + if (txinput->script_type == InputScriptType_SPENDWITNESS + || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + if (!compile_input_script_sig(txinput)) { + fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + signing_abort(); + return false; + } + if (txinput->amount > segwit_to_spend) { + fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + signing_abort(); + return false; + } + segwit_to_spend -= txinput->amount; + + sha256_Init(&hashers[0]); + sha256_Update(&hashers[0], (const uint8_t *)&version, 4); + sha256_Update(&hashers[0], hash_prevouts, 32); + sha256_Update(&hashers[0], hash_sequence, 32); + tx_prevout_hash(&hashers[0], txinput); + tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); + sha256_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); + tx_sequence_hash(&hashers[0], txinput); + sha256_Update(&hashers[0], hash_outputs, 32); + sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); + sha256_Update(&hashers[0], (const uint8_t*) &sighash, 4); + sha256_Final(&hashers[0], hash); + sha256_Raw(hash, 32, hash); + + resp.has_serialized = true; + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + signing_abort(); + return false; + } + + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + if (txinput->has_multisig) { + uint32_t r, i, script_len; + int nwitnesses; + // fill in the signature + int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), node.public_key); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + signing_abort(); + return false; + } + memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + + r = 1; // skip number of items (filled in later) + resp.serialized.serialized_tx.bytes[r] = 0; r++; + nwitnesses = 2; + for (i = 0; i < txinput->multisig.signatures_count; i++) { + if (txinput->multisig.signatures[i].size == 0) { + continue; + } + nwitnesses++; + txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = 1; + r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); + } + script_len = compile_script_multisig(&txinput->multisig, 0); + r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(&txinput->multisig, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.bytes[0] = nwitnesses; + resp.serialized.serialized_tx.size = r; + } else { // single signature + uint32_t r = 0; + r += ser_length(2, resp.serialized.serialized_tx.bytes + r); + resp.serialized.signature.bytes[resp.serialized.signature.size] = 1; + r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + } else { + // empty witness + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.bytes[0] = 0; + resp.serialized.serialized_tx.size = 1; + } + // if last witness add tx footer + if (idx1 == inputs_count - 1) { + uint32_t r = resp.serialized.serialized_tx.size; + r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + return true; +} + void signing_txack(TransactionType *tx) { if (!signing) { @@ -423,38 +743,11 @@ void signing_txack(TransactionType *tx) switch (signing_stage) { case STAGE_REQUEST_1_INPUT: - /* compute multisig fingerprint */ - /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (tx->inputs[0].has_multisig && !multisig_fp_mismatch - && tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&(tx->inputs[0].multisig), h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); - signing_abort(); - return; - } - if (multisig_fp_set) { - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - memcpy(multisig_fp, h, 32); - multisig_fp_set = true; - } - } else { // single signature - multisig_fp_mismatch = true; - } - // remember the input bip32 path - // change addresses must use the same bip32 path as all inputs - set_input_bip32_path(&tx->inputs[0]); - // compute segwit hashPrevouts & hashSequence - tx_prevout_hash(&hashers[0], &tx->inputs[0]); - tx_sequence_hash(&hashers[1], &tx->inputs[0]); - // hash prevout and script type to check it later (relevant for fee computation) - tx_prevout_hash(&hashers[2], &tx->inputs[0]); - sha256_Update(&hashers[2], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + signing_check_input(&tx->inputs[0]); if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + // remember the first non-segwit input -- this is the first input + // we need to sign during phase2 if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1; memcpy(&input, tx->inputs, sizeof(TxInputType)); @@ -526,19 +819,12 @@ void signing_txack(TransactionType *tx) /* Check prevtx of next input */ idx2++; send_req_2_prev_output(); - } else { // last output - uint8_t hash[32]; - if (tp.extra_data_len > 0) { // has extra data - send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); - return; - } - tx_hash_final(&tp, hash, true); - if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); - signing_abort(); - return; - } - phase1_request_next_input(); + } else if (tp.extra_data_len > 0) { // has extra data + send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); + return; + } else { + /* prevtx is done */ + signing_check_prevtx_hash(); } return; case STAGE_REQUEST_2_PREV_EXTRADATA: @@ -550,117 +836,15 @@ void signing_txack(TransactionType *tx) if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received)); } else { - /* Check next output */ - uint8_t hash[32]; - tx_hash_final(&tp, hash, true); - if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); - signing_abort(); - return; - } - phase1_request_next_input(); + signing_check_prevtx_hash(); } return; case STAGE_REQUEST_3_OUTPUT: - { - /* Downloaded output idx1 the first time. - * Add it to transaction check - * Ask for permission. - */ - bool is_change = false; - if (tx->outputs[0].address_n_count > 0) { - if (tx->outputs[0].has_address) { - fsm_sendFailure(FailureType_Failure_Other, "Address in change output"); - signing_abort(); - return; - } - if (tx->outputs[0].script_type == OutputScriptType_PAYTOMULTISIG) { - uint8_t h[32]; - if (!multisig_fp_set || multisig_fp_mismatch - || cryptoMultisigFingerprint(&(tx->outputs[0].multisig), h) == 0 - || memcmp(multisig_fp, h, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); - signing_abort(); - return; - } - is_change = check_change_bip32_path(&tx->outputs[0]); - } else if (tx->outputs[0].script_type == OutputScriptType_PAYTOADDRESS - || ((tx->outputs[0].script_type == OutputScriptType_PAYTOWITNESS - || tx->outputs[0].script_type == OutputScriptType_PAYTOP2SHWITNESS) - && tx->outputs[0].amount < segwit_to_spend)) { - is_change = check_change_bip32_path(&tx->outputs[0]); - } - } - - if (is_change) { - if (change_spend == 0) { // not set - change_spend = tx->outputs[0].amount; - } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); - signing_abort(); - return; - } - } - - if (spending + tx->outputs[0].amount < spending) { - fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); - signing_abort(); + if (!signing_check_output(&tx->outputs[0])) { return; } - spending += tx->outputs[0].amount; - co = compile_output(coin, root, tx->outputs, &bin_output, !is_change); - if (!is_change) { - layoutProgress("Signing transaction", progress); - } - if (co < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); - signing_abort(); - return; - } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); - signing_abort(); - return; - } - // compute segwit hashOuts - tx_output_hash(&hashers[0], &bin_output); - if (idx1 < outputs_count - 1) { - idx1++; - send_req_3_output(); - } else { - sha256_Final(&hashers[0], hash_outputs); - sha256_Raw(hash_outputs, 32, hash_outputs); - // check fees - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); - layoutHome(); - return; - } - uint64_t fee = to_spend - spending; - uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); - if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, tx_est_size); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - layoutHome(); - return; - } - layoutProgress("Signing transaction", progress); - } - // last confirmation - layoutConfirmTx(coin, to_spend - change_spend, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); - signing_abort(); - return; - } - // Everything was checked, now phase 2 begins and the transaction is signed. - progress_meta_step = progress_step / (inputs_count + outputs_count); - layoutProgress("Signing transaction", progress); - idx1 = 0; - phase2_request_next_input(); - } + phase1_request_next_output(); return; - } case STAGE_REQUEST_4_INPUT: progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { @@ -731,47 +915,9 @@ void signing_txack(TransactionType *tx) idx2++; send_req_4_output(); } else { - uint8_t hash[32]; - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); - if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); - signing_abort(); + if (!signing_sign_input()) { return; } - tx_hash_final(&ti, hash, false); - resp.has_serialized = true; - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); - signing_abort(); - return; - } - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - - if (input.has_multisig) { - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); - signing_abort(); - return; - } - memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); - if (input.script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize multisig script"); - signing_abort(); - return; - } - } else { // SPENDADDRESS - input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); - } - resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); // since this took a longer time, update progress layoutProgress("Signing transaction", progress); update_ctr = 0; @@ -855,104 +1001,10 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_SEGWIT_WITNESS: - { - uint8_t hash[32]; - uint32_t sighash = 1; + if (!signing_sign_segwit_input(&tx->inputs[0])) { + return; + } progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); - - if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); - signing_abort(); - return; - } - if (tx->inputs[0].amount > segwit_to_spend) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); - signing_abort(); - return; - } - segwit_to_spend -= tx->inputs[0].amount; - - sha256_Init(&hashers[0]); - sha256_Update(&hashers[0], (const uint8_t *)&version, 4); - sha256_Update(&hashers[0], hash_prevouts, 32); - sha256_Update(&hashers[0], hash_sequence, 32); - tx_prevout_hash(&hashers[0], &tx->inputs[0]); - tx_script_hash(&hashers[0], tx->inputs[0].script_sig.size, tx->inputs[0].script_sig.bytes); - sha256_Update(&hashers[0], (const uint8_t*) &tx->inputs[0].amount, 8); - tx_sequence_hash(&hashers[0], &tx->inputs[0]); - sha256_Update(&hashers[0], hash_outputs, 32); - sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); - sha256_Update(&hashers[0], (const uint8_t*) &sighash, 4); - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); - - resp.has_serialized = true; - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); - signing_abort(); - return; - } - - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - if (tx->inputs[0].has_multisig) { - uint32_t r, i, script_len; - int nwitnesses; - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(tx->inputs[0].multisig), node.public_key); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); - signing_abort(); - return; - } - memcpy(tx->inputs[0].multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - tx->inputs[0].multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - - - r = 1; // skip number of items (filled in later) - resp.serialized.serialized_tx.bytes[r] = 0; r++; - nwitnesses = 2; - for (i = 0; i < tx->inputs[0].multisig.signatures_count; i++) { - if (tx->inputs[0].multisig.signatures[i].size == 0) { - continue; - } - nwitnesses++; - tx->inputs[0].multisig.signatures[i].bytes[tx->inputs[0].multisig.signatures[i].size] = 1; - r += tx_serialize_script(tx->inputs[0].multisig.signatures[i].size + 1, tx->inputs[0].multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); - } - script_len = compile_script_multisig(&tx->inputs[0].multisig, 0); - r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); - r += compile_script_multisig(&tx->inputs[0].multisig, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.bytes[0] = nwitnesses; - resp.serialized.serialized_tx.size = r; - } else { // single signature - uint32_t r = 0; - r += ser_length(2, resp.serialized.serialized_tx.bytes + r); - resp.serialized.signature.bytes[resp.serialized.signature.size] = 1; - r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); - r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - } else { - // empty witness - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.bytes[0] = 0; - resp.serialized.serialized_tx.size = 1; - } - if (idx1 == inputs_count - 1) { - uint32_t r = resp.serialized.serialized_tx.size; - r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - // since this took a longer time, update progress layoutProgress("Signing transaction", progress); update_ctr = 0; if (idx1 < inputs_count - 1) { @@ -963,9 +1015,8 @@ void signing_txack(TransactionType *tx) signing_abort(); } return; - } } - + fsm_sendFailure(FailureType_Failure_Other, "Signing error"); signing_abort(); } From d70ac623a46e0177d8f2ce7e124c4b4d12e01e58 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 8 Apr 2017 22:36:32 +0200 Subject: [PATCH 0416/1154] Small bugfixes in signing Segwit progress bar fixed. Call `signing_abort` instead of `layoutHome` on all errors The second `compile_output` does not work for user button and cannot return -1. --- firmware/signing.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 91c4bfd548..d4921e03e3 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -47,6 +47,7 @@ enum { STAGE_REQUEST_SEGWIT_WITNESS } signing_stage; static uint32_t idx1, idx2; +static uint32_t signatures; static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; @@ -389,6 +390,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp version = _version; lock_time = _lock_time; + signatures = 0; idx1 = 0; to_spend = 0; spending = 0; @@ -512,7 +514,7 @@ static bool signing_check_output(TxOutputType *txoutput) { if (spending + txoutput->amount < spending) { fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); signing_abort(); - return false; + return false; } spending += txoutput->amount; int co = compile_output(coin, root, txoutput, &bin_output, !is_change); @@ -537,7 +539,7 @@ static bool signing_check_fee(void) { // check fees if (spending > to_spend) { fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); - layoutHome(); + signing_abort(); return false; } uint64_t fee = to_spend - spending; @@ -546,7 +548,7 @@ static bool signing_check_fee(void) { layoutFeeOverThreshold(coin, fee, tx_est_size); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); - layoutHome(); + signing_abort(); return false; } layoutProgress("Signing transaction", progress); @@ -738,7 +740,6 @@ void signing_txack(TransactionType *tx) update_ctr = 0; } - int co; memset(&resp, 0, sizeof(TxRequest)); switch (signing_stage) { @@ -846,7 +847,7 @@ void signing_txack(TransactionType *tx) phase1_request_next_output(); return; case STAGE_REQUEST_4_INPUT: - progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); + progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, true); sha256_Init(&hashers[0]); @@ -893,13 +894,8 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_4_OUTPUT: - progress = 500 + ((idx1 * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); - co = compile_output(coin, root, tx->outputs, &bin_output, false); - if (co < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); - signing_abort(); - return; - } else if (co == 0) { + progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); + if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); signing_abort(); return; @@ -919,6 +915,8 @@ void signing_txack(TransactionType *tx) return; } // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); layoutProgress("Signing transaction", progress); update_ctr = 0; if (idx1 < inputs_count - 1) { @@ -932,8 +930,6 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_SEGWIT_INPUT: - progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); - resp.has_serialized = true; resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; @@ -1004,7 +1000,8 @@ void signing_txack(TransactionType *tx) if (!signing_sign_segwit_input(&tx->inputs[0])) { return; } - progress = 500 + ((idx1 * progress_step) >> PROGRESS_PRECISION); + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); layoutProgress("Signing transaction", progress); update_ctr = 0; if (idx1 < inputs_count - 1) { From dcceec806dc0fe2a2259984dc57508fc14a0f4ca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Apr 2017 14:05:19 +0200 Subject: [PATCH 0417/1154] fix call to protectButton while showing segwit warning --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4df6911236..57f35db8e8 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -593,7 +593,7 @@ void fsm_msgGetAddress(GetAddress *msg) if (msg->has_show_display && msg->show_display) { if (is_segwit) { layoutSegwitWarning(); - if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { + if (!protectButton(ButtonRequestType_ButtonRequest_Address, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); layoutHome(); return; From 0200ee5763d8955009aa5691374746d2ed456c42 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Apr 2017 16:55:01 +0200 Subject: [PATCH 0418/1154] bootloader: cleanup protobuf messages --- bootloader/bootloader.c | 13 +++--- bootloader/bootloader.h | 2 +- bootloader/signatures.c | 30 ++++++------ bootloader/usb.c | 100 +++++++++++++++++++++++++++------------- 4 files changed, 88 insertions(+), 57 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index c502e42b06..843a1dddf4 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -38,11 +38,10 @@ #error Bootloader cannot be used in app mode #endif -void layoutFirmwareHash(uint8_t *hash) +void layoutFirmwareHash(const uint8_t *hash) { char str[4][17]; - int i; - for (i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { data2hex(hash + i * 8, 8, str[i]); } layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); @@ -54,7 +53,7 @@ void show_halt(void) system_halt(); } -void show_unofficial_warning(uint8_t *hash) +void show_unofficial_warning(const uint8_t *hash) { layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); @@ -117,13 +116,13 @@ void bootloader_loop(void) int check_firmware_sanity(void) { - if (memcmp((void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match + if (memcmp((const void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match return 0; } - if (*((uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB + if (*((const uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB return 0; } - if (*((uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size + if (*((const uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size return 0; } return 1; diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index a1f505eb44..93215356b0 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -33,6 +33,6 @@ #include "memory.h" -void layoutFirmwareHash(uint8_t *hash); +void layoutFirmwareHash(const uint8_t *hash); #endif diff --git a/bootloader/signatures.c b/bootloader/signatures.c index bbe96fd0ad..0b6ea5b9f6 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -28,27 +28,25 @@ #define PUBKEYS 5 -static const uint8_t *pubkey[PUBKEYS] = { - (uint8_t *)"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58", - (uint8_t *)"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1", - (uint8_t *)"\x04\x43\xae\xdb\xb6\xf7\xe7\x1c\x56\x3f\x8e\xd2\xef\x64\xec\x99\x81\x48\x25\x19\xe7\xef\x4f\x4a\xa9\x8b\x27\x85\x4e\x8c\x49\x12\x6d\x49\x56\xd3\x00\xab\x45\xfd\xc3\x4c\xd2\x6b\xc8\x71\x0d\xe0\xa3\x1d\xbd\xf6\xde\x74\x35\xfd\x0b\x49\x2b\xe7\x0a\xc7\x5f\xde\x58", - (uint8_t *)"\x04\x87\x7c\x39\xfd\x7c\x62\x23\x7e\x03\x82\x35\xe9\xc0\x75\xda\xb2\x61\x63\x0f\x78\xee\xb8\xed\xb9\x24\x87\x15\x9f\xff\xed\xfd\xf6\x04\x6c\x6f\x8b\x88\x1f\xa4\x07\xc4\xa4\xce\x6c\x28\xde\x0b\x19\xc1\xf4\xe2\x9f\x1f\xcb\xc5\xa5\x8f\xfd\x14\x32\xa3\xe0\x93\x8a", - (uint8_t *)"\x04\x73\x84\xc5\x1a\xe8\x1a\xdd\x0a\x52\x3a\xdb\xb1\x86\xc9\x1b\x90\x6f\xfb\x64\xc2\xc7\x65\x80\x2b\xf2\x6d\xbd\x13\xbd\xf1\x2c\x31\x9e\x80\xc2\x21\x3a\x13\x6c\x8e\xe0\x3d\x78\x74\xfd\x22\xb7\x0d\x68\xe7\xde\xe4\x69\xde\xcf\xbb\xb5\x10\xee\x9a\x46\x0c\xda\x45", +static const uint8_t * const pubkey[PUBKEYS] = { + (const uint8_t *)"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58", + (const uint8_t *)"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1", + (const uint8_t *)"\x04\x43\xae\xdb\xb6\xf7\xe7\x1c\x56\x3f\x8e\xd2\xef\x64\xec\x99\x81\x48\x25\x19\xe7\xef\x4f\x4a\xa9\x8b\x27\x85\x4e\x8c\x49\x12\x6d\x49\x56\xd3\x00\xab\x45\xfd\xc3\x4c\xd2\x6b\xc8\x71\x0d\xe0\xa3\x1d\xbd\xf6\xde\x74\x35\xfd\x0b\x49\x2b\xe7\x0a\xc7\x5f\xde\x58", + (const uint8_t *)"\x04\x87\x7c\x39\xfd\x7c\x62\x23\x7e\x03\x82\x35\xe9\xc0\x75\xda\xb2\x61\x63\x0f\x78\xee\xb8\xed\xb9\x24\x87\x15\x9f\xff\xed\xfd\xf6\x04\x6c\x6f\x8b\x88\x1f\xa4\x07\xc4\xa4\xce\x6c\x28\xde\x0b\x19\xc1\xf4\xe2\x9f\x1f\xcb\xc5\xa5\x8f\xfd\x14\x32\xa3\xe0\x93\x8a", + (const uint8_t *)"\x04\x73\x84\xc5\x1a\xe8\x1a\xdd\x0a\x52\x3a\xdb\xb1\x86\xc9\x1b\x90\x6f\xfb\x64\xc2\xc7\x65\x80\x2b\xf2\x6d\xbd\x13\xbd\xf1\x2c\x31\x9e\x80\xc2\x21\x3a\x13\x6c\x8e\xe0\x3d\x78\x74\xfd\x22\xb7\x0d\x68\xe7\xde\xe4\x69\xde\xcf\xbb\xb5\x10\xee\x9a\x46\x0c\xda\x45", }; #define SIGNATURES 3 int signatures_ok(uint8_t *store_hash) { - uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); - uint8_t sigindex1, sigindex2, sigindex3; - - sigindex1 = *((uint8_t *)FLASH_META_SIGINDEX1); - sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2); - sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3); + const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); + const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); + const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); + const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3); uint8_t hash[32]; - sha256_Raw((uint8_t *)FLASH_APP_START, codelen, hash); + sha256_Raw((const uint8_t *)FLASH_APP_START, codelen, hash); if (store_hash) { memcpy(store_hash, hash, 32); } @@ -61,13 +59,13 @@ int signatures_ok(uint8_t *store_hash) if (sigindex1 == sigindex3) return 0; // duplicate use if (sigindex2 == sigindex3) return 0; // duplicate use - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure return 0; } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, hash) != 0) { // failure + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash) != 0) { // failure return 0; } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, hash) != 0) { // failture + if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash) != 0) { // failture return 0; } diff --git a/bootloader/usb.c b/bootloader/usb.c index e4dc998e36..987ee3e128 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -183,24 +183,33 @@ static uint8_t meta_backup[FLASH_META_LEN]; static void send_msg_success(usbd_device *dev) { - // send response: Success message (id 2), payload len 0 + // response: Success message (id 2), payload len 0 while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x02" // msg_id - "\x00\x00\x00\x00" // payload_len + // header + "?##" + // msg_id + "\x00\x02" + // msg_size + "\x00\x00\x00\x00" + // padding "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } static void send_msg_failure(usbd_device *dev) { - // send response: Failure message (id 3), payload len 2 - // code = 99 (Failure_FirmwareError) + // response: Failure message (id 3), payload len 2 + // - code = 99 (Failure_FirmwareError) while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x03" // msg_id - "\x00\x00\x00\x02" // payload_len - "\x08\x63" // data + // header + "?##" + // msg_id + "\x00\x03" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x63" + // padding "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } @@ -209,41 +218,66 @@ extern int firmware_present; static void send_msg_features(usbd_device *dev) { - // send response: Features message (id 17), payload len 30 - // vendor = "bitcointrezor.com" - // major_version = VERSION_MAJOR - // minor_version = VERSION_MINOR - // patch_version = VERSION_PATCH - // bootloader_mode = True - // firmware_present = True/False + // response: Features message (id 17), payload len 30 + // - vendor = "bitcointrezor.com" + // - major_version = VERSION_MAJOR + // - minor_version = VERSION_MINOR + // - patch_version = VERSION_PATCH + // - bootloader_mode = True + // - firmware_present = True/False if (firmware_present) { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x11" // msg_id - "\x00\x00\x00\x1e" // payload_len - "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data - "\x90\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x1e" + // data + "\x0a" "\x11" "bitcointrezor.com" + "\x10" VERSION_MAJOR_CHAR + "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" "\x01" + "\x90\x01" "\x01" + // padding + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } else { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x11" // msg_id - "\x00\x00\x00\x1e" // payload_len - "\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data - "\x90\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x1e" + // data + "\x0a\x11" "bitcointrezor.com" + "\x10" VERSION_MAJOR_CHAR + "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" "\x01" + "\x90\x01" "\x00" + // padding + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } } static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) { - // send response: ButtonRequest message (id 26), payload len 2 - // code = ButtonRequest_FirmwareCheck (9) + // response: ButtonRequest message (id 26), payload len 2 + // - code = ButtonRequest_FirmwareCheck (9) while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - "?##" // header - "\x00\x1a" // msg_id - "\x00\x00\x00\x02" // payload_len - "\x08\x09" // data + // header + "?##" + // msg_id + "\x00\x1a" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x09" + // padding "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } From 09eaaa09ee705a48f02e8f800062132274d923cd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Apr 2017 19:28:25 +0200 Subject: [PATCH 0419/1154] bootloader: don't show recovery seed warning if no firmware is present --- bootloader/usb.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 987ee3e128..9d5675b14c 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -322,12 +322,14 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_OPEN) { if (msg_id == 0x0006) { // FirmwareErase message (id 6) - layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - if (button.YesUp) { + if (firmware_present) { + layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + } + if (!firmware_present || button.YesUp) { // backup metadata memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); flash_unlock(); From 6eb74410a52352fd621962c2540ca0f4aef28837 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 16 Apr 2017 19:28:51 +0200 Subject: [PATCH 0420/1154] update libopencm3 --- .travis.yml | 2 +- vendor/libopencm3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4275c03c3a..2a7d42fcd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ addons: - libnewlib-arm-none-eabi script: - - make -C vendor/libopencm3 + - CFLAGS="-std=c99" make -C vendor/libopencm3 - make - make -C firmware - make -C bootloader diff --git a/vendor/libopencm3 b/vendor/libopencm3 index d3fff11c1f..383fafc862 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit d3fff11c1f68b706591c0d51c82d18a0bc88dc17 +Subproject commit 383fafc862c0d47f30965f00409d03a328049278 From d4cc4a48b87224ce5a0e9d4897ea722a9173af4d Mon Sep 17 00:00:00 2001 From: Peter Banik Date: Fri, 21 Apr 2017 12:51:13 +0200 Subject: [PATCH 0421/1154] Added altcoin support to GetPublicKey (#161) --- firmware/coins-gen.py | 6 ++++++ firmware/coins.c | 16 ++++++++-------- firmware/fsm.c | 5 ++++- firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 4 +++- firmware/protob/messages.pb.h | 12 ++++++++---- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index d3109ec8d1..c7181d942e 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -30,6 +30,12 @@ for c in coins: 'true' if c['signed_message_header'] is not None else 'false', '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', + + 'true' if c['xpub_magic'] is not None else 'false', + '0x%s' % c['xpub_magic'] if c['xpub_magic'] is not None else '00000000', + + 'true' if c['xprv_magic'] is not None else 'false', + '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000' ]) for j in range(len(fields[0])): diff --git a/firmware/coins.c b/firmware/coins.c index 094f2d5ed9..f26808e2bf 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,14 +26,14 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", }, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", }, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", }, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", }, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", }, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", }, - {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", }, - {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", }, + {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, }, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, }, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, }, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, }, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, }, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, }, + {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, }, + {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, }, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/fsm.c b/firmware/fsm.c index 3cea7f2331..0893d3f5bd 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -317,6 +317,9 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) CHECK_PIN + const CoinType *coin = fsm_getCoin(msg->coin_name); + if (!coin) return; + const char *curve = SECP256K1_NAME; if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; @@ -360,7 +363,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.public_key.bytes[0] = 0; } resp->has_xpub = true; - hdnode_serialize_public(node, fingerprint, resp->xpub, sizeof(resp->xpub)); + hdnode_serialize_public(node, fingerprint, resp->xpub, sizeof(resp->xpub), coin->xpub_magic); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 9164ce6dba..c0f88fc3ff 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -26,6 +26,7 @@ Entropy.entropy max_size:1024 GetPublicKey.address_n max_count:8 GetPublicKey.ecdsa_curve_name max_size:32 +GetPublicKey.coin_name max_size:17 PublicKey.xpub max_size:113 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 7011ece5d2..8e85255962 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -3,6 +3,7 @@ #include "messages.pb.h" +const char GetPublicKey_coin_name_default[17] = "Bitcoin"; const char GetAddress_coin_name_default[17] = "Bitcoin"; const InputScriptType GetAddress_script_type_default = InputScriptType_SPENDADDRESS; const char LoadDevice_language_default[17] = "english"; @@ -130,10 +131,11 @@ const pb_field_t Entropy_fields[2] = { PB_LAST_FIELD }; -const pb_field_t GetPublicKey_fields[4] = { +const pb_field_t GetPublicKey_fields[5] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetPublicKey, show_display, ecdsa_curve_name, 0), + PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, coin_name, show_display, &GetPublicKey_coin_name_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index f5b5893b61..ced5e9b6e1 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -598,6 +598,8 @@ typedef struct _GetPublicKey { char ecdsa_curve_name[32]; bool has_show_display; bool show_display; + bool has_coin_name; + char coin_name[17]; } GetPublicKey; typedef struct _LoadDevice { @@ -831,6 +833,7 @@ typedef struct _WordRequest { } WordRequest; /* Default values for struct fields */ +extern const char GetPublicKey_coin_name_default[17]; extern const char GetAddress_coin_name_default[17]; extern const InputScriptType GetAddress_script_type_default; extern const char LoadDevice_language_default[17]; @@ -867,7 +870,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define PassphraseAck_init_default {""} #define GetEntropy_init_default {0} #define Entropy_init_default {{0, {0}}} -#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} +#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, "Bitcoin"} #define PublicKey_init_default {HDNodeType_init_default, false, ""} #define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default, false, InputScriptType_SPENDADDRESS} #define EthereumGetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} @@ -933,7 +936,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define PassphraseAck_init_zero {""} #define GetEntropy_init_zero {0} #define Entropy_init_zero {{0, {0}}} -#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0} +#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, ""} #define PublicKey_init_zero {HDNodeType_init_zero, false, ""} #define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero, false, (InputScriptType)0} #define EthereumGetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} @@ -1090,6 +1093,7 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define GetPublicKey_address_n_tag 1 #define GetPublicKey_ecdsa_curve_name_tag 2 #define GetPublicKey_show_display_tag 3 +#define GetPublicKey_coin_name_tag 4 #define LoadDevice_mnemonic_tag 1 #define LoadDevice_node_tag 2 #define LoadDevice_pin_tag 3 @@ -1178,7 +1182,7 @@ extern const pb_field_t PassphraseRequest_fields[1]; extern const pb_field_t PassphraseAck_fields[2]; extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t Entropy_fields[2]; -extern const pb_field_t GetPublicKey_fields[4]; +extern const pb_field_t GetPublicKey_fields[5]; extern const pb_field_t PublicKey_fields[3]; extern const pb_field_t GetAddress_fields[6]; extern const pb_field_t EthereumGetAddress_fields[3]; @@ -1246,7 +1250,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define PassphraseAck_size 53 #define GetEntropy_size 6 #define Entropy_size 1027 -#define GetPublicKey_size 84 +#define GetPublicKey_size 103 #define PublicKey_size (121 + HDNodeType_size) #define GetAddress_size (81 + MultisigRedeemScriptType_size) #define EthereumGetAddress_size 50 From 258d3eadddc425ce3ccdeb430f6eeb19e54af91e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 21 Apr 2017 12:55:14 +0200 Subject: [PATCH 0422/1154] GetPublicKey: use Bitcoin as default coin if not provided disable SimpleSignTx and Firmware messages update submodules --- firmware/fsm.c | 35 +++++++++++--------------- firmware/fsm.h | 2 -- firmware/messages.c | 2 -- firmware/protob/messages.options | 10 +++----- firmware/protob/messages.pb.c | 20 +-------------- firmware/protob/messages.pb.h | 43 +------------------------------- firmware/protob/types.pb.c | 6 ++++- firmware/protob/types.pb.h | 16 +++++++++--- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- vendor/trezor-qrenc | 2 +- 11 files changed, 40 insertions(+), 100 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 0893d3f5bd..41133ed312 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -116,9 +116,14 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } -const CoinType *fsm_getCoin(const char *name) +const CoinType *fsm_getCoin(bool has_name, const char *name) { - const CoinType *coin = coinByName(name); + const CoinType *coin; + if (has_name) { + coin = coinByName(name); + } else { + coin = coinByName("Bitcoin"); + } if (!coin) { fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); layoutHome(); @@ -278,18 +283,6 @@ void fsm_msgWipeDevice(WipeDevice *msg) layoutHome(); } -void fsm_msgFirmwareErase(FirmwareErase *msg) -{ - (void)msg; - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in bootloader mode"); -} - -void fsm_msgFirmwareUpload(FirmwareUpload *msg) -{ - (void)msg; - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in bootloader mode"); -} - void fsm_msgGetEntropy(GetEntropy *msg) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); @@ -317,7 +310,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; const char *curve = SECP256K1_NAME; @@ -363,7 +356,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.public_key.bytes[0] = 0; } resp->has_xpub = true; - hdnode_serialize_public(node, fingerprint, resp->xpub, sizeof(resp->xpub), coin->xpub_magic); + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } @@ -419,7 +412,7 @@ void fsm_msgSignTx(SignTx *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0); if (!node) return; @@ -580,7 +573,7 @@ void fsm_msgGetAddress(GetAddress *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -690,7 +683,7 @@ void fsm_msgSignMessage(SignMessage *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -713,7 +706,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) CHECK_PARAM(msg->has_address, "No address provided"); CHECK_PARAM(msg->has_message, "No message provided"); - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint32_t address_type; @@ -883,7 +876,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) const HDNode *node = 0; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (signing) { - const CoinType *coin = fsm_getCoin(msg->coin_name); + const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; CHECK_PIN diff --git a/firmware/fsm.h b/firmware/fsm.h index 085c236381..04be361f32 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -32,8 +32,6 @@ void fsm_msgGetFeatures(GetFeatures *msg); void fsm_msgPing(Ping *msg); void fsm_msgChangePin(ChangePin *msg); void fsm_msgWipeDevice(WipeDevice *msg); -void fsm_msgFirmwareErase(FirmwareErase *msg); -void fsm_msgFirmwareUpload(FirmwareUpload *msg); void fsm_msgGetEntropy(GetEntropy *msg); void fsm_msgGetPublicKey(GetPublicKey *msg); void fsm_msgLoadDevice(LoadDevice *msg); diff --git a/firmware/messages.c b/firmware/messages.c index c927e531b7..9e761a326a 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -44,8 +44,6 @@ static const struct MessagesMap_t MessagesMap[] = { {'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *))fsm_msgPing}, {'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *))fsm_msgChangePin}, {'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *))fsm_msgWipeDevice}, - {'n', 'i', MessageType_MessageType_FirmwareErase, FirmwareErase_fields, (void (*)(void *))fsm_msgFirmwareErase}, - {'n', 'i', MessageType_MessageType_FirmwareUpload, FirmwareUpload_fields, (void (*)(void *))fsm_msgFirmwareUpload}, {'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *))fsm_msgGetEntropy}, {'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *))fsm_msgGetPublicKey}, {'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *))fsm_msgLoadDevice}, diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c0f88fc3ff..7138c65978 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -120,13 +120,11 @@ GetECDHSessionKey.ecdsa_curve_name max_size:32 ECDHSessionKey.session_key max_size:65 # not used in firmware -SimpleSignTx.inputs max_count:0 -SimpleSignTx.outputs max_count:0 -SimpleSignTx.transactions max_count:0 -SimpleSignTx.coin_name max_size:17 +SimpleSignTx skip_message:true +FirmwareRequest skip_message:true +FirmwareUpload skip_message:true -# not used in firmware -FirmwareUpload.payload max_size:0 +# used in debug firmware DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 8e85255962..b2421129d4 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -17,9 +17,6 @@ const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; const uint32_t SignTx_version_default = 1u; const uint32_t SignTx_lock_time_default = 0u; -const char SimpleSignTx_coin_name_default[17] = "Bitcoin"; -const uint32_t SimpleSignTx_version_default = 1u; -const uint32_t SimpleSignTx_lock_time_default = 0u; const pb_field_t Initialize_fields[1] = { @@ -316,16 +313,6 @@ const pb_field_t SignTx_fields[6] = { PB_LAST_FIELD }; -const pb_field_t SimpleSignTx_fields[7] = { - PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields), - PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields), - PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, version, coin_name, &SimpleSignTx_version_default), - PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, lock_time, version, &SimpleSignTx_lock_time_default), - PB_LAST_FIELD -}; - const pb_field_t TxRequest_fields[4] = { PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), @@ -400,11 +387,6 @@ const pb_field_t FirmwareErase_fields[1] = { PB_LAST_FIELD }; -const pb_field_t FirmwareUpload_fields[2] = { - PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, FirmwareUpload, payload, payload, 0), - PB_LAST_FIELD -}; - const pb_field_t DebugLinkDecision_fields[2] = { PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), PB_LAST_FIELD @@ -472,7 +454,7 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index ced5e9b6e1..0dad8391fc 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -20,6 +20,7 @@ typedef enum _MessageType { MessageType_MessageType_WipeDevice = 5, MessageType_MessageType_FirmwareErase = 6, MessageType_MessageType_FirmwareUpload = 7, + MessageType_MessageType_FirmwareRequest = 8, MessageType_MessageType_GetEntropy = 9, MessageType_MessageType_Entropy = 10, MessageType_MessageType_GetPublicKey = 11, @@ -551,15 +552,6 @@ typedef struct _Features { bool firmware_present; } Features; -typedef struct { - size_t size; - uint8_t bytes[0]; -} FirmwareUpload_payload_t; - -typedef struct _FirmwareUpload { - FirmwareUpload_payload_t payload; -} FirmwareUpload; - typedef struct _GetAddress { size_t address_n_count; uint32_t address_n[8]; @@ -763,21 +755,6 @@ typedef struct _SignedIdentity { SignedIdentity_signature_t signature; } SignedIdentity; -typedef struct _SimpleSignTx { - size_t inputs_count; - TxInputType inputs[0]; - size_t outputs_count; - TxOutputType outputs[0]; - size_t transactions_count; - TransactionType transactions[0]; - bool has_coin_name; - char coin_name[17]; - bool has_version; - uint32_t version; - bool has_lock_time; - uint32_t lock_time; -} SimpleSignTx; - typedef struct _Success { bool has_message; char message[256]; @@ -847,9 +824,6 @@ extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const uint32_t SignTx_version_default; extern const uint32_t SignTx_lock_time_default; -extern const char SimpleSignTx_coin_name_default[17]; -extern const uint32_t SimpleSignTx_version_default; -extern const uint32_t SimpleSignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} @@ -896,7 +870,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} #define TxSize_init_default {false, 0} #define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} -#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} #define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} @@ -908,7 +881,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ECDHSessionKey_init_default {false, {0, {0}}} #define SetU2FCounter_init_default {false, 0} #define FirmwareErase_init_default {0} -#define FirmwareUpload_init_default {{0, {0}}} #define DebugLinkDecision_init_default {0} #define DebugLinkGetState_init_default {0} #define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0} @@ -962,7 +934,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define EstimateTxSize_init_zero {0, 0, false, ""} #define TxSize_init_zero {false, 0} #define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} -#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} #define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} @@ -974,7 +945,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define ECDHSessionKey_init_zero {false, {0, {0}}} #define SetU2FCounter_init_zero {false, 0} #define FirmwareErase_init_zero {0} -#define FirmwareUpload_init_zero {{0, {0}}} #define DebugLinkDecision_init_zero {0} #define DebugLinkGetState_init_zero {0} #define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0} @@ -1080,7 +1050,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define Features_pin_cached_tag 16 #define Features_passphrase_cached_tag 17 #define Features_firmware_present_tag 18 -#define FirmwareUpload_payload_tag 1 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 @@ -1144,12 +1113,6 @@ extern const uint32_t SimpleSignTx_lock_time_default; #define SignedIdentity_address_tag 1 #define SignedIdentity_public_key_tag 2 #define SignedIdentity_signature_tag 3 -#define SimpleSignTx_inputs_tag 1 -#define SimpleSignTx_outputs_tag 2 -#define SimpleSignTx_transactions_tag 3 -#define SimpleSignTx_coin_name_tag 4 -#define SimpleSignTx_version_tag 5 -#define SimpleSignTx_lock_time_tag 6 #define Success_message_tag 1 #define TxAck_tx_tag 1 #define TxRequest_request_type_tag 1 @@ -1208,7 +1171,6 @@ extern const pb_field_t CipheredKeyValue_fields[2]; extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[6]; -extern const pb_field_t SimpleSignTx_fields[7]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; extern const pb_field_t EthereumSignTx_fields[10]; @@ -1220,7 +1182,6 @@ extern const pb_field_t GetECDHSessionKey_fields[4]; extern const pb_field_t ECDHSessionKey_fields[2]; extern const pb_field_t SetU2FCounter_fields[2]; extern const pb_field_t FirmwareErase_fields[1]; -extern const pb_field_t FirmwareUpload_fields[2]; extern const pb_field_t DebugLinkDecision_fields[2]; extern const pb_field_t DebugLinkGetState_fields[1]; extern const pb_field_t DebugLinkState_fields[11]; @@ -1276,7 +1237,6 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define EstimateTxSize_size 31 #define TxSize_size 6 #define SignTx_size 43 -#define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) #define EthereumSignTx_size 1245 @@ -1288,7 +1248,6 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define ECDHSessionKey_size 67 #define SetU2FCounter_size 6 #define FirmwareErase_size 0 -#define FirmwareUpload_size 2 #define DebugLinkDecision_size 2 #define DebugLinkGetState_size 0 #define DebugLinkState_size (1468 + HDNodeType_size) diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 67148cacd7..7863d57ad6 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -7,6 +7,8 @@ const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_p2sh_default = 5u; const uint32_t CoinType_address_type_p2wpkh_default = 6u; const uint32_t CoinType_address_type_p2wsh_default = 10u; +const uint32_t CoinType_xpub_magic_default = 76067358u; +const uint32_t CoinType_xprv_magic_default = 76066276u; const uint32_t TxInputType_sequence_default = 4294967295u; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const uint32_t IdentityType_index_default = 0u; @@ -28,7 +30,7 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[9] = { +const pb_field_t CoinType_fields[11] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), @@ -37,6 +39,8 @@ const pb_field_t CoinType_fields[9] = { PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wpkh, address_type_p2sh, &CoinType_address_type_p2wpkh_default), PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wsh, address_type_p2wpkh, &CoinType_address_type_p2wsh_default), PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2wsh, 0), + PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), + PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 68b5ec6a55..4586a9407b 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -98,6 +98,10 @@ typedef struct _CoinType { uint32_t address_type_p2wsh; bool has_signed_message_header; char signed_message_header[32]; + bool has_xpub_magic; + uint32_t xpub_magic; + bool has_xprv_magic; + uint32_t xprv_magic; } CoinType; typedef struct { @@ -288,6 +292,8 @@ extern const uint32_t CoinType_address_type_default; extern const uint32_t CoinType_address_type_p2sh_default; extern const uint32_t CoinType_address_type_p2wpkh_default; extern const uint32_t CoinType_address_type_p2wsh_default; +extern const uint32_t CoinType_xpub_magic_default; +extern const uint32_t CoinType_xprv_magic_default; extern const uint32_t TxInputType_sequence_default; extern const InputScriptType TxInputType_script_type_default; extern const uint32_t IdentityType_index_default; @@ -295,7 +301,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, ""} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, "", false, 76067358u, false, 76066276u} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -306,7 +312,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, ""} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -325,6 +331,8 @@ extern const uint32_t IdentityType_index_default; #define CoinType_address_type_p2wpkh_tag 6 #define CoinType_address_type_p2wsh_tag 7 #define CoinType_signed_message_header_tag 8 +#define CoinType_xpub_magic_tag 9 +#define CoinType_xprv_magic_tag 10 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -382,7 +390,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[9]; +extern const pb_field_t CoinType_fields[11]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; @@ -395,7 +403,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 99 +#define CoinType_size 111 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5508 #define TxOutputType_size 3934 diff --git a/vendor/trezor-common b/vendor/trezor-common index 80c7b666a2..dd1f7a2b0b 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 80c7b666a204c74be1d1ed6b019d1fad2d2fe909 +Subproject commit dd1f7a2b0b44793734e286239f64ddb3d816058d diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index df2524e35b..fa82ba6d3f 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit df2524e35bc7d10129b965be017277ce46d2cae0 +Subproject commit fa82ba6d3f4ca9bbfee0c3dd7f8da22a8bfc6f11 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 9344f23d86..392ee5654f 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 9344f23d869030fbe7261d3361862eaba12b9975 +Subproject commit 392ee5654f4862f2e2b49b69a4e802997715d34f From 2866e6fe889beb7989135920db4ed70de597ee10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Apr 2017 20:34:13 +0200 Subject: [PATCH 0423/1154] ethereum: add EthereumSignTx.prefix --- firmware/ethereum.c | 8 ++++++++ firmware/protob/messages.options | 1 + firmware/protob/messages.pb.c | 3 ++- firmware/protob/messages.pb.h | 16 ++++++++++++---- vendor/trezor-common | 2 +- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index a7342391ad..8d6c78ec11 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -438,6 +438,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->to.size = 0; if (!msg->has_nonce) msg->nonce.size = 0; + if (!msg->has_prefix) + msg->prefix.size = 0; /* eip-155 chain id */ if (msg->has_chain_id) { @@ -512,6 +514,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing", 0); + if (msg->has_prefix) { + rlp_length += rlp_calculate_length(msg->prefix.size, msg->prefix.bytes[0]); + } rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); @@ -529,6 +534,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing", 100); + if (msg->has_prefix) { + hash_rlp_field(msg->prefix.bytes, msg->prefix.size); + } hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 7138c65978..c538e5e99d 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -100,6 +100,7 @@ EthereumSignTx.gas_limit max_size:32 EthereumSignTx.to max_size:20 EthereumSignTx.value max_size:32 EthereumSignTx.data_initial_chunk max_size:1024 +EthereumSignTx.prefix max_size:32 EthereumTxRequest.signature_r max_size:32 EthereumTxRequest.signature_s max_size:32 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index b2421129d4..5a55dbeb03 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -325,7 +325,7 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t EthereumSignTx_fields[10] = { +const pb_field_t EthereumSignTx_fields[11] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0), PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0), @@ -335,6 +335,7 @@ const pb_field_t EthereumSignTx_fields[10] = { PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0), PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0), + PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, prefix, chain_id, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 0dad8391fc..d8470eb997 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -444,6 +444,11 @@ typedef struct { uint8_t bytes[1024]; } EthereumSignTx_data_initial_chunk_t; +typedef struct { + size_t size; + uint8_t bytes[32]; +} EthereumSignTx_prefix_t; + typedef struct _EthereumSignTx { size_t address_n_count; uint32_t address_n[8]; @@ -463,6 +468,8 @@ typedef struct _EthereumSignTx { uint32_t data_length; bool has_chain_id; uint32_t chain_id; + bool has_prefix; + EthereumSignTx_prefix_t prefix; } EthereumSignTx; typedef struct { @@ -872,7 +879,7 @@ extern const uint32_t SignTx_lock_time_default; #define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} -#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} +#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, {0, {0}}} #define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_default {false, {0, {0}}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} @@ -936,7 +943,7 @@ extern const uint32_t SignTx_lock_time_default; #define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} -#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} +#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, {0, {0}}} #define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_zero {false, {0, {0}}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} @@ -1025,6 +1032,7 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumSignTx_data_initial_chunk_tag 7 #define EthereumSignTx_data_length_tag 8 #define EthereumSignTx_chain_id_tag 9 +#define EthereumSignTx_prefix_tag 10 #define EthereumTxAck_data_chunk_tag 1 #define EthereumTxRequest_data_length_tag 1 #define EthereumTxRequest_signature_v_tag 2 @@ -1173,7 +1181,7 @@ extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[6]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; -extern const pb_field_t EthereumSignTx_fields[10]; +extern const pb_field_t EthereumSignTx_fields[11]; extern const pb_field_t EthereumTxRequest_fields[5]; extern const pb_field_t EthereumTxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; @@ -1239,7 +1247,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define SignTx_size 43 #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) -#define EthereumSignTx_size 1245 +#define EthereumSignTx_size 1279 #define EthereumTxRequest_size 80 #define EthereumTxAck_size 1027 #define SignIdentity_size (558 + IdentityType_size) diff --git a/vendor/trezor-common b/vendor/trezor-common index dd1f7a2b0b..78da723c06 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit dd1f7a2b0b44793734e286239f64ddb3d816058d +Subproject commit 78da723c063ae0aa76e06a517fe48d0013928cc4 From aafd61ec8bb915f83dfa9d8f49824bf73238e9e1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 26 Apr 2017 15:43:57 +0200 Subject: [PATCH 0424/1154] update trezor-common, add cointype.segwit bool --- firmware/coins-gen.py | 5 ++++- firmware/coins.c | 16 ++++++++-------- firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 11 +++++++---- vendor/trezor-common | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index c7181d942e..39de05c38e 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -35,7 +35,10 @@ for c in coins: '0x%s' % c['xpub_magic'] if c['xpub_magic'] is not None else '00000000', 'true' if c['xprv_magic'] is not None else 'false', - '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000' + '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000', + + 'true' if c['segwit'] is not None else 'false', + 'true' if c['segwit'] else 'false' ]) for j in range(len(fields[0])): diff --git a/firmware/coins.c b/firmware/coins.c index f26808e2bf..abe080f75e 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,14 +26,14 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, }, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, }, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, }, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, }, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, }, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, }, - {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, }, - {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, }, + {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, + {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 7863d57ad6..13448c606c 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -30,7 +30,7 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[11] = { +const pb_field_t CoinType_fields[12] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), @@ -41,6 +41,7 @@ const pb_field_t CoinType_fields[11] = { PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2wsh, 0), PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), + PB_FIELD2( 11, BOOL , OPTIONAL, STATIC , OTHER, CoinType, segwit, xprv_magic, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 4586a9407b..8dd5cc5dfc 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -102,6 +102,8 @@ typedef struct _CoinType { uint32_t xpub_magic; bool has_xprv_magic; uint32_t xprv_magic; + bool has_segwit; + bool segwit; } CoinType; typedef struct { @@ -301,7 +303,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, "", false, 76067358u, false, 76066276u} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, "", false, 76067358u, false, 76066276u, false, 0} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -312,7 +314,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -333,6 +335,7 @@ extern const uint32_t IdentityType_index_default; #define CoinType_signed_message_header_tag 8 #define CoinType_xpub_magic_tag 9 #define CoinType_xprv_magic_tag 10 +#define CoinType_segwit_tag 11 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -390,7 +393,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[11]; +extern const pb_field_t CoinType_fields[12]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; @@ -403,7 +406,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 111 +#define CoinType_size 113 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5508 #define TxOutputType_size 3934 diff --git a/vendor/trezor-common b/vendor/trezor-common index 78da723c06..2148e5ff8d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 78da723c063ae0aa76e06a517fe48d0013928cc4 +Subproject commit 2148e5ff8d76444f82f8e4c833157df7de8eaba5 From 13f03d38808b28ecd24c09333208c60c8a1261f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Apr 2017 03:26:57 +0200 Subject: [PATCH 0425/1154] Revert "ethereum: add EthereumSignTx.prefix" This reverts commit 2866e6fe889beb7989135920db4ed70de597ee10. --- firmware/ethereum.c | 8 -------- firmware/protob/messages.options | 1 - firmware/protob/messages.pb.c | 3 +-- firmware/protob/messages.pb.h | 16 ++++------------ vendor/trezor-common | 2 +- 5 files changed, 6 insertions(+), 24 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 8d6c78ec11..a7342391ad 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -438,8 +438,6 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->to.size = 0; if (!msg->has_nonce) msg->nonce.size = 0; - if (!msg->has_prefix) - msg->prefix.size = 0; /* eip-155 chain id */ if (msg->has_chain_id) { @@ -514,9 +512,6 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing", 0); - if (msg->has_prefix) { - rlp_length += rlp_calculate_length(msg->prefix.size, msg->prefix.bytes[0]); - } rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); @@ -534,9 +529,6 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress("Signing", 100); - if (msg->has_prefix) { - hash_rlp_field(msg->prefix.bytes, msg->prefix.size); - } hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c538e5e99d..7138c65978 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -100,7 +100,6 @@ EthereumSignTx.gas_limit max_size:32 EthereumSignTx.to max_size:20 EthereumSignTx.value max_size:32 EthereumSignTx.data_initial_chunk max_size:1024 -EthereumSignTx.prefix max_size:32 EthereumTxRequest.signature_r max_size:32 EthereumTxRequest.signature_s max_size:32 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 5a55dbeb03..b2421129d4 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -325,7 +325,7 @@ const pb_field_t TxAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t EthereumSignTx_fields[11] = { +const pb_field_t EthereumSignTx_fields[10] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0), PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0), @@ -335,7 +335,6 @@ const pb_field_t EthereumSignTx_fields[11] = { PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0), PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0), - PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, prefix, chain_id, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index d8470eb997..0dad8391fc 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -444,11 +444,6 @@ typedef struct { uint8_t bytes[1024]; } EthereumSignTx_data_initial_chunk_t; -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumSignTx_prefix_t; - typedef struct _EthereumSignTx { size_t address_n_count; uint32_t address_n[8]; @@ -468,8 +463,6 @@ typedef struct _EthereumSignTx { uint32_t data_length; bool has_chain_id; uint32_t chain_id; - bool has_prefix; - EthereumSignTx_prefix_t prefix; } EthereumSignTx; typedef struct { @@ -879,7 +872,7 @@ extern const uint32_t SignTx_lock_time_default; #define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} -#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, {0, {0}}} +#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_default {false, {0, {0}}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} @@ -943,7 +936,7 @@ extern const uint32_t SignTx_lock_time_default; #define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} -#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, {0, {0}}} +#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_zero {false, {0, {0}}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} @@ -1032,7 +1025,6 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumSignTx_data_initial_chunk_tag 7 #define EthereumSignTx_data_length_tag 8 #define EthereumSignTx_chain_id_tag 9 -#define EthereumSignTx_prefix_tag 10 #define EthereumTxAck_data_chunk_tag 1 #define EthereumTxRequest_data_length_tag 1 #define EthereumTxRequest_signature_v_tag 2 @@ -1181,7 +1173,7 @@ extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[6]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; -extern const pb_field_t EthereumSignTx_fields[11]; +extern const pb_field_t EthereumSignTx_fields[10]; extern const pb_field_t EthereumTxRequest_fields[5]; extern const pb_field_t EthereumTxAck_fields[2]; extern const pb_field_t SignIdentity_fields[5]; @@ -1247,7 +1239,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define SignTx_size 43 #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) -#define EthereumSignTx_size 1279 +#define EthereumSignTx_size 1245 #define EthereumTxRequest_size 80 #define EthereumTxAck_size 1027 #define SignIdentity_size (558 + IdentityType_size) diff --git a/vendor/trezor-common b/vendor/trezor-common index 2148e5ff8d..fe6e62c11f 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 2148e5ff8d76444f82f8e4c833157df7de8eaba5 +Subproject commit fe6e62c11f7dca8cb601e53c5865f15f770fd079 From 38970cbd68aee688307c8922c1097a5a35324a8d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 3 May 2017 18:57:47 +0200 Subject: [PATCH 0426/1154] transaction: fix compile_output for OP_RETURN --- firmware/transaction.c | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index a844c16505..691f1ca056 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -161,38 +161,38 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T size_t addr_raw_len; bool is_segwit; + if (in->script_type == OutputScriptType_PAYTOOPRETURN) { + // only 0 satoshi allowed for OP_RETURN + if (in->amount != 0) { + return 0; // failed to compile output + } + uint32_t r = 0; + out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN + r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); + memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; + out->script_pubkey.size = r; + return r; + } + if (in->address_n_count > 0) { HDNode node; InputScriptType input_script_type; switch (in->script_type) { - - case OutputScriptType_PAYTOOPRETURN: - // only 0 satoshi allowed for OP_RETURN - if (in->amount != 0) + case OutputScriptType_PAYTOADDRESS: + input_script_type = InputScriptType_SPENDADDRESS; + break; + case OutputScriptType_PAYTOMULTISIG: + input_script_type = InputScriptType_SPENDMULTISIG; + break; + case OutputScriptType_PAYTOWITNESS: + input_script_type = InputScriptType_SPENDWITNESS; + break; + case OutputScriptType_PAYTOP2SHWITNESS: + input_script_type = InputScriptType_SPENDP2SHWITNESS; + break; + default: return 0; // failed to compile output - uint32_t r = 0; - out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN - r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); - memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; - out->script_pubkey.size = r; - return r; - - case OutputScriptType_PAYTOADDRESS: - input_script_type = InputScriptType_SPENDADDRESS; - break; - case OutputScriptType_PAYTOMULTISIG: - input_script_type = InputScriptType_SPENDMULTISIG; - break; - case OutputScriptType_PAYTOWITNESS: - input_script_type = InputScriptType_SPENDWITNESS; - break; - case OutputScriptType_PAYTOP2SHWITNESS: - input_script_type = InputScriptType_SPENDP2SHWITNESS; - break; - - default: - return 0; // failed to compile output } memcpy(&node, root, sizeof(HDNode)); if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { From cb14b9821399c285e29769e13a168f2001122215 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 May 2017 15:12:24 +0200 Subject: [PATCH 0427/1154] ethereum: add new chain_ids --- firmware/ethereum.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index a7342391ad..6e8bb0c6b4 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -242,10 +242,31 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25]) // remove trailing dot. if (value_ptr[-1] == '.') value_ptr--; - if (chain_id == 61 || chain_id == 62) { - strcpy(value_ptr, " ETC"); - } else { - strcpy(value_ptr, " ETH"); + switch (chain_id) { + case 61: + strcpy(value_ptr, " ETC"); // Ethereum Classic Mainnet + break; + case 62: + strcpy(value_ptr, " tETC"); // Ethereum Classic Testnet + break; + case 30: + strcpy(value_ptr, " RSK"); // Rootstock Mainnet + break; + case 31: + strcpy(value_ptr, " tRSK"); // Rootstock Testnet + break; + case 3: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Ropsten + break; + case 4: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Rinkeby + break; + case 42: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Kovan + break; + default: + strcpy(value_ptr, " ETH"); // Ethereum Mainnet + break; } // value is at most 16 + 4 + 1 characters long } else { From 4183b6cbbc73cbf70e600df5563c3dc02510c6a9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 May 2017 18:15:46 +0200 Subject: [PATCH 0428/1154] update logic for change addresses (address_n length 1 is allowed now) --- firmware/signing.c | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index d4921e03e3..500595da91 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -322,35 +322,51 @@ void phase2_request_next_input(void) void set_input_bip32_path(const TxInputType *tinput) { size_t count = tinput->address_n_count; - if (count < 2) { + if (count < 1) { // no change address allowed in_address_n_count = (size_t) -1; - } else if (in_address_n_count == 0) { + return; + } + if (in_address_n_count == 0) { // initialize in_address_n on first input seen in_address_n_count = count; - memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); - } else if (in_address_n_count != count - || memcmp(in_address_n, tinput->address_n, (count-2) * sizeof(uint32_t)) != 0) { - // mismatch -> no change address allowed - in_address_n_count = (size_t) -1; + if (count > 2) { // if longer than 2 elements, store first N - 2 + memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); + } + } else { + // check whether they are same length + if (in_address_n_count != count) { + in_address_n_count = (size_t) -1; + return; + } + if (count > 2 && memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { + // mismatch -> no change address allowed + in_address_n_count = (size_t) -1; + return; + } } } bool check_change_bip32_path(const TxOutputType *toutput) { size_t count = toutput->address_n_count; - // check that the last two components specify a sane address on the change chain - if (count < 2 - || toutput->address_n[count-2] != 1 - || toutput->address_n[count-1] > 1000000) - return 0; - // check that the other components exactly match input. - if (in_address_n_count != count - || memcmp(in_address_n, toutput->address_n, (count-2) * sizeof(uint32_t)) != 0) + if (count < 1) { return 0; + } - return 1; + if (count == 1) { + return in_address_n_count == 1 && toutput->address_n[0] < 1000000; + } + + if (count >= 2) { + return in_address_n_count == count && + 0 == memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) && + toutput->address_n[count - 2] == 1 && + toutput->address_n[count - 1] < 1000000; + } + + return 0; } bool compile_input_script_sig(TxInputType *tinput) From b1995bb8d1aad983770aae8a13106ed5cadbcf71 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 May 2017 18:54:54 +0200 Subject: [PATCH 0429/1154] remove segwit warning, don't enable segwit on coins that don't have segwit=true in definition --- firmware/fsm.c | 11 +---------- firmware/layout2.c | 15 --------------- firmware/layout2.h | 1 - firmware/signing.c | 9 +++++++-- firmware/transaction.c | 24 ++++++++++++++---------- firmware/transaction.h | 2 +- 6 files changed, 23 insertions(+), 39 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 527f7756c4..1c4b86df83 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -580,21 +580,12 @@ void fsm_msgGetAddress(GetAddress *msg) HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; hdnode_fill_public_key(node); - bool is_segwit = 0; - if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address, &is_segwit)) { + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); } if (msg->has_show_display && msg->show_display) { - if (is_segwit) { - layoutSegwitWarning(); - if (!protectButton(ButtonRequestType_ButtonRequest_Address, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); - layoutHome(); - return; - } - } char desc[16]; if (msg->has_multisig) { strlcpy(desc, "Msig __ of __:", sizeof(desc)); diff --git a/firmware/layout2.c b/firmware/layout2.c index bb6516a9ec..0a8e665231 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -426,18 +426,3 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico } layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL); } - -void layoutSegwitWarning() -{ - layoutDialogSwipe(&bmp_icon_info, - "Cancel", - "Understood", - NULL, - "The following address", - "is for SegWit soft fork.", - NULL, - "It is unsafe to use", - "until segwit activates.", - NULL - ); -} diff --git a/firmware/layout2.h b/firmware/layout2.h index 95633fa722..458fa55fda 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -45,6 +45,5 @@ void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); -void layoutSegwitWarning(void); #endif diff --git a/firmware/signing.c b/firmware/signing.c index 500595da91..4e5c197574 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -113,9 +113,9 @@ Phase2: sign inputs, check that nothing changed foreach I (idx1): // input to sign if (idx1 is segwit) Request I STAGE_REQUEST_SEGWIT_INPUT - Return serialized input chunk + Return serialized input chunk - else + else foreach I (idx2): Request I STAGE_REQUEST_4_INPUT If idx1 == idx2 @@ -771,6 +771,11 @@ void signing_txack(TransactionType *tx) send_req_2_prev_meta(); } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { + if (!coin->has_segwit || !coin->segwit) { + fsm_sendFailure(FailureType_Failure_Other, "Segwit not enabled on this coin"); + signing_abort(); + return; + } if (!tx->inputs[0].has_amount) { fsm_sendFailure(FailureType_Failure_Other, "Segwit input without amount"); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 691f1ca056..5956f12c07 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -62,8 +62,7 @@ bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, - char address[MAX_ADDR_SIZE], - bool *is_segwit) { + char address[MAX_ADDR_SIZE]) { uint8_t raw[32]; uint8_t digest[MAX_ADDR_RAW_SIZE]; @@ -78,7 +77,9 @@ bool compute_address(const CoinType *coin, } if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wsh: script hash is single sha256 - *is_segwit = 1; + if (!coin->has_segwit || !coin->segwit) { + return 0; + } if (!coin->has_address_type_p2wsh) { return 0; } @@ -92,7 +93,9 @@ bool compute_address(const CoinType *coin, } } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wsh encapsuled in p2sh address - *is_segwit = 1; + if (!coin->has_segwit || !coin->segwit) { + return 0; + } if (!coin->has_address_type_p2sh) { return 0; } @@ -108,7 +111,6 @@ bool compute_address(const CoinType *coin, } } else { // non-segwit p2sh multisig - *is_segwit = 0; prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); @@ -118,7 +120,9 @@ bool compute_address(const CoinType *coin, } } else if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wpkh: pubkey hash is ripemd160 of sha256 - *is_segwit = 1; + if (!coin->has_segwit || !coin->segwit) { + return 0; + } if (!coin->has_address_type_p2wpkh) { return 0; } @@ -132,7 +136,9 @@ bool compute_address(const CoinType *coin, } } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wpkh embedded in p2sh - *is_segwit = 1; + if (!coin->has_segwit || !coin->segwit) { + return 0; + } if (!coin->has_address_type_p2sh) { return 0; } @@ -147,7 +153,6 @@ bool compute_address(const CoinType *coin, return 0; } } else { - *is_segwit = 0; ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE); } return 1; @@ -159,7 +164,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T out->amount = in->amount; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; size_t addr_raw_len; - bool is_segwit; if (in->script_type == OutputScriptType_PAYTOOPRETURN) { // only 0 satoshi allowed for OP_RETURN @@ -201,7 +205,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T hdnode_fill_public_key(&node); if (!compute_address(coin, input_script_type, &node, in->has_multisig, &in->multisig, - in->address, &is_segwit)) { + in->address)) { return 0; // failed to compile output } } else if (!in->has_address) { diff --git a/firmware/transaction.h b/firmware/transaction.h index 808ccbca2e..06d07f765e 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -45,7 +45,7 @@ typedef struct { SHA256_CTX ctx; } TxStruct; -bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE], bool *is_segwit); +bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); From e31e55e5050155c426bab0b6f2d11412908fbbae Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 5 May 2017 14:37:40 +0200 Subject: [PATCH 0430/1154] simplify bip32 change logic --- firmware/signing.c | 51 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 4e5c197574..dedbec4068 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -319,8 +319,11 @@ void phase2_request_next_input(void) } } -void set_input_bip32_path(const TxInputType *tinput) +void extract_input_bip32_path(const TxInputType *tinput) { + if (in_address_n_count == (size_t) -1) { + return; + } size_t count = tinput->address_n_count; if (count < 1) { // no change address allowed @@ -333,40 +336,46 @@ void set_input_bip32_path(const TxInputType *tinput) if (count > 2) { // if longer than 2 elements, store first N - 2 memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); } - } else { - // check whether they are same length - if (in_address_n_count != count) { - in_address_n_count = (size_t) -1; - return; - } - if (count > 2 && memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { - // mismatch -> no change address allowed - in_address_n_count = (size_t) -1; - return; - } + return; + } + // check whether they are same length + if (in_address_n_count != count) { + in_address_n_count = (size_t) -1; + return; + } + if (count > 2 && memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { + // mismatch -> no change address allowed + in_address_n_count = (size_t) -1; + return; } } +#define MAX_BIP32_LAST_ELEMENT 1000000 + bool check_change_bip32_path(const TxOutputType *toutput) { size_t count = toutput->address_n_count; - if (count < 1) { + if (count < 1 || in_address_n_count < 1) { return 0; } - if (count == 1) { - return in_address_n_count == 1 && toutput->address_n[0] < 1000000; + if (count != in_address_n_count) { + return 0; + } + + if (toutput->address_n[count - 1] > MAX_BIP32_LAST_ELEMENT) { + return 0; } if (count >= 2) { - return in_address_n_count == count && - 0 == memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) && - toutput->address_n[count - 2] == 1 && - toutput->address_n[count - 1] < 1000000; + if (0 != memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) || + toutput->address_n[count - 2] != 1) { + return 0; + } } - return 0; + return 1; } bool compile_input_script_sig(TxInputType *tinput) @@ -463,7 +472,7 @@ static bool signing_check_input(TxInputType *txinput) { } // remember the input bip32 path // change addresses must use the same bip32 path as all inputs - set_input_bip32_path(txinput); + extract_input_bip32_path(txinput); // compute segwit hashPrevouts & hashSequence tx_prevout_hash(&hashers[0], txinput); tx_sequence_hash(&hashers[1], txinput); From 4343d0eaeb483127c07ca4ee62c3d6febd1f12bd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 5 May 2017 15:45:58 +0200 Subject: [PATCH 0431/1154] show progressbar layout in GetAddress --- firmware/fsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 1c4b86df83..70cfaf08f2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -581,6 +581,7 @@ void fsm_msgGetAddress(GetAddress *msg) if (!node) return; hdnode_fill_public_key(node); + layoutProgress("Computing address", 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); } From 261b8d5e411f95189bbc36da0f8bef2b99678a76 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 6 May 2017 19:52:49 +0200 Subject: [PATCH 0432/1154] multisig: allow mismatched change addresses, show them as non-change --- firmware/signing.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index dedbec4068..780a587cb5 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -510,14 +510,11 @@ static bool signing_check_output(TxOutputType *txoutput) { } if (txoutput->script_type == OutputScriptType_PAYTOMULTISIG) { uint8_t h[32]; - if (!multisig_fp_set || multisig_fp_mismatch - || cryptoMultisigFingerprint(&(txoutput->multisig), h) == 0 - || memcmp(multisig_fp, h, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig change address"); - signing_abort(); - return false; + if (multisig_fp_set && !multisig_fp_mismatch + && cryptoMultisigFingerprint(&(txoutput->multisig), h) + && memcmp(multisig_fp, h, 32) == 0) { + is_change = check_change_bip32_path(txoutput); } - is_change = check_change_bip32_path(txoutput); } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS || ((txoutput->script_type == OutputScriptType_PAYTOWITNESS || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) From 5faee8149f11fd1584e5b50c22d0f473cd4a8175 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 May 2017 17:16:20 +0200 Subject: [PATCH 0433/1154] update trezor-crypto --- Makefile.include | 1 + firmware/Makefile | 8 ++++---- vendor/trezor-crypto | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index 7e71499fd4..524f62229d 100644 --- a/Makefile.include +++ b/Makefile.include @@ -48,6 +48,7 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ + -I$(TOP_DIR)vendor/trezor-crypto/aes \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc diff --git a/firmware/Makefile b/firmware/Makefile index 1638b857be..88fe99fec6 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -38,10 +38,10 @@ OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha3.o -OBJS += ../vendor/trezor-crypto/aescrypt.o -OBJS += ../vendor/trezor-crypto/aeskey.o -OBJS += ../vendor/trezor-crypto/aestab.o -OBJS += ../vendor/trezor-crypto/aes_modes.o +OBJS += ../vendor/trezor-crypto/aes/aescrypt.o +OBJS += ../vendor/trezor-crypto/aes/aeskey.o +OBJS += ../vendor/trezor-crypto/aes/aestab.o +OBJS += ../vendor/trezor-crypto/aes/aes_modes.o OBJS += ../vendor/trezor-qrenc/qr_encode.o diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index fa82ba6d3f..ea227fd805 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit fa82ba6d3f4ca9bbfee0c3dd7f8da22a8bfc6f11 +Subproject commit ea227fd805fb97aa2fa76a89bfd05d44012d153f From 31a09a9f7501f4572a93a9d054e377d021cbe60a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 9 May 2017 01:42:23 +0200 Subject: [PATCH 0434/1154] fix Docker build of libopencm3 --- bootloader-docker-build.sh | 2 +- firmware-docker-build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index d25e7e0234..5a136f0534 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -10,7 +10,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ - make -C vendor/libopencm3 && \ + CFLAGS='-std=c99' make -C vendor/libopencm3 && \ export OPTFLAGS=-Os make && \ make -C bootloader && \ diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh index 564a45e7e5..7738a98c00 100755 --- a/firmware-docker-build.sh +++ b/firmware-docker-build.sh @@ -10,7 +10,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ cd trezor-mcu && \ git checkout $FIRMWARETAG && \ git submodule update --init && \ - make -C vendor/libopencm3 && \ + CFLAGS='-std=c99' make -C vendor/libopencm3 && \ make && \ make -C firmware && \ make -C firmware sign && \ From 1ecbca83381118637481ab0293bb9bcb1d2ede95 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 9 May 2017 23:26:18 +0200 Subject: [PATCH 0435/1154] signing: add option to enable/disable mixing of segwit/non-segwit inputs --- firmware/signing.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index 780a587cb5..8871b01e4b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -748,6 +748,8 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { return true; } +#define ENABLE_SEGWIT_NONSEGWIT_MIXING 0 + void signing_txack(TransactionType *tx) { if (!signing) { @@ -774,6 +776,14 @@ void signing_txack(TransactionType *tx) if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1; memcpy(&input, tx->inputs, sizeof(TxInputType)); +#if !ENABLE_SEGWIT_NONSEGWIT_MIXING + // don't mix segwit and non-segwit inputs + if (idx1 > 0 && to.is_segwit == true) { + fsm_sendFailure(FailureType_Failure_Other, "Mixing segwit and non-segwit inputs is not allowed"); + signing_abort(); + return; + } +#endif send_req_2_prev_meta(); } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { @@ -792,9 +802,20 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } +#if !ENABLE_SEGWIT_NONSEGWIT_MIXING + // don't mix segwit and non-segwit inputs + if (idx1 == 0) { + to.is_segwit = true; + } else if (to.is_segwit == false) { + fsm_sendFailure(FailureType_Failure_Other, "Mixing segwit and non-segwit inputs is not allowed"); + signing_abort(); + return; + } +#else + to.is_segwit = true; +#endif to_spend += tx->inputs[0].amount; segwit_to_spend += tx->inputs[0].amount; - to.is_segwit = true; phase1_request_next_input(); } else { fsm_sendFailure(FailureType_Failure_Other, "Wrong input script type"); From 6d0d2348cfa78020a2d94f27fc33965cc5de75b4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 9 May 2017 23:49:05 +0200 Subject: [PATCH 0436/1154] usb: whitespace cleanup --- firmware/usb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 0bd7aed821..9b7085337f 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -128,16 +128,16 @@ static const uint8_t hid_report_descriptor_u2f[] = { 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x20, // USAGE (Input Report Data) 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75,0x08, // REPORT_SIZE (8) - 0x95,0x40, // REPORT_COUNT (64) - 0x81,0x02, // INPUT (Data,Var,Abs) - 0x09,0x21, // USAGE (Output Report Data) - 0x15,0x00, // LOGICAL_MINIMUM (0) - 0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75,0x08, // REPORT_SIZE (8) - 0x95,0x40, // REPORT_COUNT (64) - 0x91,0x02, // OUTPUT (Data,Var,Abs) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0 // END_COLLECTION }; From f4e3d7ae1eb2357585b377c27ae6d76fa164ca61 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 May 2017 00:12:23 +0200 Subject: [PATCH 0437/1154] bump version to 1.5.0 --- firmware/trezor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index 4303afc601..8005e8ac65 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,8 +21,8 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 4 -#define VERSION_PATCH 2 +#define VERSION_MINOR 5 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 06304c2378ed9b4ec867f6a9f384257a6394cd29 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 12 May 2017 23:00:42 +0200 Subject: [PATCH 0438/1154] update coins --- firmware/coins-gen.py | 6 ------ firmware/coins.c | 16 ++++++++-------- firmware/protob/types.pb.c | 8 ++------ firmware/protob/types.pb.h | 16 ++++------------ vendor/trezor-common | 2 +- 5 files changed, 15 insertions(+), 33 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 39de05c38e..7cb323c725 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -22,12 +22,6 @@ for c in coins: 'true' if c['address_type_p2sh'] is not None else 'false', '%d' % c['address_type_p2sh'] if c['address_type_p2sh'] is not None else '0', - 'true' if c['address_type_p2wpkh'] is not None else 'false', - '%d' % c['address_type_p2wpkh'] if c['address_type_p2wpkh'] is not None else '0', - - 'true' if c['address_type_p2wsh'] is not None else 'false', - '%d' % c['address_type_p2wsh'] if c['address_type_p2wsh'] is not None else '0', - 'true' if c['signed_message_header'] is not None else 'false', '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', diff --git a/firmware/coins.c b/firmware/coins.c index abe080f75e..ac1f54defa 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,14 +26,14 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, 6, true, 10, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, - {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, - {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, false, 0, false, 0, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, + {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, + {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, + {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, + {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, + {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, + {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, }; const CoinType *coinByShortcut(const char *shortcut) diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index 13448c606c..dfc9a49084 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -5,8 +5,6 @@ const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_p2sh_default = 5u; -const uint32_t CoinType_address_type_p2wpkh_default = 6u; -const uint32_t CoinType_address_type_p2wsh_default = 10u; const uint32_t CoinType_xpub_magic_default = 76067358u; const uint32_t CoinType_xprv_magic_default = 76066276u; const uint32_t TxInputType_sequence_default = 4294967295u; @@ -30,15 +28,13 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[12] = { +const pb_field_t CoinType_fields[10] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), - PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wpkh, address_type_p2sh, &CoinType_address_type_p2wpkh_default), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wsh, address_type_p2wpkh, &CoinType_address_type_p2wsh_default), - PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2wsh, 0), + PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2sh, 0), PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), PB_FIELD2( 11, BOOL , OPTIONAL, STATIC , OTHER, CoinType, segwit, xprv_magic, 0), diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 30c52123c5..892b0df88d 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -92,10 +92,6 @@ typedef struct _CoinType { uint64_t maxfee_kb; bool has_address_type_p2sh; uint32_t address_type_p2sh; - bool has_address_type_p2wpkh; - uint32_t address_type_p2wpkh; - bool has_address_type_p2wsh; - uint32_t address_type_p2wsh; bool has_signed_message_header; char signed_message_header[32]; bool has_xpub_magic; @@ -292,8 +288,6 @@ extern const pb_extension_type_t wire_debug_out; /* Default values for struct fields */ extern const uint32_t CoinType_address_type_default; extern const uint32_t CoinType_address_type_p2sh_default; -extern const uint32_t CoinType_address_type_p2wpkh_default; -extern const uint32_t CoinType_address_type_p2wsh_default; extern const uint32_t CoinType_xpub_magic_default; extern const uint32_t CoinType_xprv_magic_default; extern const uint32_t TxInputType_sequence_default; @@ -303,7 +297,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u, false, "", false, 76067358u, false, 76066276u, false, 0} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, "", false, 76067358u, false, 76066276u, false, 0} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -314,7 +308,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -330,8 +324,6 @@ extern const uint32_t IdentityType_index_default; #define CoinType_address_type_tag 3 #define CoinType_maxfee_kb_tag 4 #define CoinType_address_type_p2sh_tag 5 -#define CoinType_address_type_p2wpkh_tag 6 -#define CoinType_address_type_p2wsh_tag 7 #define CoinType_signed_message_header_tag 8 #define CoinType_xpub_magic_tag 9 #define CoinType_xprv_magic_tag 10 @@ -393,7 +385,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[12]; +extern const pb_field_t CoinType_fields[10]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; @@ -406,7 +398,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 113 +#define CoinType_size 101 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5508 #define TxOutputType_size 3947 diff --git a/vendor/trezor-common b/vendor/trezor-common index fe6e62c11f..564801fddc 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit fe6e62c11f7dca8cb601e53c5865f15f770fd079 +Subproject commit 564801fddc908c30e0ef8410465a193ae35e2992 From 49f44d296cb4c1695ac35da07bc33e796acd67b8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 May 2017 00:45:11 +0200 Subject: [PATCH 0439/1154] refactor signing_check_output --- firmware/signing.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 8871b01e4b..36c3f8d010 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -515,10 +515,11 @@ static bool signing_check_output(TxOutputType *txoutput) { && memcmp(multisig_fp, h, 32) == 0) { is_change = check_change_bip32_path(txoutput); } - } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS - || ((txoutput->script_type == OutputScriptType_PAYTOWITNESS - || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) - && txoutput->amount < segwit_to_spend)) { + } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS) { + is_change = check_change_bip32_path(txoutput); + } else if (txoutput->script_type == OutputScriptType_PAYTOWITNESS && txoutput->amount < segwit_to_spend) { + is_change = check_change_bip32_path(txoutput); + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS && txoutput->amount < segwit_to_spend) { is_change = check_change_bip32_path(txoutput); } } From 24ac52079fa6b61ba18fd595e637bcbcbfb17135 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 May 2017 01:03:03 +0200 Subject: [PATCH 0440/1154] disable native segwit for now --- firmware/coins.c | 8 ------- firmware/signing.c | 12 +++++++++++ firmware/transaction.c | 47 +++++++----------------------------------- 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index ac1f54defa..2643b6a5f1 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -92,14 +92,6 @@ bool coinExtractAddressTypeRaw(const CoinType *coin, const uint8_t *addr_raw, ui *address_type = coin->address_type_p2sh; return true; } - if (coin->has_address_type_p2wpkh && address_check_prefix(addr_raw, coin->address_type_p2wpkh)) { - *address_type = coin->address_type_p2wpkh; - return true; - } - if (coin->has_address_type_p2wsh && address_check_prefix(addr_raw, coin->address_type_p2wsh)) { - *address_type = coin->address_type_p2wsh; - return true; - } *address_type = 0; return false; } diff --git a/firmware/signing.c b/firmware/signing.c index 36c3f8d010..e6f29369c0 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -656,6 +656,12 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { if (txinput->script_type == InputScriptType_SPENDWITNESS || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + // disable native segwit for now + if (txinput->script_type == InputScriptType_SPENDWITNESS) { + fsm_sendFailure(FailureType_Failure_Other, "Native segwit is disabled"); + signing_abort(); + return false; + } if (!compile_input_script_sig(txinput)) { fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); signing_abort(); @@ -793,6 +799,12 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + // disable native segwit for now + if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS) { + fsm_sendFailure(FailureType_Failure_Other, "Native segwit is disabled"); + signing_abort(); + return; + } if (!tx->inputs[0].has_amount) { fsm_sendFailure(FailureType_Failure_Other, "Segwit input without amount"); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 5956f12c07..27cfb72309 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -80,17 +80,8 @@ bool compute_address(const CoinType *coin, if (!coin->has_segwit || !coin->segwit) { return 0; } - if (!coin->has_address_type_p2wsh) { - return 0; - } - prelen = address_prefix_bytes_len(coin->address_type_p2wsh); - address_write_prefix_bytes(coin->address_type_p2wsh, raw); - raw[prelen] = 0; // version byte - raw[prelen + 1] = 0; // always 0, see bip-142 - memcpy(raw+prelen+2, digest, 32); - if (!base58_encode_check(raw, prelen + 34, address, MAX_ADDR_SIZE)) { - return 0; - } + // disable native segwit for now + return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wsh encapsuled in p2sh address if (!coin->has_segwit || !coin->segwit) { @@ -123,17 +114,8 @@ bool compute_address(const CoinType *coin, if (!coin->has_segwit || !coin->segwit) { return 0; } - if (!coin->has_address_type_p2wpkh) { - return 0; - } - prelen = address_prefix_bytes_len(coin->address_type_p2wpkh); - address_write_prefix_bytes(coin->address_type_p2wpkh, raw); - raw[prelen] = 0; // version byte - raw[prelen + 1] = 0; // always 0, see bip-142 - ecdsa_get_pubkeyhash(node->public_key, raw + prelen + 2); - if (!base58_encode_check(raw, prelen + 22, address, MAX_ADDR_SIZE)) { - return 0; - } + // disable native segwit for now + return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wpkh embedded in p2sh if (!coin->has_segwit || !coin->segwit) { @@ -190,8 +172,8 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T input_script_type = InputScriptType_SPENDMULTISIG; break; case OutputScriptType_PAYTOWITNESS: - input_script_type = InputScriptType_SPENDWITNESS; - break; + // disable native segwit for now + return 0; case OutputScriptType_PAYTOP2SHWITNESS: input_script_type = InputScriptType_SPENDP2SHWITNESS; break; @@ -215,8 +197,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; if (address_check_prefix(addr_raw, coin->address_type) // p2pkh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { - + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes @@ -231,20 +212,6 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; - } else if (address_check_prefix(addr_raw, coin->address_type_p2wpkh) - && addr_raw_len == 22 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wpkh)) - && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wpkh v0 - out->script_pubkey.bytes[0] = 0x00; // version 0 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 20); - out->script_pubkey.size = 22; - } else if (address_check_prefix(addr_raw, coin->address_type_p2wsh) - && addr_raw_len == 34 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2wsh)) - && addr_raw[prefix_len] == 0 && addr_raw[prefix_len + 1] == 0) { // p2wsh v0 - out->script_pubkey.bytes[0] = 0x00; // version 0 - out->script_pubkey.bytes[1] = 0x20; // pushing 32 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len + 2, 32); - out->script_pubkey.size = 34; } else { return 0; } From c8dc17341c5a103bbc8d5b425214e8c01d72f730 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 May 2017 01:29:12 +0200 Subject: [PATCH 0441/1154] bump bitcoin maxfee --- firmware/coins.c | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 2643b6a5f1..9278f6f5e1 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,7 +26,7 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 300000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Bitcoin", true, "BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, diff --git a/vendor/trezor-common b/vendor/trezor-common index 564801fddc..54000d8438 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 564801fddc908c30e0ef8410465a193ae35e2992 +Subproject commit 54000d8438bedc9b762a58846a21535444f6db9d From 391e3940e5783c1abf3d118db152c61efa4b7ab0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 May 2017 12:08:54 +0200 Subject: [PATCH 0442/1154] refactor fee computation, but keep ceil logic --- firmware/layout2.c | 3 +-- firmware/layout2.h | 2 +- firmware/signing.c | 6 +++--- firmware/transaction.c | 5 ----- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 0a8e665231..94f0eb5268 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -153,9 +153,8 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ ); } -void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb) +void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) { - (void)kb; const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); layoutDialogSwipe(&bmp_icon_question, "Cancel", diff --git a/firmware/layout2.h b/firmware/layout2.h index 458fa55fda..2ed72614e7 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -33,7 +33,7 @@ void layoutScreensaver(void); void layoutHome(void); void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); -void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); +void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyAddress(const char *address); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); diff --git a/firmware/signing.c b/firmware/signing.c index e6f29369c0..0d2b705251 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -566,9 +566,9 @@ static bool signing_check_fee(void) { return false; } uint64_t fee = to_spend - spending; - uint32_t tx_est_size = transactionEstimateSizeKb(inputs_count, outputs_count); - if (fee > (uint64_t)tx_est_size * coin->maxfee_kb) { - layoutFeeOverThreshold(coin, fee, tx_est_size); + uint64_t tx_est_size_kb = (transactionEstimateSize(inputs_count, outputs_count) + 999) / 1000; + if (fee > tx_est_size_kb * coin->maxfee_kb) { + layoutFeeOverThreshold(coin, fee); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 27cfb72309..70954e0f3c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -570,8 +570,3 @@ uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs) { return 10 + inputs * 149 + outputs * 35; } - -uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs) -{ - return (transactionEstimateSize(inputs, outputs) + 999) / 1000; -} From ba9aae143e1f2a1c2442116c020fbf39104eb217 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 May 2017 14:00:55 +0200 Subject: [PATCH 0443/1154] ethereum: support for ERC-20 tokens --- firmware/Makefile | 1 + firmware/coins.c | 9 +-- firmware/ethereum.c | 100 ++++++++++++++++++++------------ firmware/ethereum_tokens-gen.py | 24 ++++++++ firmware/ethereum_tokens.c | 59 +++++++++++++++++++ firmware/ethereum_tokens.h | 37 ++++++++++++ 6 files changed, 186 insertions(+), 44 deletions(-) create mode 100755 firmware/ethereum_tokens-gen.py create mode 100644 firmware/ethereum_tokens.c create mode 100644 firmware/ethereum_tokens.h diff --git a/firmware/Makefile b/firmware/Makefile index 88fe99fec6..8833df3842 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -18,6 +18,7 @@ OBJS += reset.o OBJS += signing.o OBJS += crypto.o OBJS += ethereum.o +OBJS += ethereum_tokens.o OBJS += debug.o diff --git a/firmware/coins.c b/firmware/coins.c index 9278f6f5e1..0ceaf3d499 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -39,8 +39,7 @@ const CoinType coins[COINS_COUNT] = { const CoinType *coinByShortcut(const char *shortcut) { if (!shortcut) return 0; - int i; - for (i = 0; i < COINS_COUNT; i++) { + for (int i = 0; i < COINS_COUNT; i++) { if (strcmp(shortcut, coins[i].coin_shortcut) == 0) { return &(coins[i]); } @@ -51,8 +50,7 @@ const CoinType *coinByShortcut(const char *shortcut) const CoinType *coinByName(const char *name) { if (!name) return 0; - int i; - for (i = 0; i < COINS_COUNT; i++) { + for (int i = 0; i < COINS_COUNT; i++) { if (strcmp(name, coins[i].coin_name) == 0) { return &(coins[i]); } @@ -62,8 +60,7 @@ const CoinType *coinByName(const char *name) const CoinType *coinByAddressType(uint32_t address_type) { - int i; - for (i = 0; i < COINS_COUNT; i++) { + for (int i = 0; i < COINS_COUNT; i++) { if (address_type == coins[i].address_type) { return &(coins[i]); } diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 6e8bb0c6b4..b309a3ddbf 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -30,6 +30,7 @@ #include "secp256k1.h" #include "sha3.h" #include "util.h" +#include "ethereum_tokens.h" static bool ethereum_signing = false; static uint32_t data_total, data_left; @@ -196,8 +197,9 @@ static void send_signature(void) * using standard ethereum units. * The buffer must be at least 25 bytes. */ -static void ethereumFormatAmount(bignum256 *val, char buffer[25]) +static void ethereumFormatAmount(bignum256 *val, char buffer[25], const TokenType *token) { + // TODO: use token->decimals to properly format amount char value[25] = {0}; char *value_ptr = value; @@ -242,36 +244,40 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25]) // remove trailing dot. if (value_ptr[-1] == '.') value_ptr--; - switch (chain_id) { - case 61: - strcpy(value_ptr, " ETC"); // Ethereum Classic Mainnet - break; - case 62: - strcpy(value_ptr, " tETC"); // Ethereum Classic Testnet - break; - case 30: - strcpy(value_ptr, " RSK"); // Rootstock Mainnet - break; - case 31: - strcpy(value_ptr, " tRSK"); // Rootstock Testnet - break; - case 3: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Ropsten - break; - case 4: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Rinkeby - break; - case 42: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Kovan - break; - default: - strcpy(value_ptr, " ETH"); // Ethereum Mainnet - break; + if (token) { + strcpy(value_ptr, token->ticker); // ERC-20 Token + } else { + switch (chain_id) { + case 61: + strcpy(value_ptr, " ETC"); // Ethereum Classic Mainnet + break; + case 62: + strcpy(value_ptr, " tETC"); // Ethereum Classic Testnet + break; + case 30: + strcpy(value_ptr, " RSK"); // Rootstock Mainnet + break; + case 31: + strcpy(value_ptr, " tRSK"); // Rootstock Testnet + break; + case 3: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Ropsten + break; + case 4: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Rinkeby + break; + case 42: + strcpy(value_ptr, " tETH"); // Ethereum Testnet: Kovan + break; + default: + strcpy(value_ptr, " ETH"); // Ethereum Mainnet + break; + } } // value is at most 16 + 4 + 1 characters long } else { // value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik) - strlcpy(value, "trillions of ETH", sizeof(value)); + strlcpy(value, "gazillions of money", sizeof(value)); } // skip leading zeroes @@ -284,7 +290,7 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25]) strcpy(buffer, value_ptr); } -static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len) +static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token) { bignum256 val; uint8_t pad_val[32]; @@ -293,10 +299,14 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui bn_read_be(pad_val, &val); char amount[25]; - if (bn_is_zero(&val)) { - strcpy(amount, "message"); + if (token == NULL) { + if (bn_is_zero(&val)) { + strcpy(amount, "message"); + } else { + ethereumFormatAmount(&val, amount, NULL); + } } else { - ethereumFormatAmount(&val, amount); + ethereumFormatAmount(&val, amount, token); } static char _to1[17] = {0}; @@ -369,7 +379,8 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, const uint8_t *gas_price, uint32_t gas_price_len, - const uint8_t *gas_limit, uint32_t gas_limit_len) + const uint8_t *gas_limit, uint32_t gas_limit_len, + bool is_token) { bignum256 val, gas; uint8_t pad_val[32]; @@ -385,16 +396,16 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, bn_read_be(pad_val, &gas); bn_multiply(&val, &gas, &secp256k1.prime); - ethereumFormatAmount(&gas, gas_value); + ethereumFormatAmount(&gas, gas_value, NULL); memset(pad_val, 0, sizeof(pad_val)); memcpy(pad_val + (32 - value_len), value, value_len); bn_read_be(pad_val, &val); if (bn_is_zero(&val)) { - strcpy(tx_value, "message"); + strcpy(tx_value, is_token ? "token" : "message"); } else { - ethereumFormatAmount(&val, tx_value); + ethereumFormatAmount(&val, tx_value, NULL); } layoutDialogSwipe(&bmp_icon_question, @@ -503,14 +514,27 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) return; } - layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size); + const TokenType *token = NULL; + + // detect ERC-20 token + if (msg->to.size == 20 && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 + && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { + token = tokenByAddress(msg->to.bytes); + } + + if (token != NULL) { + layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); + } else { + layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL); + } + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); ethereum_signing_abort(); return; } - if (data_total > 0) { + if (token == NULL && data_total > 0) { layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); @@ -521,7 +545,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes, msg->gas_price.size, - msg->gas_limit.bytes, msg->gas_limit.size); + msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); ethereum_signing_abort(); diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py new file mode 100755 index 0000000000..5c1199e391 --- /dev/null +++ b/firmware/ethereum_tokens-gen.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +import requests + +def get_tokens(): + URL = 'https://raw.githubusercontent.com/kvhnuke/etherwallet/mercury/app/scripts/tokens/ethTokens.json' + r = requests.get(URL) + return r.json() + +tokens = get_tokens() + +subst = { + 'BeerCoin \U0001F37A': 'BEER', + 'CryptoCarbon': 'CCRB', + 'DAO_extraBalance': 'DAOe', + 'DGX 1.0': 'DGX1', + 'Unicorn \U0001F984': 'UNCRN', +} + +for t in tokens: + address, symbol, decimal = t['address'], t['symbol'], t['decimal'] + if symbol in subst: + symbol = subst[symbol] + address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() + print('\t{"%s", " %s", %d},' % (address, symbol, decimal)) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c new file mode 100644 index 0000000000..85311ca321 --- /dev/null +++ b/firmware/ethereum_tokens.c @@ -0,0 +1,59 @@ +#include +#include "ethereum_tokens.h" + +const TokenType tokens[TOKENS_COUNT] = { + {"\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, + {"\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, + {"\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, + {"\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, + {"\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, + {"\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, + {"\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, + {"\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, + {"\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, + {"\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, + {"\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, + {"\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, + {"\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, + {"\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, + {"\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, + {"\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, + {"\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, + {"\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, + {"\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, + {"\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, + {"\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, + {"\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, + {"\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, + {"\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, + {"\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, + {"\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + {"\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, + {"\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, + {"\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, + {"\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, + {"\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " ROL", 16}, + {"\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, + {"\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, + {"\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, + {"\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, + {"\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, + {"\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, + {"\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, + {"\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, + {"\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN ", 0}, + {"\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, + {"\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, + {"\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, +}; + +const TokenType *tokenByAddress(const uint8_t *address) +{ + if (!address) return 0; + for (int i = 0; i < TOKENS_COUNT; i++) { + if (memcmp(address, tokens[i].address, 20) == 0) { + return &(tokens[i]); + } + } + return 0; +} diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h new file mode 100644 index 0000000000..3109ed98db --- /dev/null +++ b/firmware/ethereum_tokens.h @@ -0,0 +1,37 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __ETHEREUM_TOKENS_H__ +#define __ETHEREUM_TOKENS_H__ + +#include + +#define TOKENS_COUNT 43 + +typedef struct { + const char * const address; + const char * const ticker; + int decimals; +} TokenType; + +extern const TokenType tokens[TOKENS_COUNT]; + +const TokenType *tokenByAddress(const uint8_t *address); + +#endif From 652a40c3e654318aa813f011d59dd79792fc99a7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 18 May 2017 16:19:10 +0200 Subject: [PATCH 0444/1154] use bn_format from trezor-crypto where possible --- firmware/ethereum.c | 126 ++++++++------------------------ firmware/ethereum_tokens-gen.py | 2 +- firmware/layout2.c | 52 ++++--------- vendor/trezor-crypto | 2 +- 4 files changed, 48 insertions(+), 134 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index b309a3ddbf..87a2511dfc 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -192,102 +192,36 @@ static void send_signature(void) ethereum_signing_abort(); } - /* Format a 256 bit number (amount in wei) into a human readable format * using standard ethereum units. * The buffer must be at least 25 bytes. */ -static void ethereumFormatAmount(bignum256 *val, char buffer[25], const TokenType *token) +static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, char *buf, int buflen) { - // TODO: use token->decimals to properly format amount - char value[25] = {0}; - char *value_ptr = value; - - // convert val into base 1000 for easy printing. - uint16_t num[26]; - uint8_t last_used = 0; - for (int i = 0; i < 26; i++) { - uint32_t limb; - bn_divmod1000(val, &limb); - // limb is < 1000. - num[i] = (uint16_t) limb; - if (limb > 0) { - last_used = i; - } - } - - if (last_used < 3) { - // value is smaller than 1e9 wei => show value in wei - for (int i = last_used; i >= 0; i--) { - *value_ptr++ = '0' + (num[i] / 100) % 10; - *value_ptr++ = '0' + (num[i] / 10) % 10; - *value_ptr++ = '0' + (num[i]) % 10; - } - strcpy(value_ptr, " Wei"); - // value is at most 9 + 4 + 1 characters long - } else if (last_used < 10) { - // value is bigger than 1e9 wei and smaller than 1e12 ETH => show value in ETH - int i = last_used; - if (i < 6) - i = 6; - int end = i - 4; - while (i >= end) { - *value_ptr++ = '0' + (num[i] / 100) % 10; - *value_ptr++ = '0' + (num[i] / 10) % 10; - *value_ptr++ = '0' + (num[i]) % 10; - if (i == 6) - *value_ptr++ = '.'; - i--; - } - while (value_ptr[-1] == '0') // remove trailing zeros - value_ptr--; - // remove trailing dot. - if (value_ptr[-1] == '.') - value_ptr--; - if (token) { - strcpy(value_ptr, token->ticker); // ERC-20 Token - } else { - switch (chain_id) { - case 61: - strcpy(value_ptr, " ETC"); // Ethereum Classic Mainnet - break; - case 62: - strcpy(value_ptr, " tETC"); // Ethereum Classic Testnet - break; - case 30: - strcpy(value_ptr, " RSK"); // Rootstock Mainnet - break; - case 31: - strcpy(value_ptr, " tRSK"); // Rootstock Testnet - break; - case 3: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Ropsten - break; - case 4: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Rinkeby - break; - case 42: - strcpy(value_ptr, " tETH"); // Ethereum Testnet: Kovan - break; - default: - strcpy(value_ptr, " ETH"); // Ethereum Mainnet - break; - } - } - // value is at most 16 + 4 + 1 characters long + bignum256 bn1e9; + bn_read_uint32(1000000000, &bn1e9); + const char *suffix = NULL; + int decimals = 18; + if (token != NULL) { + suffix = token->ticker; + decimals = token->decimals; + } else + if (bn_is_less(amnt, &bn1e9)) { + suffix = " Wei"; + decimals = 0; } else { - // value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik) - strlcpy(value, "gazillions of money", sizeof(value)); + switch (chain_id) { + case 61: suffix = " ETC"; break; // Ethereum Classic Mainnet + case 62: suffix = " tETC"; break; // Ethereum Classic Testnet + case 30: suffix = " RSK"; break; // Rootstock Mainnet + case 31: suffix = " tRSK"; break; // Rootstock Testnet + case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten + case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby + case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan + default: suffix = " ETH"; break; // Ethereum Mainnet + } } - - // skip leading zeroes - value_ptr = value; - while (*value_ptr == '0' && *(value_ptr + 1) >= '0' && *(value_ptr + 1) <= '9') { - value_ptr++; - } - - // copy to destination buffer - strcpy(buffer, value_ptr); + bn_format(amnt, NULL, suffix, decimals, buf, buflen); } static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token) @@ -298,15 +232,15 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui memcpy(pad_val + (32 - value_len), value, value_len); bn_read_be(pad_val, &val); - char amount[25]; + char amount[32]; if (token == NULL) { if (bn_is_zero(&val)) { strcpy(amount, "message"); } else { - ethereumFormatAmount(&val, amount, NULL); + ethereumFormatAmount(&val, NULL, amount, sizeof(amount)); } } else { - ethereumFormatAmount(&val, amount, token); + ethereumFormatAmount(&val, token, amount, sizeof(amount)); } static char _to1[17] = {0}; @@ -384,8 +318,8 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, { bignum256 val, gas; uint8_t pad_val[32]; - char tx_value[25]; - char gas_value[25]; + char tx_value[32]; + char gas_value[32]; memset(pad_val, 0, sizeof(pad_val)); memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); @@ -396,7 +330,7 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, bn_read_be(pad_val, &gas); bn_multiply(&val, &gas, &secp256k1.prime); - ethereumFormatAmount(&gas, gas_value, NULL); + ethereumFormatAmount(&gas, NULL, gas_value, sizeof(gas_value)); memset(pad_val, 0, sizeof(pad_val)); memcpy(pad_val + (32 - value_len), value, value_len); @@ -405,7 +339,7 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, if (bn_is_zero(&val)) { strcpy(tx_value, is_token ? "token" : "message"); } else { - ethereumFormatAmount(&val, tx_value, NULL); + ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value)); } layoutDialogSwipe(&bmp_icon_question, diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 5c1199e391..6c8cdcb3b5 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -21,4 +21,4 @@ for t in tokens: if symbol in subst: symbol = subst[symbol] address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() - print('\t{"%s", " %s", %d},' % (address, symbol, decimal)) + print('\t{"%s", "%s", %d},' % (address, symbol, decimal)) diff --git a/firmware/layout2.c b/firmware/layout2.c index 94f0eb5268..0611b3c471 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -29,6 +29,7 @@ #include "util.h" #include "qr_encode.h" #include "timer.h" +#include "bignum.h" void *layoutLast = layoutHome; @@ -87,42 +88,14 @@ void layoutHome(void) system_millis_lock_start = system_millis; } -const char *str_amount(uint64_t amnt, const char *abbr, char *buf, int len) -{ - memset(buf, 0, len); - uint64_t a = amnt, b = 1; - int i; - for (i = 0; i < 8; i++) { - buf[16 - i] = '0' + (a / b) % 10; - b *= 10; - } - buf[8] = '.'; - for (i = 0; i < 8; i++) { - buf[7 - i] = '0' + (a / b) % 10; - b *= 10; - } - i = 17; - while (i > 10 && buf[i - 1] == '0') { // drop trailing zeroes - i--; - } - if (abbr) { - buf[i] = ' '; - strlcpy(buf + i + 1, abbr, len - i - 1); - } else { - buf[i] = 0; - } - const char *r = buf; - while (*r == '0' && *(r + 1) != '.') r++; // drop leading zeroes - return r; -} - -static char buf_out[32], buf_fee[32]; - void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) { + char str_out[32]; + bignum256 amnt; + bn_read_uint64(out->amount, &amnt); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_out, sizeof(str_out)); static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); - const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", @@ -138,8 +111,12 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee) { - const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); - const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee)); + char str_out[32], str_fee[32]; + bignum256 amnt; + bn_read_uint64(amount_out, &amnt); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_out, sizeof(str_out)); + bn_read_uint64(amount_fee, &amnt); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", @@ -155,13 +132,16 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) { - const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out)); + char str_fee[32]; + bignum256 amnt; + bn_read_uint64(fee, &amnt); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Fee", - str_out, + str_fee, "is unexpectedly high.", NULL, "Send anyway?", diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index ea227fd805..af01ef71fc 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit ea227fd805fb97aa2fa76a89bfd05d44012d153f +Subproject commit af01ef71fc51b57e2de9436c65a235ea94b33df2 From 766a6c1189be398b984c4939c5725bc2deaf09e1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 May 2017 11:29:44 +0200 Subject: [PATCH 0445/1154] add space before coin shortcut because of how new formatter works --- firmware/coins-gen.py | 2 +- firmware/coins.c | 27 ++++++++------------------- firmware/coins.h | 1 - 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 7cb323c725..59c88a868f 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -11,7 +11,7 @@ for c in coins: '"%s"' % c['coin_name'] if c['coin_name'] is not None else 'NULL', 'true' if c['coin_shortcut'] is not None else 'false', - '"%s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', + '" %s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', 'true' if c['address_type'] is not None else 'false', '%d' % c['address_type'] if c['address_type'] is not None else '0', diff --git a/firmware/coins.c b/firmware/coins.c index 0ceaf3d499..4a2f11ae5e 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,27 +26,16 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, "BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, - {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, - {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, - {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, - {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, - {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, - {true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, - {true, "Zcash Testnet", true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, + {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, + {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, + {true, "Litecoin", true, " LTC", true, 48, true, 1000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, + {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, + {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, + {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, }; -const CoinType *coinByShortcut(const char *shortcut) -{ - if (!shortcut) return 0; - for (int i = 0; i < COINS_COUNT; i++) { - if (strcmp(shortcut, coins[i].coin_shortcut) == 0) { - return &(coins[i]); - } - } - return 0; -} - const CoinType *coinByName(const char *name) { if (!name) return 0; diff --git a/firmware/coins.h b/firmware/coins.h index 46a70a7720..1ae87eb846 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -26,7 +26,6 @@ extern const CoinType coins[COINS_COUNT]; -const CoinType *coinByShortcut(const char *shortcut); const CoinType *coinByName(const char *name); const CoinType *coinByAddressType(uint32_t address_type); bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *address_type); From d4248293335394bca097d1c0afd582359798b7dd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 May 2017 14:25:58 +0200 Subject: [PATCH 0446/1154] add chain_id to erc20 tokens --- firmware/ethereum.c | 5 +- firmware/ethereum_tokens-gen.py | 37 ++++++++------ firmware/ethereum_tokens.c | 91 +++++++++++++++++---------------- firmware/ethereum_tokens.h | 5 +- 4 files changed, 73 insertions(+), 65 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 87a2511dfc..3ebf234ec7 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -211,6 +211,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, decimals = 0; } else { switch (chain_id) { + case 1: suffix = " ETH"; break; // Ethereum Mainnet case 61: suffix = " ETC"; break; // Ethereum Classic Mainnet case 62: suffix = " tETC"; break; // Ethereum Classic Testnet case 30: suffix = " RSK"; break; // Rootstock Mainnet @@ -218,7 +219,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan - default: suffix = " ETH"; break; // Ethereum Mainnet + default: suffix = " UNKN"; break; // unknown chain } } bn_format(amnt, NULL, suffix, decimals, buf, buflen); @@ -453,7 +454,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) // detect ERC-20 token if (msg->to.size == 20 && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - token = tokenByAddress(msg->to.bytes); + token = tokenByChainAddress(chain_id, msg->to.bytes); } if (token != NULL) { diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 6c8cdcb3b5..7caacf3ef5 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -1,24 +1,29 @@ #!/usr/bin/env python3 import requests -def get_tokens(): - URL = 'https://raw.githubusercontent.com/kvhnuke/etherwallet/mercury/app/scripts/tokens/ethTokens.json' +subst = { + ( 1, 'BeerCoin \U0001F37A '): 'BEER', + ( 1, 'CryptoCarbon'): 'CCRB', + ( 1, 'DAO_extraBalance'): 'DAOe', + ( 1, 'DGX 1.0'): 'DGX1', + ( 1, 'Unicorn \U0001F984 '): 'UNCRN', +} + +def get_tokens(chain): + URL = 'https://raw.githubusercontent.com/kvhnuke/etherwallet/mercury/app/scripts/tokens/%sTokens.json' % chain r = requests.get(URL) return r.json() -tokens = get_tokens() +def print_tokens(chain, chain_id): + tokens = get_tokens(chain) -subst = { - 'BeerCoin \U0001F37A': 'BEER', - 'CryptoCarbon': 'CCRB', - 'DAO_extraBalance': 'DAOe', - 'DGX 1.0': 'DGX1', - 'Unicorn \U0001F984': 'UNCRN', -} + for t in tokens: + address, symbol, decimal = t['address'], t['symbol'], t['decimal'] + s = (chain_id, symbol) + if s in subst: + symbol = subst[s] + address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() + print('\t{%2d, "%s", " %s", %d},' % (chain_id, address, symbol, decimal)) -for t in tokens: - address, symbol, decimal = t['address'], t['symbol'], t['decimal'] - if symbol in subst: - symbol = subst[symbol] - address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() - print('\t{"%s", "%s", %d},' % (address, symbol, decimal)) +print_tokens('eth', 1) +print_tokens('etc', 61) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 85311ca321..15ae62f472 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -2,56 +2,57 @@ #include "ethereum_tokens.h" const TokenType tokens[TOKENS_COUNT] = { - {"\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, - {"\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, - {"\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, - {"\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, - {"\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, - {"\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, - {"\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, - {"\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, - {"\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, - {"\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, - {"\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, - {"\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, - {"\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, - {"\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, - {"\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, - {"\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, - {"\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, - {"\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, - {"\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, - {"\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, - {"\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, - {"\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, - {"\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, - {"\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, - {"\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, - {"\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, - {"\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, - {"\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, - {"\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, - {"\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, - {"\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " ROL", 16}, - {"\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, - {"\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, - {"\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, - {"\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, - {"\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, - {"\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, - {"\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, - {"\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, - {"\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN ", 0}, - {"\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, - {"\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, - {"\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, + { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, + { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, + { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, + { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, + { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, + { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, + { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, + { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, + { 1, "\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, + { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, + { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, + { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, + { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, + { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, + { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, + { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, + { 1, "\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, + { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, + { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, + { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, + { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, + { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, + { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, + { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, + { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, + { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, + { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, + { 1, "\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, + { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, + { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " ROL", 16}, + { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, + { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, + { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, + { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, + { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, + { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, + { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, + { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, + { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, + { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, + { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, + { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, + {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; -const TokenType *tokenByAddress(const uint8_t *address) +const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) { if (!address) return 0; for (int i = 0; i < TOKENS_COUNT; i++) { - if (memcmp(address, tokens[i].address, 20) == 0) { + if (chain_id == tokens[i].chain_id && memcmp(address, tokens[i].address, 20) == 0) { return &(tokens[i]); } } diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 3109ed98db..7e3c3efffe 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,9 +22,10 @@ #include -#define TOKENS_COUNT 43 +#define TOKENS_COUNT 44 typedef struct { + uint8_t chain_id; const char * const address; const char * const ticker; int decimals; @@ -32,6 +33,6 @@ typedef struct { extern const TokenType tokens[TOKENS_COUNT]; -const TokenType *tokenByAddress(const uint8_t *address); +const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address); #endif From 57a91c71608b51bc55bbb86666cded01c563869c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 May 2017 16:54:16 +0200 Subject: [PATCH 0447/1154] update litecoin maxfee/kb --- firmware/coins.c | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 4a2f11ae5e..5331732313 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -29,7 +29,7 @@ const CoinType coins[COINS_COUNT] = { {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, - {true, "Litecoin", true, " LTC", true, 48, true, 1000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, + {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, diff --git a/vendor/trezor-common b/vendor/trezor-common index 54000d8438..95834d75ff 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 54000d8438bedc9b762a58846a21535444f6db9d +Subproject commit 95834d75ffe28b912f5289e501cb05d333880e16 From 317363f84c9a8c05194fa1cdd4d93cb1bb9180c1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 May 2017 17:40:57 +0200 Subject: [PATCH 0448/1154] enable mixing of segwit and non-segwit inputs --- firmware/signing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index 0d2b705251..e267948317 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -755,7 +755,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { return true; } -#define ENABLE_SEGWIT_NONSEGWIT_MIXING 0 +#define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 void signing_txack(TransactionType *tx) { From 6b74139b4530a4687b4a317b8b08f4329704efc4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 May 2017 17:41:10 +0200 Subject: [PATCH 0449/1154] add 1.5.0 to changelog --- firmware/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 9627710d08..293345a0d7 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,8 @@ +Version 1.5.0 +* Stable release, optional update +* Enable Segwit for Testnet and Litecoin +* Enable ERC-20 tokens for Ethereum chains + Version 1.4.2 * Stable release, optional update * New Matrix-based recovery method From 8fa71c083736067bae7c52e70c2c9023729d6a77 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 29 May 2017 12:46:32 +0100 Subject: [PATCH 0450/1154] protob: Add messages_map.py (#167) --- firmware/messages.c | 74 +-------------------------------- firmware/protob/.gitignore | 2 + firmware/protob/Makefile | 10 ++++- firmware/protob/messages_map.h | 73 ++++++++++++++++++++++++++++++++ firmware/protob/messages_map.py | 68 ++++++++++++++++++++++++++++++ firmware/protob/types.pb.c | 26 ++++++++++++ firmware/protob/types.pb.h | 4 ++ vendor/trezor-common | 2 +- 8 files changed, 183 insertions(+), 76 deletions(-) create mode 100644 firmware/protob/messages_map.h create mode 100755 firmware/protob/messages_map.py diff --git a/firmware/messages.c b/firmware/messages.c index 9e761a326a..cf80ac7921 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -38,79 +38,7 @@ struct MessagesMap_t { }; static const struct MessagesMap_t MessagesMap[] = { - // in messages - {'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *))fsm_msgInitialize}, - {'n', 'i', MessageType_MessageType_GetFeatures, GetFeatures_fields, (void (*)(void *))fsm_msgGetFeatures}, - {'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *))fsm_msgPing}, - {'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *))fsm_msgChangePin}, - {'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *))fsm_msgWipeDevice}, - {'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *))fsm_msgGetEntropy}, - {'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *))fsm_msgGetPublicKey}, - {'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *))fsm_msgLoadDevice}, - {'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *))fsm_msgResetDevice}, - {'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *))fsm_msgSignTx}, -// {'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *))fsm_msgPinMatrixAck}, - {'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *))fsm_msgCancel}, - {'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *))fsm_msgTxAck}, - {'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *))fsm_msgCipherKeyValue}, - {'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *))fsm_msgClearSession}, - {'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *))fsm_msgApplySettings}, -// {'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *))fsm_msgButtonAck}, - {'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *))fsm_msgGetAddress}, - {'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *))fsm_msgEntropyAck}, - {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, - {'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity}, - {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, - {'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *))fsm_msgGetECDHSessionKey}, -/* ECIES disabled - {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, - {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, -*/ -// {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck}, - {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, - {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, - {'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *))fsm_msgWordAck}, - {'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *))fsm_msgSetU2FCounter}, - {'n', 'i', MessageType_MessageType_EthereumGetAddress, EthereumGetAddress_fields, (void (*)(void *))fsm_msgEthereumGetAddress}, - {'n', 'i', MessageType_MessageType_EthereumSignTx, EthereumSignTx_fields, (void (*)(void *))fsm_msgEthereumSignTx}, - {'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *))fsm_msgEthereumTxAck}, - // out messages - {'n', 'o', MessageType_MessageType_Success, Success_fields, 0}, - {'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0}, - {'n', 'o', MessageType_MessageType_Entropy, Entropy_fields, 0}, - {'n', 'o', MessageType_MessageType_PublicKey, PublicKey_fields, 0}, - {'n', 'o', MessageType_MessageType_Features, Features_fields, 0}, - {'n', 'o', MessageType_MessageType_PinMatrixRequest, PinMatrixRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_TxRequest, TxRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0}, - {'n', 'o', MessageType_MessageType_ButtonRequest, ButtonRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_Address, Address_fields, 0}, - {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, - {'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0}, - {'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0}, -/* ECIES disabled - {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, - {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, -*/ - {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, - {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, - {'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0}, - {'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0}, -#if DEBUG_LINK - // debug in messages -// {'d', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *))fsm_msgDebugLinkDecision}, - {'d', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *))fsm_msgDebugLinkGetState}, - {'d', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *))fsm_msgDebugLinkStop}, - {'d', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *))fsm_msgDebugLinkMemoryRead}, - {'d', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *))fsm_msgDebugLinkMemoryWrite}, - {'d', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *))fsm_msgDebugLinkFlashErase}, - // debug out messages - {'d', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0}, - {'d', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0}, - {'d', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0}, -#endif +#include "messages_map.h" // end {0, 0, 0, 0, 0} }; diff --git a/firmware/protob/.gitignore b/firmware/protob/.gitignore index 0a5bea8f2b..8d944df5a6 100644 --- a/firmware/protob/.gitignore +++ b/firmware/protob/.gitignore @@ -1 +1,3 @@ *.pb +*_pb2.py +__pycache__/ diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 5b8d69e038..38486526cd 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,4 +1,4 @@ -all: messages.pb.c storage.pb.c types.pb.c +all: messages.pb.c storage.pb.c types.pb.c messages_map.h %.pb.c: %.pb %.options nanopb_generator.py $< -L '#include "%s"' -T @@ -6,5 +6,11 @@ all: messages.pb.c storage.pb.c types.pb.c %.pb: %.proto protoc -I/usr/include -I. $< -o $@ +%_pb2.py: %.proto + protoc -I/usr/include -I. $< --python_out=. + +messages_map.h: messages_map.py messages_pb2.py types_pb2.py + ./$< > $@ + clean: - rm -f *.pb *.o *.pb.c *.pb.h + rm -f *.pb *.o *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h new file mode 100644 index 0000000000..8bc6ad4b58 --- /dev/null +++ b/firmware/protob/messages_map.h @@ -0,0 +1,73 @@ + // in messages + { 'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *)) fsm_msgInitialize }, + { 'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *)) fsm_msgPing }, + { 'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *)) fsm_msgChangePin }, + { 'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *)) fsm_msgWipeDevice }, +// { 'n', 'i', MessageType_MessageType_FirmwareErase, FirmwareErase_fields, (void (*)(void *)) fsm_msgFirmwareErase }, // BOOTLOADER +// { 'n', 'i', MessageType_MessageType_FirmwareUpload, FirmwareUpload_fields, (void (*)(void *)) fsm_msgFirmwareUpload }, // BOOTLOADER + { 'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *)) fsm_msgGetEntropy }, + { 'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *)) fsm_msgGetPublicKey }, + { 'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *)) fsm_msgLoadDevice }, + { 'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *)) fsm_msgResetDevice }, + { 'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *)) fsm_msgSignTx }, +// { 'n', 'i', MessageType_MessageType_SimpleSignTx, SimpleSignTx_fields, (void (*)(void *)) fsm_msgSimpleSignTx }, // DEPRECATED +// { 'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *)) fsm_msgPinMatrixAck }, + { 'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *)) fsm_msgCancel }, + { 'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *)) fsm_msgTxAck }, + { 'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *)) fsm_msgCipherKeyValue }, + { 'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *)) fsm_msgClearSession }, + { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, +// { 'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *)) fsm_msgButtonAck }, + { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, + { 'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *)) fsm_msgEntropyAck }, + { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, + { 'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *)) fsm_msgVerifyMessage }, +// { 'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *)) fsm_msgPassphraseAck }, + { 'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *)) fsm_msgEstimateTxSize }, + { 'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *)) fsm_msgRecoveryDevice }, + { 'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *)) fsm_msgWordAck }, +// { 'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *)) fsm_msgEncryptMessage }, // DEPRECATED +// { 'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *)) fsm_msgDecryptMessage }, // DEPRECATED + { 'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *)) fsm_msgSignIdentity }, + { 'n', 'i', MessageType_MessageType_GetFeatures, GetFeatures_fields, (void (*)(void *)) fsm_msgGetFeatures }, + { 'n', 'i', MessageType_MessageType_EthereumGetAddress, EthereumGetAddress_fields, (void (*)(void *)) fsm_msgEthereumGetAddress }, + { 'n', 'i', MessageType_MessageType_EthereumSignTx, EthereumSignTx_fields, (void (*)(void *)) fsm_msgEthereumSignTx }, + { 'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *)) fsm_msgEthereumTxAck }, + { 'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *)) fsm_msgGetECDHSessionKey }, + { 'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *)) fsm_msgSetU2FCounter }, + // out messages + { 'n', 'o', MessageType_MessageType_Success, Success_fields, 0 }, + { 'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0 }, +// { 'n', 'o', MessageType_MessageType_FirmwareRequest, FirmwareRequest_fields, 0 }, // BOOTLOADER + { 'n', 'o', MessageType_MessageType_Entropy, Entropy_fields, 0 }, + { 'n', 'o', MessageType_MessageType_PublicKey, PublicKey_fields, 0 }, + { 'n', 'o', MessageType_MessageType_Features, Features_fields, 0 }, + { 'n', 'o', MessageType_MessageType_PinMatrixRequest, PinMatrixRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_TxRequest, TxRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_ButtonRequest, ButtonRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_Address, Address_fields, 0 }, + { 'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0 }, + { 'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0 }, + { 'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0 }, +// { 'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0 }, // DEPRECATED +// { 'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0 }, // DEPRECATED + { 'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0 }, + { 'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0 }, + { 'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0 }, + { 'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0 }, +#if DEBUG_LINK + // debug in messages +// { 'd', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *)) fsm_msgDebugLinkDecision }, + { 'd', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *)) fsm_msgDebugLinkGetState }, + { 'd', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *)) fsm_msgDebugLinkStop }, + { 'd', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryRead }, + { 'd', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryWrite }, + { 'd', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *)) fsm_msgDebugLinkFlashErase }, + // debug out messages + { 'd', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0 }, + { 'd', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0 }, + { 'd', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0 }, +#endif diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py new file mode 100755 index 0000000000..6cf6c04fae --- /dev/null +++ b/firmware/protob/messages_map.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +from collections import defaultdict +from messages_pb2 import MessageType +from types_pb2 import wire_in, wire_out, wire_debug_in, wire_debug_out, wire_tiny, wire_bootloader + +# len("MessageType_MessageType_") - len("_fields") == 17 +TEMPLATE = "\t{{ {type} {dir} {msg_id:46} {fields:29} {process_func} }}," + +LABELS = { + wire_in: "in messages", + wire_out: "out messages", + wire_debug_in: "debug in messages", + wire_debug_out: "debug out messages", +} + +def handle_message(message, extension): + name = message.name + short_name = name.split("MessageType_", 1).pop() + assert(short_name != name) + + interface = "d" if extension in (wire_debug_in, wire_debug_out) else "n" + direction = "i" if extension in (wire_in, wire_debug_in) else "o" + + options = message.GetOptions() + bootloader = options.Extensions[wire_bootloader] + tiny = options.Extensions[wire_tiny] and direction == "i" + + if options.deprecated or bootloader or tiny: + line = "// " + else: + line = "" + + line += TEMPLATE.format( + type="'%c'," % interface, + dir="'%c'," % direction, + msg_id="MessageType_%s," % name, + fields="%s_fields," % short_name, + process_func = "(void (*)(void *)) fsm_msg%s" % short_name if direction == "i" else "0" + ) + + if options.deprecated: + line += " // DEPRECATED" + elif bootloader: + line += " // BOOTLOADER" + + return line + +messages = defaultdict(list) + +for message in MessageType.DESCRIPTOR.values: + extensions = message.GetOptions().Extensions + + for extension in (wire_in, wire_out, wire_debug_in, wire_debug_out): + if extensions[extension]: + messages[extension].append(message) + +for extension in (wire_in, wire_out, wire_debug_in, wire_debug_out): + if extension == wire_debug_in: + print("#if DEBUG_LINK") + + print("\t// {label}".format(label=LABELS[extension])) + + for message in messages[extension]: + print(handle_message(message, extension)) + + if extension == wire_debug_out: + print("#endif") + diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index dfc9a49084..c35f3d10d8 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -166,6 +166,32 @@ const pb_extension_type_t wire_debug_out = { &wire_debug_out_field }; +typedef struct { + bool wire_tiny; +} wire_tiny_struct; + +static const pb_field_t wire_tiny_field = + PB_FIELD2(50006, BOOL , OPTEXT, STATIC , FIRST, wire_tiny_struct, wire_tiny, wire_tiny, 0); + +const pb_extension_type_t wire_tiny = { + NULL, + NULL, + &wire_tiny_field +}; + +typedef struct { + bool wire_bootloader; +} wire_bootloader_struct; + +static const pb_field_t wire_bootloader_field = + PB_FIELD2(50007, BOOL , OPTEXT, STATIC , FIRST, wire_bootloader_struct, wire_bootloader, wire_bootloader, 0); + +const pb_extension_type_t wire_bootloader = { + NULL, + NULL, + &wire_bootloader_field +}; + /* Check that field information fits in pb_field_t */ #if !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 892b0df88d..4e25d7de28 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -284,6 +284,8 @@ extern const pb_extension_type_t wire_in; extern const pb_extension_type_t wire_out; extern const pb_extension_type_t wire_debug_in; extern const pb_extension_type_t wire_debug_out; +extern const pb_extension_type_t wire_tiny; +extern const pb_extension_type_t wire_bootloader; /* Default values for struct fields */ extern const uint32_t CoinType_address_type_default; @@ -381,6 +383,8 @@ extern const uint32_t IdentityType_index_default; #define wire_out_tag 50003 #define wire_debug_in_tag 50004 #define wire_debug_out_tag 50005 +#define wire_tiny_tag 50006 +#define wire_bootloader_tag 50007 /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; diff --git a/vendor/trezor-common b/vendor/trezor-common index 95834d75ff..4fd03dcc95 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 95834d75ffe28b912f5289e501cb05d333880e16 +Subproject commit 4fd03dcc955cbcd28a70a81dbcc0d597bad9dac4 From 34c0b93d549b634b3e3cd4126a1229621bad19a8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 29 May 2017 14:17:12 +0200 Subject: [PATCH 0451/1154] protob: update messages_map.py script --- firmware/protob/messages_map.h | 35 ++++++++++++++++++++++----------- firmware/protob/messages_map.py | 26 +++++++++++------------- vendor/trezor-common | 2 +- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index 8bc6ad4b58..120b965c94 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -1,33 +1,36 @@ + // This file is automatically generated by messages_map.py -- DO NOT EDIT! + // in messages + { 'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *)) fsm_msgInitialize }, { 'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *)) fsm_msgPing }, { 'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *)) fsm_msgChangePin }, { 'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *)) fsm_msgWipeDevice }, -// { 'n', 'i', MessageType_MessageType_FirmwareErase, FirmwareErase_fields, (void (*)(void *)) fsm_msgFirmwareErase }, // BOOTLOADER -// { 'n', 'i', MessageType_MessageType_FirmwareUpload, FirmwareUpload_fields, (void (*)(void *)) fsm_msgFirmwareUpload }, // BOOTLOADER + // Message FirmwareErase is used in bootloader mode only + // Message FirmwareUpload is used in bootloader mode only { 'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *)) fsm_msgGetEntropy }, { 'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *)) fsm_msgGetPublicKey }, { 'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *)) fsm_msgLoadDevice }, { 'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *)) fsm_msgResetDevice }, { 'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *)) fsm_msgSignTx }, -// { 'n', 'i', MessageType_MessageType_SimpleSignTx, SimpleSignTx_fields, (void (*)(void *)) fsm_msgSimpleSignTx }, // DEPRECATED -// { 'n', 'i', MessageType_MessageType_PinMatrixAck, PinMatrixAck_fields, (void (*)(void *)) fsm_msgPinMatrixAck }, + // Message SimpleSignTx is deprecated + // Message PinMatrixAck is used in tiny mode { 'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *)) fsm_msgCancel }, { 'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *)) fsm_msgTxAck }, { 'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *)) fsm_msgCipherKeyValue }, { 'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *)) fsm_msgClearSession }, { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, -// { 'n', 'i', MessageType_MessageType_ButtonAck, ButtonAck_fields, (void (*)(void *)) fsm_msgButtonAck }, + // Message ButtonAck is used in tiny mode { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, { 'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *)) fsm_msgEntropyAck }, { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, { 'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *)) fsm_msgVerifyMessage }, -// { 'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *)) fsm_msgPassphraseAck }, + // Message PassphraseAck is used in tiny mode { 'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *)) fsm_msgEstimateTxSize }, { 'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *)) fsm_msgRecoveryDevice }, { 'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *)) fsm_msgWordAck }, -// { 'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *)) fsm_msgEncryptMessage }, // DEPRECATED -// { 'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *)) fsm_msgDecryptMessage }, // DEPRECATED + // Message EncryptMessage is deprecated + // Message DecryptMessage is deprecated { 'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *)) fsm_msgSignIdentity }, { 'n', 'i', MessageType_MessageType_GetFeatures, GetFeatures_fields, (void (*)(void *)) fsm_msgGetFeatures }, { 'n', 'i', MessageType_MessageType_EthereumGetAddress, EthereumGetAddress_fields, (void (*)(void *)) fsm_msgEthereumGetAddress }, @@ -35,10 +38,12 @@ { 'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *)) fsm_msgEthereumTxAck }, { 'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *)) fsm_msgGetECDHSessionKey }, { 'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *)) fsm_msgSetU2FCounter }, + // out messages + { 'n', 'o', MessageType_MessageType_Success, Success_fields, 0 }, { 'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0 }, -// { 'n', 'o', MessageType_MessageType_FirmwareRequest, FirmwareRequest_fields, 0 }, // BOOTLOADER + // Message FirmwareRequest is used in bootloader mode only { 'n', 'o', MessageType_MessageType_Entropy, Entropy_fields, 0 }, { 'n', 'o', MessageType_MessageType_PublicKey, PublicKey_fields, 0 }, { 'n', 'o', MessageType_MessageType_Features, Features_fields, 0 }, @@ -52,22 +57,28 @@ { 'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0 }, { 'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0 }, { 'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0 }, -// { 'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0 }, // DEPRECATED -// { 'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0 }, // DEPRECATED + // Message EncryptedMessage is deprecated + // Message DecryptedMessage is deprecated { 'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0 }, { 'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0 }, { 'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0 }, { 'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0 }, + #if DEBUG_LINK + // debug in messages -// { 'd', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *)) fsm_msgDebugLinkDecision }, + + // Message DebugLinkDecision is used in tiny mode { 'd', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *)) fsm_msgDebugLinkGetState }, { 'd', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *)) fsm_msgDebugLinkStop }, { 'd', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryRead }, { 'd', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryWrite }, { 'd', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *)) fsm_msgDebugLinkFlashErase }, + // debug out messages + { 'd', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0 }, { 'd', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0 }, { 'd', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0 }, + #endif diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index 6cf6c04fae..f727c1a70a 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -25,12 +25,14 @@ def handle_message(message, extension): bootloader = options.Extensions[wire_bootloader] tiny = options.Extensions[wire_tiny] and direction == "i" - if options.deprecated or bootloader or tiny: - line = "// " - else: - line = "" + if options.deprecated: + return '\t// Message %s is deprecated' % short_name + if bootloader: + return '\t// Message %s is used in bootloader mode only' % short_name + if tiny: + return '\t// Message %s is used in tiny mode' % short_name - line += TEMPLATE.format( + return TEMPLATE.format( type="'%c'," % interface, dir="'%c'," % direction, msg_id="MessageType_%s," % name, @@ -38,12 +40,7 @@ def handle_message(message, extension): process_func = "(void (*)(void *)) fsm_msg%s" % short_name if direction == "i" else "0" ) - if options.deprecated: - line += " // DEPRECATED" - elif bootloader: - line += " // BOOTLOADER" - - return line +print('\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!') messages = defaultdict(list) @@ -56,13 +53,12 @@ for message in MessageType.DESCRIPTOR.values: for extension in (wire_in, wire_out, wire_debug_in, wire_debug_out): if extension == wire_debug_in: - print("#if DEBUG_LINK") + print("\n#if DEBUG_LINK") - print("\t// {label}".format(label=LABELS[extension])) + print("\n\t// {label}\n".format(label=LABELS[extension])) for message in messages[extension]: print(handle_message(message, extension)) if extension == wire_debug_out: - print("#endif") - + print("\n#endif") diff --git a/vendor/trezor-common b/vendor/trezor-common index 4fd03dcc95..e732226909 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 4fd03dcc955cbcd28a70a81dbcc0d597bad9dac4 +Subproject commit e7322269092e0253b0cb1a9c18ba84fd5cd75f91 From da17f2472b813798bfcdadd913259f33a663fe6d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 8 Jun 2017 22:51:17 +0200 Subject: [PATCH 0452/1154] ethereum: add more tokens from MEW --- firmware/ethereum_tokens.c | 7 +++++++ firmware/ethereum_tokens.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 15ae62f472..706cc2507c 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -5,6 +5,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, + { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, @@ -24,16 +25,21 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, + { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, + { 1, "\xb0\x4c\xfa\x8a\x26\xd6\x02\xfb\x50\x23\x2c\xee\x0d\xaf\x29\x06\x02\x64\xe0\x4b", " MCO", 8}, + { 1, "\xd0\xb1\x71\xeb\x0b\x0f\x2c\xbd\x35\xcc\xd9\x7c\xdc\x5e\xdc\x3f\xfe\x48\x71\xaa", " MDA", 18}, { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, + { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, { 1, "\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " ROL", 16}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, + { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, @@ -43,6 +49,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, + { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 7e3c3efffe..a16d64bd3a 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 44 +#define TOKENS_COUNT 51 typedef struct { uint8_t chain_id; From 5cac99fdf460b7a8ae52fce7312b4ade91630016 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Jun 2017 14:42:11 +0200 Subject: [PATCH 0453/1154] update travis notification url --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a7d42fcd2..1d3ba2a931 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,7 @@ script: notifications: webhooks: urls: - - http://sway.gk2.sk:5000/travis - - http://163.172.132.178:5000/travis + - http://ci-bot.satoshilabs.com:5000/travis on_success: always on_failure: always on_start: always From 09917920ba313da4dcdc7c64d47b014440bf822d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 12 Jun 2017 17:33:09 +0100 Subject: [PATCH 0454/1154] transaction: Fix buffer overflow --- firmware/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index 70954e0f3c..bb699b052b 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -64,7 +64,7 @@ bool compute_address(const CoinType *coin, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]) { - uint8_t raw[32]; + uint8_t raw[34]; uint8_t digest[MAX_ADDR_RAW_SIZE]; size_t prelen; From 77c4e7b167c01dce1c71c1f1b1b6bdf1779a15c6 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 12 Jun 2017 17:35:27 +0100 Subject: [PATCH 0455/1154] vendor: Update trezor-crypto for GCC 7.1.1 --- firmware/Makefile | 3 +++ vendor/trezor-crypto | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 8833df3842..7c41c34b45 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -29,10 +29,13 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-sha3.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-keccak.o OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o OBJS += ../vendor/trezor-crypto/pbkdf2.o +OBJS += ../vendor/trezor-crypto/base32.o OBJS += ../vendor/trezor-crypto/base58.o OBJS += ../vendor/trezor-crypto/ripemd160.o diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index af01ef71fc..ba206056e7 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit af01ef71fc51b57e2de9436c65a235ea94b33df2 +Subproject commit ba206056e73cb1972b7ecb6ad7939254cb51074f From 00f6312a81c5856796857a23ec3e65399b8b25cc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 18 Jun 2017 21:10:12 +0200 Subject: [PATCH 0456/1154] rename failures, unify strings where possible --- firmware/ethereum.c | 24 ++++++------ firmware/fsm.c | 74 ++++++++++++++++++------------------- firmware/messages.c | 6 +-- firmware/protect.c | 6 +-- firmware/protob/types.pb.h | 4 +- firmware/recovery.c | 8 ++-- firmware/reset.c | 6 +-- firmware/signing.c | 76 +++++++++++++++++++------------------- vendor/trezor-common | 2 +- 9 files changed, 103 insertions(+), 103 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 3ebf234ec7..9715de9ceb 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -163,7 +163,7 @@ static void send_signature(void) keccak_Final(&keccak_ctx, hash); if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); ethereum_signing_abort(); return; } @@ -409,7 +409,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { if (msg->chain_id < 1 || msg->chain_id > 109) { - fsm_sendFailure(FailureType_Failure_Other, "Chain Id out of bounds"); + fsm_sendFailure(FailureType_Failure_DataError, "Chain Id out of bounds"); ethereum_signing_abort(); return; } @@ -420,7 +420,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk"); + fsm_sendFailure(FailureType_Failure_DataError, "Data length provided, but no initial chunk"); ethereum_signing_abort(); return; } @@ -428,7 +428,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) * prevent exceeding the limit we use a stricter limit on data length. */ if (msg->data_length > 16000000) { - fsm_sendFailure(FailureType_Failure_Other, "Data length exceeds limit"); + fsm_sendFailure(FailureType_Failure_DataError, "Data length exceeds limit"); ethereum_signing_abort(); return; } @@ -437,14 +437,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) data_total = 0; } if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid size of initial chunk"); ethereum_signing_abort(); return; } // safety checks if (!ethereum_signing_check(msg)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing aborted (safety check failed)"); + fsm_sendFailure(FailureType_Failure_DataError, "Safety check failed"); ethereum_signing_abort(); return; } @@ -464,7 +464,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); ethereum_signing_abort(); return; } @@ -472,7 +472,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (token == NULL && data_total > 0) { layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); ethereum_signing_abort(); return; } @@ -482,7 +482,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->gas_price.bytes, msg->gas_price.size, msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); ethereum_signing_abort(); return; } @@ -530,19 +530,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { if (!ethereum_signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Ethereum signing mode"); layoutHome(); return; } if (tx->data_chunk.size > data_left) { - fsm_sendFailure(FailureType_Failure_Other, "Too much data"); + fsm_sendFailure(FailureType_Failure_DataError, "Too much data"); ethereum_signing_abort(); return; } if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(FailureType_Failure_Other, "Empty data chunk received"); + fsm_sendFailure(FailureType_Failure_DataError, "Empty data chunk received"); ethereum_signing_abort(); return; } diff --git a/firmware/fsm.c b/firmware/fsm.c index 70cfaf08f2..cb2c7d1782 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -86,7 +86,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_PARAM(cond, errormsg) \ if (!(cond)) { \ - fsm_sendFailure(FailureType_Failure_SyntaxError, (errormsg)); \ + fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ layoutHome(); \ return; \ } @@ -127,7 +127,7 @@ const CoinType *fsm_getCoin(bool has_name, const char *name) coin = coinByName("Bitcoin"); } if (!coin) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid coin name"); layoutHome(); return 0; } @@ -146,7 +146,7 @@ HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t addres return &node; } if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to derive private key"); layoutHome(); return 0; } @@ -203,7 +203,7 @@ void fsm_msgPing(Ping *msg) if (msg->has_button_protection && msg->button_protection) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -215,7 +215,7 @@ void fsm_msgPing(Ping *msg) if (msg->has_passphrase_protection && msg->passphrase_protection) { if (!protectPassphrase()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); return; } } @@ -246,7 +246,7 @@ void fsm_msgChangePin(ChangePin *msg) } } if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, removal ? "PIN removal cancelled" : "PIN change cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -260,7 +260,7 @@ void fsm_msgChangePin(ChangePin *msg) if (protectChangePin()) { fsm_sendSuccess("PIN changed"); } else { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); } } layoutHome(); @@ -271,7 +271,7 @@ void fsm_msgWipeDevice(WipeDevice *msg) (void)msg; layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -289,7 +289,7 @@ void fsm_msgGetEntropy(GetEntropy *msg) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -338,7 +338,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show public key cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -369,14 +369,14 @@ void fsm_msgLoadDevice(LoadDevice *msg) layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Mnemonic with wrong checksum provided"); + fsm_sendFailure(FailureType_Failure_DataError, "Mnemonic with wrong checksum provided"); layoutHome(); return; } @@ -435,7 +435,7 @@ void fsm_msgCancel(Cancel *msg) recovery_abort(); signing_abort(); ethereum_signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); } void fsm_msgEthereumSignTx(EthereumSignTx *msg) @@ -474,7 +474,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { layoutCipherKeyValue(encrypt, msg->key); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "CipherKeyValue cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -520,7 +520,7 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -528,7 +528,7 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_language) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -536,7 +536,7 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_use_passphrase) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -544,7 +544,7 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_homescreen) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -583,7 +583,7 @@ void fsm_msgGetAddress(GetAddress *msg) layoutProgress("Computing address", 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Can't encode address"); + fsm_sendFailure(FailureType_Failure_DataError, "Can't encode address"); } if (msg->has_show_display && msg->show_display) { @@ -601,7 +601,7 @@ void fsm_msgGetAddress(GetAddress *msg) } layoutAddress(resp->address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -636,7 +636,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) layoutAddress(address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -663,7 +663,7 @@ void fsm_msgSignMessage(SignMessage *msg) layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -683,7 +683,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { - fsm_sendFailure(FailureType_Failure_Other, "Error signing message"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Error signing message"); } layoutHome(); } @@ -698,26 +698,26 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint32_t address_type; if (!coinExtractAddressType(coin, msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { - fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid address"); return; } layoutProgressSwipe("Verifying", 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } fsm_sendSuccess("Message verified"); } else { - fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid signature"); } layoutHome(); } @@ -730,7 +730,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -739,7 +739,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid identity"); layoutHome(); return; } @@ -793,7 +793,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); } else { - fsm_sendFailure(FailureType_Failure_Other, "Error signing identity"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Error signing identity"); } layoutHome(); } @@ -806,7 +806,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) layoutDecryptIdentity(&msg->identity); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "ECDH Session cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -815,7 +815,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid identity"); layoutHome(); return; } @@ -841,7 +841,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) resp->session_key.size = result_size; msg_write(MessageType_MessageType_ECDHSessionKey, resp); } else { - fsm_sendFailure(FailureType_Failure_Other, "Error getting ECDH session key"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Error getting ECDH session key"); } layoutHome(); } @@ -874,13 +874,13 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Encrypt message cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } layoutProgressSwipe("Encrypting", 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error encrypting message"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Error encrypting message"); layoutHome(); return; } @@ -914,7 +914,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) bool signing = false; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -972,7 +972,7 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg) { layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you want to set", "the U2F counter?", NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "SetU2FCounter cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } diff --git a/firmware/messages.c b/firmware/messages.c index cf80ac7921..dcdee40f56 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -230,7 +230,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * if (status) { MessageProcessFunc(type, 'i', msg_id, msg_data); } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, stream.errmsg); + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); } } @@ -258,7 +258,7 @@ void msg_read_common(char type, const uint8_t *buf, int len) return; } if (msg_size > MSG_IN_SIZE) { // message is too big :( - fsm_sendFailure(FailureType_Failure_SyntaxError, "Message too big"); + fsm_sendFailure(FailureType_Failure_DataError, "Message too big"); return; } @@ -353,7 +353,7 @@ void msg_read_tiny(const uint8_t *buf, int len) if (status) { msg_tiny_id = msg_id; } else { - fsm_sendFailure(FailureType_Failure_SyntaxError, stream.errmsg); + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); msg_tiny_id = 0xFFFF; } } else { diff --git a/firmware/protect.c b/firmware/protect.c index 8ba3298c56..d47e58133a 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -170,7 +170,7 @@ bool protectPin(bool use_cached) protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN cancelled"); return false; } wait--; @@ -179,7 +179,7 @@ bool protectPin(bool use_cached) const char *pin; pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); + fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN cancelled"); return false; } if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) { @@ -187,7 +187,7 @@ bool protectPin(bool use_cached) storage_resetPinFails(fails); return true; } else { - fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); + fsm_sendFailure(FailureType_Failure_PinInvalid, "PIN invalid"); return false; } } diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 4e25d7de28..8ddbee4ffe 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -12,13 +12,13 @@ extern "C" { typedef enum _FailureType { FailureType_Failure_UnexpectedMessage = 1, FailureType_Failure_ButtonExpected = 2, - FailureType_Failure_SyntaxError = 3, + FailureType_Failure_DataError = 3, FailureType_Failure_ActionCancelled = 4, FailureType_Failure_PinExpected = 5, FailureType_Failure_PinCancelled = 6, FailureType_Failure_PinInvalid = 7, FailureType_Failure_InvalidSignature = 8, - FailureType_Failure_Other = 9, + FailureType_Failure_ProcessError = 9, FailureType_Failure_NotEnoughFunds = 10, FailureType_Failure_NotInitialized = 11, FailureType_Failure_FirmwareError = 99 diff --git a/firmware/recovery.c b/firmware/recovery.c index 41083dd23e..a12328c965 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -141,7 +141,7 @@ static void recovery_done(void) { fsm_sendSuccess("Device recovered"); } else { storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid mnemonic, are words in correct order?"); + fsm_sendFailure(FailureType_Failure_DataError, "Invalid mnemonic, are words in correct order?"); } awaiting_word = 0; layoutHome(); @@ -376,7 +376,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr enforce_wordlist = _enforce_wordlist; if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -411,7 +411,7 @@ static void recovery_scrambledword(const char *word) if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Wrong word retyped"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Wrong word retyped"); layoutHome(); return; } @@ -428,7 +428,7 @@ static void recovery_scrambledword(const char *word) } if (!found) { storage_reset(); - fsm_sendFailure(FailureType_Failure_SyntaxError, "Word not found in a wordlist"); + fsm_sendFailure(FailureType_Failure_DataError, "Word not found in a wordlist"); layoutHome(); return; } diff --git a/firmware/reset.c b/firmware/reset.c index 49db53a719..f10ecd234f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -50,14 +50,14 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect if (display_random) { layoutDialogSwipe(&bmp_icon_info, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } } if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "PIN change failed"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); layoutHome(); return; } @@ -140,7 +140,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { storage_reset(); layoutHome(); - fsm_sendFailure(FailureType_Failure_Other, "Reset device aborted"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); return; } } diff --git a/firmware/signing.c b/firmware/signing.c index e267948317..5501b41581 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -455,7 +455,7 @@ static bool signing_check_input(TxInputType *txinput) { && txinput->script_type == InputScriptType_SPENDMULTISIG) { uint8_t h[32]; if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Error computing multisig fingerprint"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Error computing multisig fingerprint"); signing_abort(); return false; } @@ -487,7 +487,7 @@ static bool signing_check_prevtx_hash(void) { uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); + fsm_sendFailure(FailureType_Failure_DataError, "Encountered invalid prevhash"); signing_abort(); return false; } @@ -504,7 +504,7 @@ static bool signing_check_output(TxOutputType *txoutput) { bool is_change = false; if (txoutput->address_n_count > 0) { if (txoutput->has_address) { - fsm_sendFailure(FailureType_Failure_Other, "Address in change output"); + fsm_sendFailure(FailureType_Failure_DataError, "Address in change output"); signing_abort(); return false; } @@ -528,14 +528,14 @@ static bool signing_check_output(TxOutputType *txoutput) { if (change_spend == 0) { // not set change_spend = txoutput->amount; } else { - fsm_sendFailure(FailureType_Failure_Other, "Only one change output allowed"); + fsm_sendFailure(FailureType_Failure_DataError, "Only one change output allowed"); signing_abort(); return false; } } if (spending + txoutput->amount < spending) { - fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); signing_abort(); return false; } @@ -545,11 +545,11 @@ static bool signing_check_output(TxOutputType *txoutput) { layoutProgress("Signing transaction", progress); } if (co < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); signing_abort(); return false; } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); signing_abort(); return false; } @@ -570,7 +570,7 @@ static bool signing_check_fee(void) { if (fee > tx_est_size_kb * coin->maxfee_kb) { layoutFeeOverThreshold(coin, fee); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Fee over threshold. Signing cancelled."); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); signing_abort(); return false; } @@ -579,7 +579,7 @@ static bool signing_check_fee(void) { // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); signing_abort(); return false; } @@ -609,7 +609,7 @@ static bool signing_sign_input(void) { sha256_Final(&hashers[0], hash); sha256_Raw(hash, 32, hash); if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); signing_abort(); return false; } @@ -620,7 +620,7 @@ static bool signing_sign_input(void) { resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); signing_abort(); return false; } @@ -630,7 +630,7 @@ static bool signing_sign_input(void) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + fsm_sendFailure(FailureType_Failure_DataError, "Pubkey not found in multisig script"); signing_abort(); return false; } @@ -638,7 +638,7 @@ static bool signing_sign_input(void) { input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); if (input.script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize multisig script"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize multisig script"); signing_abort(); return false; } @@ -658,17 +658,17 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { // disable native segwit for now if (txinput->script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_Other, "Native segwit is disabled"); + fsm_sendFailure(FailureType_Failure_DataError, "Native segwit is disabled"); signing_abort(); return false; } if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); signing_abort(); return false; } if (txinput->amount > segwit_to_spend) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); signing_abort(); return false; } @@ -694,7 +694,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); signing_abort(); return false; } @@ -706,7 +706,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), node.public_key); if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); + fsm_sendFailure(FailureType_Failure_DataError, "Pubkey not found in multisig script"); signing_abort(); return false; } @@ -786,7 +786,7 @@ void signing_txack(TransactionType *tx) #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(FailureType_Failure_Other, "Mixing segwit and non-segwit inputs is not allowed"); + fsm_sendFailure(FailureType_Failure_DataError, "Mixing segwit and non-segwit inputs is not allowed"); signing_abort(); return; } @@ -795,23 +795,23 @@ void signing_txack(TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (!coin->has_segwit || !coin->segwit) { - fsm_sendFailure(FailureType_Failure_Other, "Segwit not enabled on this coin"); + fsm_sendFailure(FailureType_Failure_DataError, "Segwit not enabled on this coin"); signing_abort(); return; } // disable native segwit for now if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_Other, "Native segwit is disabled"); + fsm_sendFailure(FailureType_Failure_DataError, "Native segwit is disabled"); signing_abort(); return; } if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_Other, "Segwit input without amount"); + fsm_sendFailure(FailureType_Failure_DataError, "Segwit input without amount"); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); signing_abort(); return; } @@ -820,7 +820,7 @@ void signing_txack(TransactionType *tx) if (idx1 == 0) { to.is_segwit = true; } else if (to.is_segwit == false) { - fsm_sendFailure(FailureType_Failure_Other, "Mixing segwit and non-segwit inputs is not allowed"); + fsm_sendFailure(FailureType_Failure_DataError, "Mixing segwit and non-segwit inputs is not allowed"); signing_abort(); return; } @@ -831,7 +831,7 @@ void signing_txack(TransactionType *tx) segwit_to_spend += tx->inputs[0].amount; phase1_request_next_input(); } else { - fsm_sendFailure(FailureType_Failure_Other, "Wrong input script type"); + fsm_sendFailure(FailureType_Failure_DataError, "Wrong input script type"); signing_abort(); return; } @@ -850,7 +850,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_INPUT: progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize input"); signing_abort(); return; } @@ -865,13 +865,13 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_OUTPUT: progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize output"); signing_abort(); return; } if (idx2 == input.prev_index) { if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_Other, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); signing_abort(); return; } @@ -891,7 +891,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_2_PREV_EXTRADATA: if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize extra data"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize extra data"); signing_abort(); return; } @@ -918,7 +918,7 @@ void signing_txack(TransactionType *tx) sha256_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); signing_abort(); return; } @@ -934,7 +934,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.size = 0; } if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize input"); signing_abort(); return; } @@ -945,7 +945,7 @@ void signing_txack(TransactionType *tx) uint8_t hash[32]; sha256_Final(&hashers[0], hash); if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); signing_abort(); return; } @@ -957,14 +957,14 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_OUTPUT: progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); signing_abort(); return; } // check hashOutputs tx_output_hash(&hashers[0], &bin_output); if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize output"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize output"); signing_abort(); return; } @@ -998,7 +998,7 @@ void signing_txack(TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); signing_abort(); return; } @@ -1017,7 +1017,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); signing_abort(); return; } @@ -1038,7 +1038,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_5_OUTPUT: if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { - fsm_sendFailure(FailureType_Failure_Other, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); signing_abort(); return; } @@ -1075,7 +1075,7 @@ void signing_txack(TransactionType *tx) return; } - fsm_sendFailure(FailureType_Failure_Other, "Signing error"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Signing error"); signing_abort(); } diff --git a/vendor/trezor-common b/vendor/trezor-common index e732226909..4eef33b05a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit e7322269092e0253b0cb1a9c18ba84fd5cd75f91 +Subproject commit 4eef33b05afb5e8465c8947272bc5421b1b6d896 From c6fd70b471d062c0b0979098b89cacd573fec17b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 18 Jun 2017 22:22:33 +0200 Subject: [PATCH 0457/1154] gettext: mark localizable strings as proof-of-concept --- firmware/ethereum.c | 63 ++++++------- firmware/fsm.c | 215 ++++++++++++++++++++++++++------------------ firmware/gettext.h | 25 ++++++ firmware/layout2.c | 87 +++++++++--------- firmware/messages.c | 7 +- firmware/protect.c | 19 ++-- firmware/recovery.c | 19 ++-- firmware/reset.c | 21 ++--- firmware/signing.c | 95 ++++++++++---------- firmware/storage.c | 5 +- firmware/u2f.c | 8 +- 11 files changed, 319 insertions(+), 245 deletions(-) create mode 100644 firmware/gettext.h diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 9715de9ceb..7db5352727 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -30,6 +30,7 @@ #include "secp256k1.h" #include "sha3.h" #include "util.h" +#include "gettext.h" #include "ethereum_tokens.h" static bool ethereum_signing = false; @@ -135,7 +136,7 @@ static void send_request_chunk(void) int progress = 1000 - (data_total > 1000000 ? data_left / (data_total/800) : data_left * 800 / data_total); - layoutProgress("Signing", progress); + layoutProgress(_("Signing"), progress); resp.has_data_length = true; resp.data_length = data_left <= 1024 ? data_left : 1024; msg_write(MessageType_MessageType_EthereumTxRequest, &resp); @@ -151,7 +152,7 @@ static void send_signature(void) { uint8_t hash[32], sig[64]; uint8_t v; - layoutProgress("Signing", 1000); + layoutProgress(_("Signing"), 1000); /* eip-155 replay protection */ if (chain_id != 0) { @@ -163,7 +164,7 @@ static void send_signature(void) keccak_Final(&keccak_ctx, hash); if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); ethereum_signing_abort(); return; } @@ -236,7 +237,7 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui char amount[32]; if (token == NULL) { if (bn_is_zero(&val)) { - strcpy(amount, "message"); + strcpy(amount, _("message")); } else { ethereumFormatAmount(&val, NULL, amount, sizeof(amount)); } @@ -249,22 +250,22 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui static char _to3[17] = {0}; if (to_len) { - strcpy(_to1, "to "); + strcpy(_to1, _("to ")); data2hex(to, 6, _to1 + 3); data2hex(to + 6, 7, _to2); data2hex(to + 13, 7, _to3); _to3[14] = '?'; _to3[15] = 0; } else { - strlcpy(_to1, "to new contract?", sizeof(_to1)); + strlcpy(_to1, _("to new contract?"), sizeof(_to1)); strlcpy(_to2, "", sizeof(_to2)); strlcpy(_to3, "", sizeof(_to3)); } layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Send", + _("Send"), amount, _to1, _to2, @@ -300,10 +301,10 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total summarystart = summary + 4; layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Transaction data:", + _("Transaction data:"), hexdata[0], hexdata[1], hexdata[2], @@ -338,20 +339,20 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, bn_read_be(pad_val, &val); if (bn_is_zero(&val)) { - strcpy(tx_value, is_token ? "token" : "message"); + strcpy(tx_value, is_token ? _("token") : _("message")); } else { ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value)); } layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Really send", + _("Really send"), tx_value, - "paying up to", + _("paying up to"), gas_value, - "for gas?", + _("for gas?"), NULL ); } @@ -409,7 +410,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { if (msg->chain_id < 1 || msg->chain_id > 109) { - fsm_sendFailure(FailureType_Failure_DataError, "Chain Id out of bounds"); + fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); ethereum_signing_abort(); return; } @@ -420,7 +421,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Data length provided, but no initial chunk"); + fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); ethereum_signing_abort(); return; } @@ -428,7 +429,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) * prevent exceeding the limit we use a stricter limit on data length. */ if (msg->data_length > 16000000) { - fsm_sendFailure(FailureType_Failure_DataError, "Data length exceeds limit"); + fsm_sendFailure(FailureType_Failure_DataError, _("Data length exceeds limit")); ethereum_signing_abort(); return; } @@ -437,14 +438,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) data_total = 0; } if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid size of initial chunk"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid size of initial chunk")); ethereum_signing_abort(); return; } // safety checks if (!ethereum_signing_check(msg)) { - fsm_sendFailure(FailureType_Failure_DataError, "Safety check failed"); + fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed")); ethereum_signing_abort(); return; } @@ -464,7 +465,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -472,7 +473,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (token == NULL && data_total > 0) { layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -482,7 +483,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->gas_price.bytes, msg->gas_price.size, msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -490,7 +491,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* Stage 1: Calculate total RLP length */ uint32_t rlp_length = 0; - layoutProgress("Signing", 0); + layoutProgress(_("Signing"), 0); rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); @@ -507,7 +508,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* Stage 2: Store header fields */ hash_rlp_list_length(rlp_length); - layoutProgress("Signing", 100); + layoutProgress(_("Signing"), 100); hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); @@ -530,19 +531,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { if (!ethereum_signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Ethereum signing mode"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); layoutHome(); return; } if (tx->data_chunk.size > data_left) { - fsm_sendFailure(FailureType_Failure_DataError, "Too much data"); + fsm_sendFailure(FailureType_Failure_DataError, _("Too much data")); ethereum_signing_abort(); return; } if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(FailureType_Failure_DataError, "Empty data chunk received"); + fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received")); ethereum_signing_abort(); return; } diff --git a/firmware/fsm.c b/firmware/fsm.c index cb2c7d1782..f1d807babc 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -50,6 +50,7 @@ #include "secp256k1.h" #include #include "ethereum.h" +#include "gettext.h" // message methods @@ -62,13 +63,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_INITIALIZED \ if (!storage_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ + fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ return; \ } #define CHECK_NOT_INITIALIZED \ if (storage_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ return; \ } @@ -111,6 +112,46 @@ void fsm_sendFailure(FailureType code, const char *text) RESP_INIT(Failure); resp->has_code = true; resp->code = code; + if (!text) { + switch (code) { + case FailureType_Failure_UnexpectedMessage: + text = _("Unexpected message"); + break; + case FailureType_Failure_ButtonExpected: + text = _("Button expected"); + break; + case FailureType_Failure_DataError: + text = _("Data error"); + break; + case FailureType_Failure_ActionCancelled: + text = _("Action cancelled by user"); + break; + case FailureType_Failure_PinExpected: + text = _("PIN expected"); + break; + case FailureType_Failure_PinCancelled: + text = _("PIN cancelled"); + break; + case FailureType_Failure_PinInvalid: + text = _("PIN invalid"); + break; + case FailureType_Failure_InvalidSignature: + text = _("Invalid signature"); + break; + case FailureType_Failure_ProcessError: + text = _("Process error"); + break; + case FailureType_Failure_NotEnoughFunds: + text = _("Not enough funds"); + break; + case FailureType_Failure_NotInitialized: + text = _("Device not initialized"); + break; + case FailureType_Failure_FirmwareError: + text = _("Firmware error"); + break; + } + } if (text) { resp->has_message = true; strlcpy(resp->message, text, sizeof(resp->message)); @@ -127,7 +168,7 @@ const CoinType *fsm_getCoin(bool has_name, const char *name) coin = coinByName("Bitcoin"); } if (!coin) { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid coin name"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); layoutHome(); return 0; } @@ -138,7 +179,7 @@ HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t addres { static HDNode node; if (!storage_getRootNode(&node, curve, true)) { - fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve"); + fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); return 0; } @@ -146,7 +187,7 @@ HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t addres return &node; } if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to derive private key"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); layoutHome(); return 0; } @@ -201,9 +242,9 @@ void fsm_msgPing(Ping *msg) RESP_INIT(Success); if (msg->has_button_protection && msg->button_protection) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -215,7 +256,7 @@ void fsm_msgPing(Ping *msg) if (msg->has_passphrase_protection && msg->passphrase_protection) { if (!protectPassphrase()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } } @@ -233,20 +274,20 @@ void fsm_msgChangePin(ChangePin *msg) bool removal = msg->has_remove && msg->remove; if (removal) { if (storage_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); } else { - fsm_sendSuccess("PIN removed"); + fsm_sendSuccess(_("PIN removed")); return; } } else { if (storage_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); } else { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -255,12 +296,12 @@ void fsm_msgChangePin(ChangePin *msg) if (removal) { storage_setPin(0); - fsm_sendSuccess("PIN removed"); + fsm_sendSuccess(_("PIN removed")); } else { if (protectChangePin()) { - fsm_sendSuccess("PIN changed"); + fsm_sendSuccess(_("PIN changed")); } else { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } } layoutHome(); @@ -269,9 +310,9 @@ void fsm_msgChangePin(ChangePin *msg) void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -281,15 +322,15 @@ void fsm_msgWipeDevice(WipeDevice *msg) storage_clearPinArea(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change - fsm_sendSuccess("Device wiped"); + fsm_sendSuccess(_("Device wiped")); layoutHome(); } void fsm_msgGetEntropy(GetEntropy *msg) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -338,7 +379,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -367,16 +408,16 @@ void fsm_msgLoadDevice(LoadDevice *msg) { CHECK_NOT_INITIALIZED - layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(FailureType_Failure_DataError, "Mnemonic with wrong checksum provided"); + fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); layoutHome(); return; } @@ -384,7 +425,7 @@ void fsm_msgLoadDevice(LoadDevice *msg) storage_loadDevice(msg); storage_commit(); - fsm_sendSuccess("Device loaded"); + fsm_sendSuccess(_("Device loaded")); layoutHome(); } @@ -392,7 +433,7 @@ void fsm_msgResetDevice(ResetDevice *msg) { CHECK_NOT_INITIALIZED - CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, "Invalid seed strength"); + CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); reset_init( msg->has_display_random && msg->display_random, @@ -409,8 +450,8 @@ void fsm_msgSignTx(SignTx *msg) { CHECK_INITIALIZED - CHECK_PARAM(msg->inputs_count > 0, "Transaction must have at least one input"); - CHECK_PARAM(msg->outputs_count > 0, "Transaction must have at least one output"); + CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); + CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); CHECK_PIN @@ -424,7 +465,7 @@ void fsm_msgSignTx(SignTx *msg) void fsm_msgTxAck(TxAck *msg) { - CHECK_PARAM(msg->has_tx, "No transaction provided"); + CHECK_PARAM(msg->has_tx, _("No transaction provided")); signing_txack(&(msg->tx)); } @@ -435,7 +476,7 @@ void fsm_msgCancel(Cancel *msg) recovery_abort(); signing_abort(); ethereum_signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } void fsm_msgEthereumSignTx(EthereumSignTx *msg) @@ -459,9 +500,9 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) { CHECK_INITIALIZED - CHECK_PARAM(msg->has_key, "No key provided"); - CHECK_PARAM(msg->has_value, "No value provided"); - CHECK_PARAM(msg->value.size % 16 == 0, "Value length must be a multiple of 16"); + CHECK_PARAM(msg->has_key, _("No key provided")); + CHECK_PARAM(msg->has_value, _("No value provided")); + CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); CHECK_PIN @@ -474,7 +515,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { layoutCipherKeyValue(encrypt, msg->key); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -508,43 +549,43 @@ void fsm_msgClearSession(ClearSession *msg) (void)msg; session_clear(true); // clear PIN as well layoutScreensaver(); - fsm_sendSuccess("Session cleared"); + fsm_sendSuccess(_("Session cleared")); } void fsm_msgApplySettings(ApplySettings *msg) { - CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen, "No setting provided"); + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen, _("No setting provided")); CHECK_PIN if (msg->has_label) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change label to"), msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_language) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_use_passphrase) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("encryption?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_homescreen) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -563,7 +604,7 @@ void fsm_msgApplySettings(ApplySettings *msg) storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } storage_commit(); - fsm_sendSuccess("Settings applied"); + fsm_sendSuccess(_("Settings applied")); layoutHome(); } @@ -581,9 +622,9 @@ void fsm_msgGetAddress(GetAddress *msg) if (!node) return; hdnode_fill_public_key(node); - layoutProgress("Computing address", 0); + layoutProgress(_("Computing address"), 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { - fsm_sendFailure(FailureType_Failure_DataError, "Can't encode address"); + fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); } if (msg->has_show_display && msg->show_display) { @@ -597,11 +638,11 @@ void fsm_msgGetAddress(GetAddress *msg) desc[11] = (n < 10) ? ' ': ('0' + (n / 10)); desc[12] = '0' + (n % 10); } else { - strlcpy(desc, "Address:", sizeof(desc)); + strlcpy(desc, _("Address:"), sizeof(desc)); } layoutAddress(resp->address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -636,7 +677,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) layoutAddress(address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -663,7 +704,7 @@ void fsm_msgSignMessage(SignMessage *msg) layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -675,7 +716,7 @@ void fsm_msgSignMessage(SignMessage *msg) HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; - layoutProgressSwipe("Signing", 0); + layoutProgressSwipe(_("Signing"), 0); if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address)); @@ -683,41 +724,41 @@ void fsm_msgSignMessage(SignMessage *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, "Error signing message"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); } layoutHome(); } void fsm_msgVerifyMessage(VerifyMessage *msg) { - CHECK_PARAM(msg->has_address, "No address provided"); - CHECK_PARAM(msg->has_message, "No message provided"); + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint32_t address_type; if (!coinExtractAddressType(coin, msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid address"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); return; } - layoutProgressSwipe("Verifying", 0); + layoutProgressSwipe(_("Verifying"), 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - fsm_sendSuccess("Message verified"); + fsm_sendSuccess(_("Message verified")); } else { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid signature"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); } layoutHome(); } @@ -730,7 +771,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -739,7 +780,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid identity"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -762,7 +803,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); int result = 0; - layoutProgressSwipe("Signing", 0); + layoutProgressSwipe(_("Signing"), 0); if (sign_ssh) { // SSH does not sign visual challenge result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); } else if (sign_gpg) { // GPG should sign a message digest @@ -793,7 +834,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, "Error signing identity"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); } layoutHome(); } @@ -806,7 +847,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) layoutDecryptIdentity(&msg->identity); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -815,7 +856,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Invalid identity"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -841,7 +882,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) resp->session_key.size = result_size; msg_write(MessageType_MessageType_ECDHSessionKey, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, "Error getting ECDH session key"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); } layoutHome(); } @@ -851,11 +892,11 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) { CHECK_INITIALIZED - CHECK_PARAM(msg->has_pubkey, "No public key provided"); - CHECK_PARAM(msg->has_message, "No message provided"); - CHECK_PARAM(msg->pubkey.size == 33, "Invalid public key provided"); + CHECK_PARAM(msg->has_pubkey, _("No public key provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + CHECK_PARAM(msg->pubkey.size == 33, _("Invalid public key provided")); curve_point pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, "Invalid public key provided"); + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, _("Invalid public key provided")); bool display_only = msg->has_display_only && msg->display_only; bool signing = msg->address_n_count > 0; @@ -874,13 +915,13 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - layoutProgressSwipe("Encrypting", 0); + layoutProgressSwipe(_("Encrypting"), 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Error encrypting message"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); layoutHome(); return; } @@ -895,26 +936,26 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) { CHECK_INITIALIZED - CHECK_PARAM(msg->has_nonce, "No nonce provided"); - CHECK_PARAM(msg->has_message, "No message provided"); - CHECK_PARAM(msg->has_hmac, "No message hmac provided"); + CHECK_PARAM(msg->has_nonce, _("No nonce provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + CHECK_PARAM(msg->has_hmac, _("No message hmac provided")); - CHECK_PARAM(msg->nonce.size == 33, "Invalid nonce key provided"); + CHECK_PARAM(msg->nonce.size == 33, _("Invalid nonce key provided")); curve_point nonce_pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, "Invalid nonce provided"); + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, _("Invalid nonce provided")); CHECK_PIN const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; - layoutProgressSwipe("Decrypting", 0); + layoutProgressSwipe(_("Decrypting"), 0); RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -949,7 +990,7 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) { CHECK_NOT_INITIALIZED - CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, "Invalid word count"); + CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); recovery_init( msg->has_word_count ? msg->word_count : 12, @@ -970,14 +1011,14 @@ void fsm_msgWordAck(WordAck *msg) void fsm_msgSetU2FCounter(SetU2FCounter *msg) { - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you want to set", "the U2F counter?", NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } storage_setU2FCounter(msg->u2f_counter); - fsm_sendSuccess("U2F counter set"); + fsm_sendSuccess(_("U2F counter set")); layoutHome(); } diff --git a/firmware/gettext.h b/firmware/gettext.h new file mode 100644 index 0000000000..c663dfbc2a --- /dev/null +++ b/firmware/gettext.h @@ -0,0 +1,25 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __GETTEXT_H__ +#define __GETTEXT_H__ + +#define _(X) (X) + +#endif diff --git a/firmware/layout2.c b/firmware/layout2.c index 0611b3c471..64a8fa2034 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -30,6 +30,7 @@ #include "qr_encode.h" #include "timer.h" #include "bignum.h" +#include "gettext.h" void *layoutLast = layoutHome; @@ -66,7 +67,7 @@ void layoutHome(void) oledSwipeLeft(); } layoutLast = layoutHome; - const char *label = storage_isInitialized() ? storage_getLabel() : "Go to trezor.io/start"; + const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start"); const uint8_t *homescreen = storage_getHomescreen(); if (homescreen) { BITMAP b; @@ -97,12 +98,12 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Confirm sending", + _("Confirm sending"), str_out, - "to", + _("to"), first_half, out->address + 17, NULL @@ -118,13 +119,13 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ bn_read_uint64(amount_fee, &amnt); bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Really send", + _("Really send"), str_out, - "from your wallet?", - "Fee included:", + _("from your wallet?"), + _("Fee included:"), str_fee, NULL ); @@ -137,14 +138,14 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) bn_read_uint64(fee, &amnt); bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, - "Cancel", - "Confirm", + _("Cancel"), + _("Confirm"), NULL, - "Fee", + _("Fee"), str_fee, - "is unexpectedly high.", + _("is unexpectedly high."), NULL, - "Send anyway?", + _("Send anyway?"), NULL ); } @@ -174,49 +175,49 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) void layoutSignMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", - "Sign message?", + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Sign message?"), str[0], str[1], str[2], str[3], NULL, NULL); } void layoutVerifyAddress(const char *address) { const char **str = split_message((const uint8_t *)address, strlen(address), 17); - layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm", - "Confirm address?", - "Message signed by:", + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Confirm address?"), + _("Message signed by:"), NULL, str[0], str[1], str[2], NULL); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm", - "Verified message", + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Verified message"), str[0], str[1], str[2], str[3], NULL, NULL); } void layoutCipherKeyValue(bool encrypt, const char *key) { const char **str = split_message((const uint8_t *)key, strlen(key), 16); - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", - encrypt ? "Encode value of this key?" : "Decode value of this key?", + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + encrypt ? _("Encode value of this key?") : _("Decode value of this key?"), str[0], str[1], str[2], str[3], NULL, NULL); } void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", - signing ? "Encrypt+Sign message?" : "Encrypt message?", + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + signing ? _("Encrypt+Sign message?") : _("Encrypt message?"), str[0], str[1], str[2], str[3], NULL, NULL); } void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) { const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_info, NULL, "OK", - address ? "Decrypted signed message" : "Decrypted message", + layoutDialogSwipe(&bmp_icon_info, NULL, _("OK"), + address ? _("Decrypted signed message") : _("Decrypted message"), str[0], str[1], str[2], str[3], NULL, NULL); } @@ -273,7 +274,7 @@ void layoutAddress(const char *address, const char *desc) oledDrawString(startx, (i+1) * 9 + 4, str[i]); } - static const char *btnYes = "Continue"; + static const char *btnYes = _("Continue"); oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); @@ -288,7 +289,7 @@ void layoutPublicKey(const uint8_t *pubkey) data2hex(pubkey, 1, desc + 12); data2hex(pubkey + 1, 32, hex); const char **str = split_message((const uint8_t *)hex, 32*2, 16); - layoutDialogSwipe(&bmp_icon_question, NULL, "Continue", NULL, + layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0], str[1], str[2], str[3], NULL); } @@ -302,17 +303,17 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) if (identity->has_proto && identity->proto[0]) { if (strcmp(identity->proto, "https") == 0) { - strlcpy(row_proto, "Web sign in to:", sizeof(row_proto)); + strlcpy(row_proto, _("Web sign in to:"), sizeof(row_proto)); } else if (is_gpg) { - strlcpy(row_proto, "GPG sign for:", sizeof(row_proto)); + strlcpy(row_proto, _("GPG sign for:"), sizeof(row_proto)); } else { strlcpy(row_proto, identity->proto, sizeof(row_proto)); char *p = row_proto; while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, " login to:", sizeof(row_proto)); + strlcat(row_proto, _(" login to:"), sizeof(row_proto)); } } else { - strlcpy(row_proto, "Login to:", sizeof(row_proto)); + strlcpy(row_proto, _("Login to:"), sizeof(row_proto)); } if (identity->has_host && identity->host[0]) { @@ -326,7 +327,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) } if (identity->has_user && identity->user[0]) { - strlcpy(row_user, "user: ", sizeof(row_user)); + strlcpy(row_user, _("user: "), sizeof(row_user)); strlcat(row_user, identity->user, sizeof(row_user)); } else { row_user[0] = 0; @@ -347,8 +348,8 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge) } } - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", - "Do you want to sign in?", + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Do you want to sign in?"), row_proto[0] ? row_proto : NULL, row_hostport[0] ? row_hostport : NULL, row_user[0] ? row_user : NULL, @@ -367,9 +368,9 @@ void layoutDecryptIdentity(const IdentityType *identity) strlcpy(row_proto, identity->proto, sizeof(row_proto)); char *p = row_proto; while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, " decrypt for:", sizeof(row_proto)); + strlcat(row_proto, _(" decrypt for:"), sizeof(row_proto)); } else { - strlcpy(row_proto, "Decrypt for:", sizeof(row_proto)); + strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto)); } if (identity->has_host && identity->host[0]) { @@ -383,14 +384,14 @@ void layoutDecryptIdentity(const IdentityType *identity) } if (identity->has_user && identity->user[0]) { - strlcpy(row_user, "user: ", sizeof(row_user)); + strlcpy(row_user, _("user: "), sizeof(row_user)); strlcat(row_user, identity->user, sizeof(row_user)); } else { row_user[0] = 0; } - layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", - "Do you want to decrypt?", + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Do you want to decrypt?"), row_proto[0] ? row_proto : NULL, row_hostport[0] ? row_hostport : NULL, row_user[0] ? row_user : NULL, @@ -403,5 +404,5 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico if (!appicon) { appicon = &bmp_icon_question; } - layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", NULL, appname, NULL, NULL); + layoutDialog(appicon, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); } diff --git a/firmware/messages.c b/firmware/messages.c index dcdee40f56..1e152519be 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -24,6 +24,7 @@ #include "debug.h" #include "fsm.h" #include "util.h" +#include "gettext.h" #include "pb_decode.h" #include "pb_encode.h" @@ -254,11 +255,11 @@ void msg_read_common(char type, const uint8_t *buf, int len) fields = MessageFields(type, 'i', msg_id); if (!fields) { // unknown message - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); return; } if (msg_size > MSG_IN_SIZE) { // message is too big :( - fsm_sendFailure(FailureType_Failure_DataError, "Message too big"); + fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); return; } @@ -357,7 +358,7 @@ void msg_read_tiny(const uint8_t *buf, int len) msg_tiny_id = 0xFFFF; } } else { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Unknown message"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); msg_tiny_id = 0xFFFF; } } diff --git a/firmware/protect.c b/firmware/protect.c index d47e58133a..01e44f0516 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -28,6 +28,7 @@ #include "layout2.h" #include "util.h" #include "debug.h" +#include "gettext.h" bool protectAbortedByInitialize = false; @@ -152,7 +153,7 @@ bool protectPin(bool use_cached) while (wait > 0) { // convert wait to secstr string char secstrbuf[20]; - strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf)); + strlcpy(secstrbuf, _("________0 seconds"), sizeof(secstrbuf)); char *secstr = secstrbuf + 9; uint32_t secs = wait; while (secs > 0 && secstr >= secstrbuf) { @@ -163,23 +164,23 @@ bool protectPin(bool use_cached) if (wait == 1) { secstrbuf[16] = 0; } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); // wait one second usbSleep(1000); if (msg_tiny_id == MessageType_MessageType_Initialize) { protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN cancelled"); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } wait--; } usbTiny(0); const char *pin; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN cancelled"); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) { @@ -187,7 +188,7 @@ bool protectPin(bool use_cached) storage_resetPinFails(fails); return true; } else { - fsm_sendFailure(FailureType_Failure_PinInvalid, "PIN invalid"); + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); return false; } } @@ -196,12 +197,12 @@ bool protectChangePin(void) { const char *pin; char pin1[17], pin2[17]; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, "Please enter new PIN:"); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); if (!pin) { return false; } strlcpy(pin1, pin, sizeof(pin1)); - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, "Please re-enter new PIN:"); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); if (!pin) { return false; } @@ -225,7 +226,7 @@ bool protectPassphrase(void) usbTiny(1); msg_write(MessageType_MessageType_PassphraseRequest, &resp); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"), _("passphrase using"), _("the computer's"), _("keyboard."), NULL, NULL); bool result; for (;;) { diff --git a/firmware/recovery.c b/firmware/recovery.c index a12328c965..da0a69831f 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -30,6 +30,7 @@ #include "bip39.h" #include "oled.h" #include "usb.h" +#include "gettext.h" #include "types.pb.h" #include "recovery-table.h" @@ -138,10 +139,10 @@ static void recovery_done(void) { storage.imported = true; } storage_commit(); - fsm_sendSuccess("Device recovered"); + fsm_sendSuccess(_("Device recovered")); } else { storage_reset(); - fsm_sendFailure(FailureType_Failure_DataError, "Invalid mnemonic, are words in correct order?"); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid mnemonic, are words in correct order?")); } awaiting_word = 0; layoutHome(); @@ -212,7 +213,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) char desc[] = "##th word"; int nr = (word_index / 4) + 1; format_number(desc, nr); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL, NULL, NULL); } else { oledBox(0, 27, 127, 63, false); } @@ -358,12 +359,12 @@ void next_word(void) { if (word_pos == 0) { const char * const *wl = mnemonic_wordlist(); strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the word"), NULL, fake_word, NULL, _("on your computer"), NULL); } else { fake_word[0] = 0; char desc[] = "##th word"; format_number(desc, word_pos); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), NULL, (word_pos < 10 ? desc + 1 : desc), NULL, _("of your mnemonic"), NULL); } recovery_request(); } @@ -376,7 +377,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr enforce_wordlist = _enforce_wordlist; if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -411,7 +412,7 @@ static void recovery_scrambledword(const char *word) if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { storage_reset(); - fsm_sendFailure(FailureType_Failure_ProcessError, "Wrong word retyped"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); layoutHome(); return; } @@ -428,7 +429,7 @@ static void recovery_scrambledword(const char *word) } if (!found) { storage_reset(); - fsm_sendFailure(FailureType_Failure_DataError, "Word not found in a wordlist"); + fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); layoutHome(); return; } @@ -457,7 +458,7 @@ void recovery_word(const char *word) recovery_scrambledword(word); break; default: - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Recovery mode"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); break; } } diff --git a/firmware/reset.c b/firmware/reset.c index f10ecd234f..4428753e48 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -28,6 +28,7 @@ #include "protect.h" #include "bip39.h" #include "util.h" +#include "gettext.h" static uint32_t strength; static uint8_t int_entropy[32]; @@ -48,16 +49,16 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect data2hex(int_entropy + 24, 8, ent_str[3]); if (display_random) { - layoutDialogSwipe(&bmp_icon_info, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -79,7 +80,7 @@ static char current_word[10], current_word_display[11]; void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { if (!awaiting_entropy) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Reset mode"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } SHA256_CTX ctx; @@ -126,21 +127,21 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) current_word_display[j + 1] = 0; if (word_pos == (int)strength/32*3) { // last word if (pass == 1) { - layoutDialogSwipe(&bmp_icon_info, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, _("Finish"), NULL, _("Please check the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(&bmp_icon_info, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, _("Again"), NULL, _("Write down the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } else { if (pass == 1) { - layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, _("Next"), NULL, _("Please check the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { - layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, _("Next"), NULL, _("Write down the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { storage_reset(); layoutHome(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } } @@ -148,7 +149,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) storage.has_mnemonic = true; storage_commit(); - fsm_sendSuccess("Device reset"); + fsm_sendSuccess(_("Device reset")); layoutHome(); } diff --git a/firmware/signing.c b/firmware/signing.c index 5501b41581..96e4147325 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -26,6 +26,7 @@ #include "protect.h" #include "crypto.h" #include "secp256k1.h" +#include "gettext.h" static uint32_t inputs_count; static uint32_t outputs_count; @@ -441,7 +442,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp sha256_Init(&hashers[1]); sha256_Init(&hashers[2]); - layoutProgressSwipe("Signing transaction", 0); + layoutProgressSwipe(_("Signing transaction"), 0); send_req_1_input(); } @@ -455,7 +456,7 @@ static bool signing_check_input(TxInputType *txinput) { && txinput->script_type == InputScriptType_SPENDMULTISIG) { uint8_t h[32]; if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Error computing multisig fingerprint"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); signing_abort(); return false; } @@ -487,7 +488,7 @@ static bool signing_check_prevtx_hash(void) { uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Encountered invalid prevhash"); + fsm_sendFailure(FailureType_Failure_DataError, _("Encountered invalid prevhash")); signing_abort(); return false; } @@ -504,7 +505,7 @@ static bool signing_check_output(TxOutputType *txoutput) { bool is_change = false; if (txoutput->address_n_count > 0) { if (txoutput->has_address) { - fsm_sendFailure(FailureType_Failure_DataError, "Address in change output"); + fsm_sendFailure(FailureType_Failure_DataError, _("Address in change output")); signing_abort(); return false; } @@ -528,28 +529,28 @@ static bool signing_check_output(TxOutputType *txoutput) { if (change_spend == 0) { // not set change_spend = txoutput->amount; } else { - fsm_sendFailure(FailureType_Failure_DataError, "Only one change output allowed"); + fsm_sendFailure(FailureType_Failure_DataError, _("Only one change output allowed")); signing_abort(); return false; } } if (spending + txoutput->amount < spending) { - fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return false; } spending += txoutput->amount; int co = compile_output(coin, root, txoutput, &bin_output, !is_change); if (!is_change) { - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); } if (co < 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return false; } @@ -561,7 +562,7 @@ static bool signing_check_output(TxOutputType *txoutput) { static bool signing_check_fee(void) { // check fees if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); signing_abort(); return false; } @@ -570,16 +571,16 @@ static bool signing_check_fee(void) { if (fee > tx_est_size_kb * coin->maxfee_kb) { layoutFeeOverThreshold(coin, fee); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); } // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Action cancelled by user"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } @@ -598,7 +599,7 @@ static void phase1_request_next_output(void) { } // Everything was checked, now phase 2 begins and the transaction is signed. progress_meta_step = progress_step / (inputs_count + outputs_count); - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); idx1 = 0; phase2_request_next_input(); } @@ -609,7 +610,7 @@ static bool signing_sign_input(void) { sha256_Final(&hashers[0], hash); sha256_Raw(hash, 32, hash); if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -620,7 +621,7 @@ static bool signing_sign_input(void) { resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); signing_abort(); return false; } @@ -630,7 +631,7 @@ static bool signing_sign_input(void) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Pubkey not found in multisig script"); + fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); signing_abort(); return false; } @@ -638,7 +639,7 @@ static bool signing_sign_input(void) { input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); if (input.script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize multisig script"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); signing_abort(); return false; } @@ -658,17 +659,17 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { // disable native segwit for now if (txinput->script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_DataError, "Native segwit is disabled"); + fsm_sendFailure(FailureType_Failure_DataError, _("Native segwit is disabled")); signing_abort(); return false; } if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return false; } if (txinput->amount > segwit_to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -694,7 +695,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Signing failed"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); signing_abort(); return false; } @@ -706,7 +707,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), node.public_key); if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Pubkey not found in multisig script"); + fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); signing_abort(); return false; } @@ -760,14 +761,14 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { void signing_txack(TransactionType *tx) { if (!signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); layoutHome(); return; } static int update_ctr = 0; if (update_ctr++ == 20) { - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); update_ctr = 0; } @@ -786,7 +787,7 @@ void signing_txack(TransactionType *tx) #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(FailureType_Failure_DataError, "Mixing segwit and non-segwit inputs is not allowed"); + fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -795,23 +796,23 @@ void signing_txack(TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (!coin->has_segwit || !coin->segwit) { - fsm_sendFailure(FailureType_Failure_DataError, "Segwit not enabled on this coin"); + fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); signing_abort(); return; } // disable native segwit for now if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_DataError, "Native segwit is disabled"); + fsm_sendFailure(FailureType_Failure_DataError, _("Native segwit is disabled")); signing_abort(); return; } if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, "Segwit input without amount"); + fsm_sendFailure(FailureType_Failure_DataError, _("Segwit input without amount")); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -820,7 +821,7 @@ void signing_txack(TransactionType *tx) if (idx1 == 0) { to.is_segwit = true; } else if (to.is_segwit == false) { - fsm_sendFailure(FailureType_Failure_DataError, "Mixing segwit and non-segwit inputs is not allowed"); + fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -831,7 +832,7 @@ void signing_txack(TransactionType *tx) segwit_to_spend += tx->inputs[0].amount; phase1_request_next_input(); } else { - fsm_sendFailure(FailureType_Failure_DataError, "Wrong input script type"); + fsm_sendFailure(FailureType_Failure_DataError, _("Wrong input script type")); signing_abort(); return; } @@ -850,7 +851,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_INPUT: progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -865,13 +866,13 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_OUTPUT: progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize output"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } if (idx2 == input.prev_index) { if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, "Value overflow"); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -891,7 +892,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_2_PREV_EXTRADATA: if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize extra data"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize extra data")); signing_abort(); return; } @@ -918,7 +919,7 @@ void signing_txack(TransactionType *tx) sha256_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -934,7 +935,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.size = 0; } if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -945,7 +946,7 @@ void signing_txack(TransactionType *tx) uint8_t hash[32]; sha256_Final(&hashers[0], hash); if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, "Transaction has changed during signing"); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } @@ -957,14 +958,14 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_OUTPUT: progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } // check hashOutputs tx_output_hash(&hashers[0], &bin_output); if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to serialize output"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } @@ -978,7 +979,7 @@ void signing_txack(TransactionType *tx) // since this took a longer time, update progress signatures++; progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); update_ctr = 0; if (idx1 < inputs_count - 1) { idx1++; @@ -998,7 +999,7 @@ void signing_txack(TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1017,7 +1018,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile input"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1038,7 +1039,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_5_OUTPUT: if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to compile output"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } @@ -1063,7 +1064,7 @@ void signing_txack(TransactionType *tx) } signatures++; progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress("Signing transaction", progress); + layoutProgress(_("Signing transaction"), progress); update_ctr = 0; if (idx1 < inputs_count - 1) { idx1++; @@ -1075,7 +1076,7 @@ void signing_txack(TransactionType *tx) return; } - fsm_sendFailure(FailureType_Failure_ProcessError, "Signing error"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); signing_abort(); } diff --git a/firmware/storage.c b/firmware/storage.c index 97f5f6a5ef..ec85cda4f1 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -40,6 +40,7 @@ #include "protect.h" #include "layout2.h" #include "usb.h" +#include "gettext.h" Storage storage; @@ -105,7 +106,7 @@ static char sessionPassphrase[51]; void storage_show_error(void) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); system_halt(); } @@ -339,7 +340,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size) void get_root_node_callback(uint32_t iter, uint32_t total) { usbSleep(1); - layoutProgress("Waking up", 1000 * iter / total); + layoutProgress(_("Waking up"), 1000 * iter / total); } const uint8_t *storage_getSeed(bool usePassphrase) diff --git a/firmware/u2f.c b/firmware/u2f.c index 6c246175c7..7c4a6b899e 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ - #include #include @@ -34,6 +33,7 @@ #include "hmac.h" #include "util.h" #include "macros.h" +#include "gettext.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" @@ -564,12 +564,12 @@ void u2f_register(const APDU *a) // error: testof-user-presence is required buttonUpdate(); // Clear button state if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { - layoutDialog(&bmp_icon_warning, NULL, "OK", NULL, "Another U2F device", "was used to register", "in this application.", NULL, NULL, NULL); + layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL, _("Another U2F device"), _("was used to register"), _("in this application."), NULL, NULL, NULL); } else { const char *appname; const BITMAP *appicon; getReadableAppId(req->appId, &appname, &appicon); - layoutU2FDialog("Register", appname, appicon); + layoutU2FDialog(_("Register"), appname, appicon); } last_req_state = REG; } @@ -704,7 +704,7 @@ void u2f_authenticate(const APDU *a) const char *appname; const BITMAP *appicon; getReadableAppId(req->appId, &appname, &appicon); - layoutU2FDialog("Authenticate", appname, appicon); + layoutU2FDialog(_("Authenticate"), appname, appicon); last_req_state = AUTH; } From 247cbd2ff16043795c31cbe60c922f4fe6244d20 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 22 Jun 2017 12:40:39 +0200 Subject: [PATCH 0458/1154] regenerate protobuf, disable unused messages --- firmware/fsm.h | 2 + firmware/protob/messages.options | 42 ++++++---- firmware/protob/messages.pb.c | 42 +--------- firmware/protob/messages.pb.h | 135 ++----------------------------- vendor/trezor-common | 2 +- 5 files changed, 41 insertions(+), 182 deletions(-) diff --git a/firmware/fsm.h b/firmware/fsm.h index 04be361f32..c440156111 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -50,8 +50,10 @@ void fsm_msgSignMessage(SignMessage *msg); void fsm_msgVerifyMessage(VerifyMessage *msg); void fsm_msgSignIdentity(SignIdentity *msg); void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg); +/* ECIES disabled void fsm_msgEncryptMessage(EncryptMessage *msg); void fsm_msgDecryptMessage(DecryptMessage *msg); +*/ //void fsm_msgPassphraseAck(PassphraseAck *msg); void fsm_msgEstimateTxSize(EstimateTxSize *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 5fbfc481bf..940e9388da 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -65,22 +65,30 @@ VerifyMessage.coin_name max_size:17 MessageSignature.address max_size:41 MessageSignature.signature max_size:65 -EncryptMessage.pubkey max_size:33 -EncryptMessage.message max_size:1024 -EncryptMessage.address_n max_count:8 -EncryptMessage.coin_name max_size:17 +# deprecated +EncryptMessage skip_message:true +# EncryptMessage.pubkey max_size:33 +# EncryptMessage.message max_size:1024 +# EncryptMessage.address_n max_count:8 +# EncryptMessage.coin_name max_size:17 -EncryptedMessage.nonce max_size:33 -EncryptedMessage.message max_size:1120 -EncryptedMessage.hmac max_size:8 +# deprecated +EncryptedMessage skip_message:true +# EncryptedMessage.nonce max_size:33 +# EncryptedMessage.message max_size:1120 +# EncryptedMessage.hmac max_size:8 -DecryptMessage.address_n max_count:8 -DecryptMessage.nonce max_size:33 -DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 -DecryptMessage.hmac max_size:8 +# deprecated +DecryptMessage skip_message:true +# DecryptMessage.address_n max_count:8 +# DecryptMessage.nonce max_size:33 +# DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 +# DecryptMessage.hmac max_size:8 -DecryptedMessage.address max_size:41 -DecryptedMessage.message max_size:1024 +# deprecated +DecryptedMessage skip_message:true +# DecryptedMessage.address max_size:41 +# DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 CipherKeyValue.key max_size:256 @@ -119,12 +127,16 @@ GetECDHSessionKey.ecdsa_curve_name max_size:32 ECDHSessionKey.session_key max_size:65 -# not used in firmware +# deprecated SimpleSignTx skip_message:true + +# not used in firmware, just in bootloader + +FirmwareErase skip_message:true FirmwareRequest skip_message:true FirmwareUpload skip_message:true -# used in debug firmware +# used only in debug firmware DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index b2421129d4..04c5d04040 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -12,7 +12,6 @@ const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; const char VerifyMessage_coin_name_default[17] = "Bitcoin"; -const char EncryptMessage_coin_name_default[17] = "Bitcoin"; const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; const uint32_t SignTx_version_default = 1u; @@ -203,7 +202,7 @@ const pb_field_t EntropyAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t RecoveryDevice_fields[9] = { +const pb_field_t RecoveryDevice_fields[10] = { PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), @@ -212,6 +211,7 @@ const pb_field_t RecoveryDevice_fields[9] = { PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, type, enforce_wordlist, 0), PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, type, 0), + PB_FIELD2( 10, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, dry_run, u2f_counter, 0), PB_LAST_FIELD }; @@ -246,36 +246,6 @@ const pb_field_t MessageSignature_fields[3] = { PB_LAST_FIELD }; -const pb_field_t EncryptMessage_fields[6] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptMessage, pubkey, pubkey, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptMessage, message, pubkey, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, EncryptMessage, display_only, message, 0), - PB_FIELD2( 4, UINT32 , REPEATED, STATIC , OTHER, EncryptMessage, address_n, display_only, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, EncryptMessage, coin_name, address_n, &EncryptMessage_coin_name_default), - PB_LAST_FIELD -}; - -const pb_field_t EncryptedMessage_fields[4] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EncryptedMessage, nonce, nonce, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, message, nonce, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EncryptedMessage, hmac, message, 0), - PB_LAST_FIELD -}; - -const pb_field_t DecryptMessage_fields[5] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, DecryptMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, nonce, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, message, nonce, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, DecryptMessage, hmac, message, 0), - PB_LAST_FIELD -}; - -const pb_field_t DecryptedMessage_fields[3] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DecryptedMessage, message, message, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DecryptedMessage, address, message, 0), - PB_LAST_FIELD -}; - const pb_field_t CipherKeyValue_fields[8] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), @@ -383,10 +353,6 @@ const pb_field_t SetU2FCounter_fields[2] = { PB_LAST_FIELD }; -const pb_field_t FirmwareErase_fields[1] = { - PB_LAST_FIELD -}; - const pb_field_t DebugLinkDecision_fields[2] = { PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), PB_LAST_FIELD @@ -454,11 +420,11 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_FirmwareErase_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for EncryptedMessage.message is too large. Define PB_FIELD_16BIT to fix this. +#error Field descriptor for ApplySettings.homescreen is too large. Define PB_FIELD_16BIT to fix this. #endif diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 9da12a785e..c474cfef0c 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -106,10 +106,6 @@ typedef struct _EntropyRequest { uint8_t dummy_field; } EntropyRequest; -typedef struct _FirmwareErase { - uint8_t dummy_field; -} FirmwareErase; - typedef struct _GetFeatures { uint8_t dummy_field; } GetFeatures; @@ -277,44 +273,6 @@ typedef struct _DebugLinkState { uint32_t recovery_word_pos; } DebugLinkState; -typedef struct { - size_t size; - uint8_t bytes[33]; -} DecryptMessage_nonce_t; - -typedef struct { - size_t size; - uint8_t bytes[1120]; -} DecryptMessage_message_t; - -typedef struct { - size_t size; - uint8_t bytes[8]; -} DecryptMessage_hmac_t; - -typedef struct _DecryptMessage { - size_t address_n_count; - uint32_t address_n[8]; - bool has_nonce; - DecryptMessage_nonce_t nonce; - bool has_message; - DecryptMessage_message_t message; - bool has_hmac; - DecryptMessage_hmac_t hmac; -} DecryptMessage; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DecryptedMessage_message_t; - -typedef struct _DecryptedMessage { - bool has_message; - DecryptedMessage_message_t message; - bool has_address; - char address[41]; -} DecryptedMessage; - typedef struct { size_t size; uint8_t bytes[65]; @@ -325,53 +283,6 @@ typedef struct _ECDHSessionKey { ECDHSessionKey_session_key_t session_key; } ECDHSessionKey; -typedef struct { - size_t size; - uint8_t bytes[33]; -} EncryptMessage_pubkey_t; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EncryptMessage_message_t; - -typedef struct _EncryptMessage { - bool has_pubkey; - EncryptMessage_pubkey_t pubkey; - bool has_message; - EncryptMessage_message_t message; - bool has_display_only; - bool display_only; - size_t address_n_count; - uint32_t address_n[8]; - bool has_coin_name; - char coin_name[17]; -} EncryptMessage; - -typedef struct { - size_t size; - uint8_t bytes[33]; -} EncryptedMessage_nonce_t; - -typedef struct { - size_t size; - uint8_t bytes[1120]; -} EncryptedMessage_message_t; - -typedef struct { - size_t size; - uint8_t bytes[8]; -} EncryptedMessage_hmac_t; - -typedef struct _EncryptedMessage { - bool has_nonce; - EncryptedMessage_nonce_t nonce; - bool has_message; - EncryptedMessage_message_t message; - bool has_hmac; - EncryptedMessage_hmac_t hmac; -} EncryptedMessage; - typedef struct { size_t size; uint8_t bytes[1024]; @@ -672,6 +583,8 @@ typedef struct _RecoveryDevice { uint32_t type; bool has_u2f_counter; uint32_t u2f_counter; + bool has_dry_run; + bool dry_run; } RecoveryDevice; typedef struct _ResetDevice { @@ -819,7 +732,6 @@ extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; extern const char SignMessage_coin_name_default[17]; extern const char VerifyMessage_coin_name_default[17]; -extern const char EncryptMessage_coin_name_default[17]; extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const uint32_t SignTx_version_default; @@ -855,16 +767,12 @@ extern const uint32_t SignTx_lock_time_default; #define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} -#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0} +#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0, false, 0} #define WordRequest_init_default {false, (WordRequestType)0} #define WordAck_init_default {""} #define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} #define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} #define MessageSignature_init_default {false, "", false, {0, {0}}} -#define EncryptMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin"} -#define EncryptedMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define DecryptMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define DecryptedMessage_init_default {false, {0, {0}}, false, ""} #define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_default {false, {0, {0}}} #define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} @@ -880,7 +788,6 @@ extern const uint32_t SignTx_lock_time_default; #define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} #define ECDHSessionKey_init_default {false, {0, {0}}} #define SetU2FCounter_init_default {false, 0} -#define FirmwareErase_init_default {0} #define DebugLinkDecision_init_default {0} #define DebugLinkGetState_init_default {0} #define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0} @@ -919,16 +826,12 @@ extern const uint32_t SignTx_lock_time_default; #define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0} #define EntropyRequest_init_zero {0} #define EntropyAck_init_zero {false, {0, {0}}} -#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0} +#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0, false, 0} #define WordRequest_init_zero {false, (WordRequestType)0} #define WordAck_init_zero {""} #define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} #define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} #define MessageSignature_init_zero {false, "", false, {0, {0}}} -#define EncryptMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""} -#define EncryptedMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define DecryptMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define DecryptedMessage_init_zero {false, {0, {0}}, false, ""} #define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_zero {false, {0, {0}}} #define EstimateTxSize_init_zero {0, 0, false, ""} @@ -944,7 +847,6 @@ extern const uint32_t SignTx_lock_time_default; #define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} #define ECDHSessionKey_init_zero {false, {0, {0}}} #define SetU2FCounter_init_zero {false, 0} -#define FirmwareErase_init_zero {0} #define DebugLinkDecision_init_zero {0} #define DebugLinkGetState_init_zero {0} #define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0} @@ -993,21 +895,7 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkState_reset_entropy_tag 8 #define DebugLinkState_recovery_fake_word_tag 9 #define DebugLinkState_recovery_word_pos_tag 10 -#define DecryptMessage_address_n_tag 1 -#define DecryptMessage_nonce_tag 2 -#define DecryptMessage_message_tag 3 -#define DecryptMessage_hmac_tag 4 -#define DecryptedMessage_message_tag 1 -#define DecryptedMessage_address_tag 2 #define ECDHSessionKey_session_key_tag 1 -#define EncryptMessage_pubkey_tag 1 -#define EncryptMessage_message_tag 2 -#define EncryptMessage_display_only_tag 3 -#define EncryptMessage_address_n_tag 4 -#define EncryptMessage_coin_name_tag 5 -#define EncryptedMessage_nonce_tag 1 -#define EncryptedMessage_message_tag 2 -#define EncryptedMessage_hmac_tag 3 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 #define EstimateTxSize_outputs_count_tag 1 @@ -1090,6 +978,7 @@ extern const uint32_t SignTx_lock_time_default; #define RecoveryDevice_enforce_wordlist_tag 6 #define RecoveryDevice_type_tag 8 #define RecoveryDevice_u2f_counter_tag 9 +#define RecoveryDevice_dry_run_tag 10 #define ResetDevice_display_random_tag 1 #define ResetDevice_strength_tag 2 #define ResetDevice_passphrase_protection_tag 3 @@ -1156,16 +1045,12 @@ extern const pb_field_t LoadDevice_fields[9]; extern const pb_field_t ResetDevice_fields[8]; extern const pb_field_t EntropyRequest_fields[1]; extern const pb_field_t EntropyAck_fields[2]; -extern const pb_field_t RecoveryDevice_fields[9]; +extern const pb_field_t RecoveryDevice_fields[10]; extern const pb_field_t WordRequest_fields[2]; extern const pb_field_t WordAck_fields[2]; extern const pb_field_t SignMessage_fields[4]; extern const pb_field_t VerifyMessage_fields[5]; extern const pb_field_t MessageSignature_fields[3]; -extern const pb_field_t EncryptMessage_fields[6]; -extern const pb_field_t EncryptedMessage_fields[4]; -extern const pb_field_t DecryptMessage_fields[5]; -extern const pb_field_t DecryptedMessage_fields[3]; extern const pb_field_t CipherKeyValue_fields[8]; extern const pb_field_t CipheredKeyValue_fields[2]; extern const pb_field_t EstimateTxSize_fields[4]; @@ -1181,7 +1066,6 @@ extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t GetECDHSessionKey_fields[4]; extern const pb_field_t ECDHSessionKey_fields[2]; extern const pb_field_t SetU2FCounter_fields[2]; -extern const pb_field_t FirmwareErase_fields[1]; extern const pb_field_t DebugLinkDecision_fields[2]; extern const pb_field_t DebugLinkGetState_fields[1]; extern const pb_field_t DebugLinkState_fields[11]; @@ -1222,16 +1106,12 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define ResetDevice_size 72 #define EntropyRequest_size 0 #define EntropyAck_size 131 -#define RecoveryDevice_size 78 +#define RecoveryDevice_size 80 #define WordRequest_size 6 #define WordAck_size 14 #define SignMessage_size 1094 #define VerifyMessage_size 1156 #define MessageSignature_size 110 -#define EncryptMessage_size 1131 -#define EncryptedMessage_size 1168 -#define DecryptMessage_size 1216 -#define DecryptedMessage_size 1070 #define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 #define EstimateTxSize_size 31 @@ -1247,7 +1127,6 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define GetECDHSessionKey_size (107 + IdentityType_size) #define ECDHSessionKey_size 67 #define SetU2FCounter_size 6 -#define FirmwareErase_size 0 #define DebugLinkDecision_size 2 #define DebugLinkGetState_size 0 #define DebugLinkState_size (1468 + HDNodeType_size) diff --git a/vendor/trezor-common b/vendor/trezor-common index 4eef33b05a..ae1900a2bc 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 4eef33b05afb5e8465c8947272bc5421b1b6d896 +Subproject commit ae1900a2bcc9a140f636d9ef2c5e029fe397441a From db19dd13066a3f9d9495a587f42c3b7cfdfd408d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Jun 2017 21:13:06 +0200 Subject: [PATCH 0459/1154] Set -mcpu=cortex-m3 linker flag. This fixes a bug with Ubuntu 17.04. It includes the correct architecture (armv7-m) and also includes the flag -mfix-cortex-m3-ldrd as default. --- Makefile.include | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index 524f62229d..15a7d9014e 100644 --- a/Makefile.include +++ b/Makefile.include @@ -71,9 +71,8 @@ LDFLAGS += --static \ -T$(LDSCRIPT) \ -nostartfiles \ -Wl,--gc-sections \ + -mcpu=cortex-m3 \ -mthumb \ - -march=armv7 \ - -mfix-cortex-m3-ldrd \ -msoft-float all: $(NAME).bin From db7915e946268631c902be13058c53e7fbd5418d Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 20 Jun 2017 22:49:17 +0300 Subject: [PATCH 0460/1154] Allow testing recovery with an initialized device This would allow safe mnemonic validation by using a dry-run flag. --- firmware/fsm.c | 10 ++++- firmware/recovery.c | 100 ++++++++++++++++++++++++++++++++++---------- firmware/recovery.h | 2 +- 3 files changed, 86 insertions(+), 26 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index f1d807babc..a956025c4a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -988,7 +988,12 @@ void fsm_msgEstimateTxSize(EstimateTxSize *msg) void fsm_msgRecoveryDevice(RecoveryDevice *msg) { - CHECK_NOT_INITIALIZED + const bool dry_run = msg->has_dry_run ? msg->dry_run : false; + if (dry_run) { + CHECK_PIN + } else { + CHECK_NOT_INITIALIZED + } CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); @@ -1000,7 +1005,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) msg->has_label ? msg->label : 0, msg->has_enforce_wordlist && msg->enforce_wordlist, msg->has_type ? msg->type : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0 + msg->has_u2f_counter ? msg->u2f_counter : 0, + dry_run ); } diff --git a/firmware/recovery.c b/firmware/recovery.c index da0a69831f..4ca56c57e3 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -44,6 +44,11 @@ static uint32_t word_count; */ static int awaiting_word = 0; +/* True if we should not write anything back to storage + * (can be used for testing seed for correctness). + */ +static bool dry_run; + /* True if we should check that seed corresponds to bip39. */ static bool enforce_wordlist; @@ -121,27 +126,73 @@ static void recovery_request(void) { msg_write(MessageType_MessageType_WordRequest, &resp); } +static bool is_same_mnemonic(const char *new_mnemonic) { + /* The execution time of the following code only depends on the + * (public) input. This avoids timing attacks. + */ + char diff = 0; + uint32_t i = 0; + for (; new_mnemonic[i]; i++) { + diff |= (storage.mnemonic[i] - new_mnemonic[i]); + } + diff |= storage.mnemonic[i]; + return diff == 0; +} + /* Called when the last word was entered. * Check mnemonic and send success/failure. */ static void recovery_done(void) { uint32_t i; - strlcpy(storage.mnemonic, words[0], sizeof(storage.mnemonic)); + char new_mnemonic[sizeof(storage.mnemonic)] = {0}; + + strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); for (i = 1; i < word_count; i++) { - strlcat(storage.mnemonic, " ", sizeof(storage.mnemonic)); - strlcat(storage.mnemonic, words[i], sizeof(storage.mnemonic)); + strlcat(new_mnemonic, " ", sizeof(new_mnemonic)); + strlcat(new_mnemonic, words[i], sizeof(new_mnemonic)); } - if (!enforce_wordlist || mnemonic_check(storage.mnemonic)) { - storage.has_mnemonic = true; - if (!enforce_wordlist) { - // not enforcing => mark storage as imported - storage.has_imported = true; - storage.imported = true; + if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { + // New mnemonic is valid. + if (!dry_run) { + // Update mnemonic on storage. + storage.has_mnemonic = true; + strlcpy(storage.mnemonic, new_mnemonic, sizeof(new_mnemonic)); + if (!enforce_wordlist) { + // not enforcing => mark storage as imported + storage.has_imported = true; + storage.imported = true; + } + storage_commit(); + fsm_sendSuccess(_("Device recovered")); + } else { + // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). + const bool same_mnemonic = is_same_mnemonic(new_mnemonic); + if (same_mnemonic) { + layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, + _("The mnemonic is"), + _("valid and matches"), + _("existing one."), NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendSuccess(_("Mnemonic is valid and matches existing one")); + } else { + layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, + _("The mnemonic is"), + _("valid but doesn't"), + _("match existing one."), NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendFailure(FailureType_Failure_DataError, + _("Mnemonic is valid but doesn't match existing one")); + } } - storage_commit(); - fsm_sendSuccess(_("Device recovered")); } else { - storage_reset(); + // New mnemonic is invalid. + if (!dry_run) { + storage_reset(); + } else { + layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, + _("The mnemonic is"), _("invalid!"), NULL, NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + } fsm_sendFailure(FailureType_Failure_DataError, _("Invalid mnemonic, are words in correct order?")); } awaiting_word = 0; @@ -369,25 +420,28 @@ void next_word(void) { recovery_request(); } -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter) +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run) { if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; word_count = _word_count; enforce_wordlist = _enforce_wordlist; + dry_run = _dry_run; - if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; + if (!dry_run) { + if (pin_protection && !protectChangePin()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + storage.has_passphrase_protection = true; + storage.passphrase_protection = passphrase_protection; + storage_setLanguage(language); + storage_setLabel(label); + storage_setU2FCounter(u2f_counter); } - storage.has_passphrase_protection = true; - storage.passphrase_protection = passphrase_protection; - storage_setLanguage(language); - storage_setLabel(label); - storage_setU2FCounter(u2f_counter); - if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { awaiting_word = 2; word_index = 0; diff --git a/firmware/recovery.h b/firmware/recovery.h index ac463d28e2..fdd61dc453 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -23,7 +23,7 @@ #include #include -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter); +void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run); void recovery_word(const char *word); void recovery_abort(void); const char *recovery_get_fake_word(void); From 825342529348c55184ded9ff00bc934eaf501893 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 23 Jun 2017 16:47:53 +0200 Subject: [PATCH 0461/1154] recovery: change wording --- firmware/recovery.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index 4ca56c57e3..ac08dc63c3 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -166,22 +166,21 @@ static void recovery_done(void) { fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - const bool same_mnemonic = is_same_mnemonic(new_mnemonic); - if (same_mnemonic) { + if (is_same_mnemonic(new_mnemonic)) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, - _("The mnemonic is"), - _("valid and matches"), - _("existing one."), NULL, NULL, NULL); + _("The seed is valid"), + _("and MATCHES"), + _("the one in the device."), NULL, NULL, NULL); protectButton(ButtonRequestType_ButtonRequest_Other, true); - fsm_sendSuccess(_("Mnemonic is valid and matches existing one")); + fsm_sendSuccess(_("The seed is valid and matches the one in the device")); } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, - _("The mnemonic is"), - _("valid but doesn't"), - _("match existing one."), NULL, NULL, NULL); + _("The seed is valid"), + _("but does NOT MATCH"), + _("the one in the device."), NULL, NULL, NULL); protectButton(ButtonRequestType_ButtonRequest_Other, true); fsm_sendFailure(FailureType_Failure_DataError, - _("Mnemonic is valid but doesn't match existing one")); + _("The seed is valid but does not match the one in the device")); } } } else { @@ -190,7 +189,7 @@ static void recovery_done(void) { storage_reset(); } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, - _("The mnemonic is"), _("invalid!"), NULL, NULL, NULL, NULL); + _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); protectButton(ButtonRequestType_ButtonRequest_Other, true); } fsm_sendFailure(FailureType_Failure_DataError, _("Invalid mnemonic, are words in correct order?")); From 1214a3f69b748bd1bd6190374d526c2ba9cc9b46 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 25 Jun 2017 15:37:45 +0100 Subject: [PATCH 0462/1154] vendor: Update trezor-crypto --- firmware/Makefile | 1 + vendor/trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 7c41c34b45..409b4e6fbd 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -29,6 +29,7 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-sha3.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-keccak.o OBJS += ../vendor/trezor-crypto/hmac.o diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index ba206056e7..5331935626 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit ba206056e73cb1972b7ecb6ad7939254cb51074f +Subproject commit 533193562601780c8705ecb80c908916bb80b427 From 0b3373e6dfbef3132001580d482839cb99084620 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 9 Jun 2017 19:54:09 +0100 Subject: [PATCH 0463/1154] bootloader: Remove duplicate 'flash' target --- bootloader/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index 8f06bb84f9..2067813e8a 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -18,6 +18,3 @@ include ../Makefile.include align: $(NAME).bin ./firmware_align.py $(NAME).bin - -flash: $(NAME).bin - $(FLASH) write $(NAME).bin 0x8000000 From 80d17c133331a47e729130febe87073718c9bd6f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:36:58 +0100 Subject: [PATCH 0464/1154] bootloader: Allow building as an app --- bootloader/bootloader.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 843a1dddf4..0e0bec13ae 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -34,10 +34,6 @@ #include "serialno.h" #include "rng.h" -#ifdef APPVER -#error Bootloader cannot be used in app mode -#endif - void layoutFirmwareHash(const uint8_t *hash) { char str[4][17]; @@ -116,6 +112,7 @@ void bootloader_loop(void) int check_firmware_sanity(void) { +#ifndef APPVER if (memcmp((const void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match return 0; } @@ -125,6 +122,7 @@ int check_firmware_sanity(void) if (*((const uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size return 0; } +#endif return 1; } @@ -138,13 +136,18 @@ void __attribute__((noreturn)) __stack_chk_fail(void) int main(void) { +#ifndef APPVER setup(); +#endif __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks +#ifndef APPVER memory_protect(); oledInit(); +#endif firmware_present = check_firmware_sanity(); +#ifndef APPVER // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); @@ -164,6 +167,7 @@ int main(void) load_app(); } +#endif bootloader_loop(); From e74f9d8730d9074f8734a5dc9917e8bfc8459a59 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:40:38 +0100 Subject: [PATCH 0465/1154] fastflash: Link bootloader that runs from RAM --- fastflash/Makefile | 13 +++++++++++++ fastflash/bootloader.c | 1 + fastflash/signatures.c | 28 ++++++++++++++++++++++++++++ fastflash/usb.c | 1 + memory_app_fastflash.ld | 9 +++++++++ 5 files changed, 52 insertions(+) create mode 100644 fastflash/Makefile create mode 120000 fastflash/bootloader.c create mode 100644 fastflash/signatures.c create mode 120000 fastflash/usb.c create mode 100644 memory_app_fastflash.ld diff --git a/fastflash/Makefile b/fastflash/Makefile new file mode 100644 index 0000000000..9679981750 --- /dev/null +++ b/fastflash/Makefile @@ -0,0 +1,13 @@ +APPVER = fastflash + +NAME = bootloader + +OBJS += bootloader.o +OBJS += signatures.o +OBJS += usb.o + +OBJS += ../vendor/trezor-crypto/sha2.o + +include ../Makefile.include + +CFLAGS += -I../bootloader diff --git a/fastflash/bootloader.c b/fastflash/bootloader.c new file mode 120000 index 0000000000..3c60d798d4 --- /dev/null +++ b/fastflash/bootloader.c @@ -0,0 +1 @@ +../bootloader/bootloader.c \ No newline at end of file diff --git a/fastflash/signatures.c b/fastflash/signatures.c new file mode 100644 index 0000000000..d452a067d6 --- /dev/null +++ b/fastflash/signatures.c @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include + +int signatures_ok(uint8_t *store_hash) +{ + (void) store_hash; + + return false; +} diff --git a/fastflash/usb.c b/fastflash/usb.c new file mode 120000 index 0000000000..13b2a33e6b --- /dev/null +++ b/fastflash/usb.c @@ -0,0 +1 @@ +../bootloader/usb.c \ No newline at end of file diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld new file mode 100644 index 0000000000..9521fd4f4c --- /dev/null +++ b/memory_app_fastflash.ld @@ -0,0 +1,9 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ +MEMORY +{ + rom (rx) : ORIGIN = 0x20000000, LENGTH = 20K + ram (rwx) : ORIGIN = ORIGIN(rom) + LENGTH(rom), + LENGTH = 128K - LENGTH(rom) +} + +INCLUDE libopencm3_stm32f2.ld From 65bb167db6b80bd89c0f1da446c7f8912e1db8b3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:41:31 +0100 Subject: [PATCH 0466/1154] firmware: Create ELF from fastflash/bootloader.bin --- firmware/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/Makefile b/firmware/Makefile index 409b4e6fbd..09a5b3c22f 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -66,3 +66,9 @@ CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DUSE_ETHEREUM=1 + +bootloader.o: ../fastflash/bootloader.bin + $(OBJCOPY) -I binary -O elf32-littlearm -B arm \ + --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_size=__bootloader_size__ \ + --rename-section .data=.bootloader \ + $< $@ From 21eb49faff1520b1818c453a62e19bfa32ff5a05 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:42:10 +0100 Subject: [PATCH 0467/1154] firmware: Start fastflash when left button held --- firmware/Makefile | 11 +++++++++++ firmware/fastflash.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ firmware/fastflash.h | 26 ++++++++++++++++++++++++ firmware/trezor.c | 9 +++++++++ memory_app_2.0.0.ld | 21 ++++++++++++++++++++ 5 files changed, 114 insertions(+) create mode 100644 firmware/fastflash.c create mode 100644 firmware/fastflash.h create mode 100644 memory_app_2.0.0.ld diff --git a/firmware/Makefile b/firmware/Makefile index 09a5b3c22f..2048d430fa 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,4 +1,11 @@ +ifeq ($(FASTFLASH),1) +APPVER = 2.0.0 + +OBJS += fastflash.o +OBJS += bootloader.o +else APPVER = 1.0.0 +endif NAME = trezor @@ -59,6 +66,10 @@ OBJS += protob/types.pb.o include ../Makefile.include +ifeq ($(FASTFLASH),1) +CFLAGS += -DFASTFLASH +endif + CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DQR_MAX_VERSION=0 diff --git a/firmware/fastflash.c b/firmware/fastflash.c new file mode 100644 index 0000000000..85aef6ffb9 --- /dev/null +++ b/firmware/fastflash.c @@ -0,0 +1,47 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "fastflash.h" + +#include +#include +#include + +#include + +extern uint32_t __bootloader_loadaddr__[]; +extern uint32_t __bootloader_runaddr__[]; +extern uint8_t __bootloader_size__[]; + +void load_bootloader() { + memcpy(__bootloader_runaddr__, __bootloader_loadaddr__, (size_t) __bootloader_size__); +} + +void run_bootloader() { + // Relocate vector tables + SCB_VTOR = (uint32_t) __bootloader_runaddr__; + + // Set stack pointer + __asm__ volatile("msr msp, %0":: "r" (__bootloader_runaddr__[0])); + + // Jump to address + ((void (*)(void))(__bootloader_runaddr__[1]))(); + + while (true); +} diff --git a/firmware/fastflash.h b/firmware/fastflash.h new file mode 100644 index 0000000000..20caf1ef7a --- /dev/null +++ b/firmware/fastflash.h @@ -0,0 +1,26 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __FASTFLASH_H__ +#define __FASTFLASH_H__ + +void load_bootloader(void); +void __attribute__((noreturn)) run_bootloader(void); + +#endif diff --git a/firmware/trezor.c b/firmware/trezor.c index 87c1928527..d9febae6c4 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -29,6 +29,7 @@ #include "rng.h" #include "timer.h" #include "buttons.h" +#include "fastflash.h" uint32_t __stack_chk_guard; @@ -98,6 +99,14 @@ int main(void) __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif +#if FASTFLASH + uint16_t state = gpio_port_read(BTN_PORT); + if ((state & BTN_PIN_NO) == 0) { + load_bootloader(); + run_bootloader(); + } +#endif + timer_init(); #if DEBUG_LINK diff --git a/memory_app_2.0.0.ld b/memory_app_2.0.0.ld new file mode 100644 index 0000000000..f846f17280 --- /dev/null +++ b/memory_app_2.0.0.ld @@ -0,0 +1,21 @@ +/* STM32F205RE - 512K Flash, 128K RAM */ +/* program starts at 0x08010000 */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K + bootloader (rx) : ORIGIN = 0x20000000, LENGTH = __bootloader_size__ + ram (rwx) : ORIGIN = ORIGIN(bootloader) + LENGTH(bootloader), + LENGTH = 128K - LENGTH(bootloader) +} + +INCLUDE libopencm3_stm32f2.ld + +SECTIONS +{ + .bootloader : { + __bootloader_runaddr__ = .; + KEEP (*(.bootloader*)) + } >bootloader AT >rom + + __bootloader_loadaddr__ = LOADADDR(.bootloader); +} From ed5e9c934702586ada83233454d5523a4f3bbc9a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:54:54 +0100 Subject: [PATCH 0468/1154] firmware: Define FASTFLASH in all cases --- firmware/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 2048d430fa..32f2cd7bd6 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -67,7 +67,9 @@ OBJS += protob/types.pb.o include ../Makefile.include ifeq ($(FASTFLASH),1) -CFLAGS += -DFASTFLASH +CFLAGS += -DFASTFLASH=1 +else +CFLAGS += -DFASTFLASH=0 endif CFLAGS += -Wno-sequence-point From d80979cd0a8d2b06006577a280ce60931b254230 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 19:55:11 +0100 Subject: [PATCH 0469/1154] Travis CI: Build FASTFLASH=1 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1d3ba2a931..06d5eed32f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,9 @@ script: - make - make -C firmware - make -C bootloader + - make -C fastflash - make -C demo + - make -C firmware clean && make -C firmware FASTFLASH=1 notifications: webhooks: From 899852423df27517523c404d1d0c91f93285faf3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 10 Jun 2017 20:15:12 +0100 Subject: [PATCH 0470/1154] fastflash: Compatible with GCC 4.9.3 --- memory_app_2.0.0.ld | 4 ++-- memory_app_fastflash.ld | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/memory_app_2.0.0.ld b/memory_app_2.0.0.ld index f846f17280..163eb75a33 100644 --- a/memory_app_2.0.0.ld +++ b/memory_app_2.0.0.ld @@ -3,8 +3,8 @@ MEMORY { rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K - bootloader (rx) : ORIGIN = 0x20000000, LENGTH = __bootloader_size__ - ram (rwx) : ORIGIN = ORIGIN(bootloader) + LENGTH(bootloader), + bootloader (rx) : ORIGIN = 0x20000000, LENGTH = 20K + ram (rwx) : ORIGIN = 0x20000000 + LENGTH(bootloader), LENGTH = 128K - LENGTH(bootloader) } diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index 9521fd4f4c..f19e51f2fa 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -2,7 +2,7 @@ MEMORY { rom (rx) : ORIGIN = 0x20000000, LENGTH = 20K - ram (rwx) : ORIGIN = ORIGIN(rom) + LENGTH(rom), + ram (rwx) : ORIGIN = 0x20000000 + LENGTH(rom), LENGTH = 128K - LENGTH(rom) } From 73708aa47e29cb02e5fc5f55bfe8be0f039f45a9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jun 2017 15:44:01 +0200 Subject: [PATCH 0471/1154] refactor recovery.is_same_mnemonic function to storage_containsMnemonic --- firmware/protect.c | 2 +- firmware/recovery.c | 15 +-------------- firmware/storage.c | 22 +++++++++++++++++++--- firmware/storage.h | 4 +++- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 01e44f0516..53f5791a9b 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -183,7 +183,7 @@ bool protectPin(bool use_cached) fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } - if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) { + if (storage_increasePinFails(fails) && storage_containsPin(pin)) { session_cachePin(); storage_resetPinFails(fails); return true; diff --git a/firmware/recovery.c b/firmware/recovery.c index ac08dc63c3..878736d37c 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -126,19 +126,6 @@ static void recovery_request(void) { msg_write(MessageType_MessageType_WordRequest, &resp); } -static bool is_same_mnemonic(const char *new_mnemonic) { - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - for (; new_mnemonic[i]; i++) { - diff |= (storage.mnemonic[i] - new_mnemonic[i]); - } - diff |= storage.mnemonic[i]; - return diff == 0; -} - /* Called when the last word was entered. * Check mnemonic and send success/failure. */ @@ -166,7 +153,7 @@ static void recovery_done(void) { fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - if (is_same_mnemonic(new_mnemonic)) { + if (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, _("The seed is valid"), _("and MATCHES"), diff --git a/firmware/storage.c b/firmware/storage.c index ec85cda4f1..0976c44fee 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -427,10 +427,26 @@ const uint8_t *storage_getHomescreen(void) return (storage.has_homescreen && storage.homescreen.size == 1024) ? storage.homescreen.bytes : 0; } -/* Check whether pin matches storage. The pin must be a null-terminated - * string with at most 9 characters. +/* Check whether mnemonic matches storage. The mnemonic must be + * a null-terminated string. */ -bool storage_isPinCorrect(const char *pin) +bool storage_containsMnemonic(const char *mnemonic) { + /* The execution time of the following code only depends on the + * (public) input. This avoids timing attacks. + */ + char diff = 0; + uint32_t i = 0; + for (; mnemonic[i]; i++) { + diff |= (storage.mnemonic[i] - mnemonic[i]); + } + diff |= storage.mnemonic[i]; + return diff == 0; +} + +/* Check whether pin matches storage. The pin must be + * a null-terminated string with at most 9 characters. + */ +bool storage_containsPin(const char *pin) { /* The execution time of the following code only depends on the * (public) input. This avoids timing attacks. diff --git a/firmware/storage.h b/firmware/storage.h index b3680a2bb4..89e2cfc4fe 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -51,7 +51,9 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); -bool storage_isPinCorrect(const char *pin); +bool storage_containsMnemonic(const char *mnemonic); + +bool storage_containsPin(const char *pin); bool storage_hasPin(void); void storage_setPin(const char *pin); void session_cachePin(void); From 01b4825d53b08721116b9821a62744e387d44f11 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 27 Jun 2017 13:51:45 +0200 Subject: [PATCH 0472/1154] ethereum: add new tokens --- firmware/ethereum_tokens-gen.py | 10 ++++++++-- firmware/ethereum_tokens.c | 22 +++++++++++++++++++++- firmware/ethereum_tokens.h | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 7caacf3ef5..3f9181d057 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -25,5 +25,11 @@ def print_tokens(chain, chain_id): address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() print('\t{%2d, "%s", " %s", %d},' % (chain_id, address, symbol, decimal)) -print_tokens('eth', 1) -print_tokens('etc', 61) + return len(tokens) + +count = 0 + +count += print_tokens('eth', 1) +count += print_tokens('etc', 61) + +print('#define TOKENS_COUNT %d' % count) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 706cc2507c..cf3de91b43 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -8,14 +8,19 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, + { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, + { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, + { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, { 1, "\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, + { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, + { 1, "\xbb\xb1\xbd\x2d\x74\x1f\x05\xe1\x44\xe6\xc4\x51\x76\x76\xa1\x55\x54\xfd\x4b\x8d", " FUN", 8}, { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, @@ -27,21 +32,34 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, { 1, "\xb0\x4c\xfa\x8a\x26\xd6\x02\xfb\x50\x23\x2c\xee\x0d\xaf\x29\x06\x02\x64\xe0\x4b", " MCO", 8}, + { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, { 1, "\xd0\xb1\x71\xeb\x0b\x0f\x2c\xbd\x35\xcc\xd9\x7c\xdc\x5e\xdc\x3f\xfe\x48\x71\xaa", " MDA", 18}, { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, + { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, + { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, + { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, + { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, + { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, + { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, { 1, "\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, - { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " ROL", 16}, + { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, + { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, + { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, + { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, + { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, + { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, @@ -49,9 +67,11 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, + { 1, "\x82\x66\x57\x64\xea\x0b\x58\x15\x7e\x1e\x5e\x9b\xab\x32\xf6\x8c\x76\xec\x0c\xdf", " VSM", 0}, { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, + { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index a16d64bd3a..1251cc7b5a 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 51 +#define TOKENS_COUNT 71 typedef struct { uint8_t chain_id; From 91a1b6c4bcaa33de37ea91769028e78bf2816805 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 28 Jun 2017 18:49:44 +0200 Subject: [PATCH 0473/1154] drop EstimateTxSize (and TxSize) --- firmware/fsm.c | 8 ----- firmware/fsm.h | 1 - firmware/protob/messages.options | 7 +++- firmware/protob/messages.pb.c | 25 +++++--------- firmware/protob/messages.pb.h | 56 +++++++++++++------------------- firmware/protob/messages_map.h | 4 +-- firmware/protob/storage.pb.c | 3 +- firmware/protob/storage.pb.h | 11 ++++--- firmware/transaction.h | 2 -- vendor/trezor-common | 2 +- 10 files changed, 50 insertions(+), 69 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index a956025c4a..60a7082b1c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -978,14 +978,6 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) } */ -void fsm_msgEstimateTxSize(EstimateTxSize *msg) -{ - RESP_INIT(TxSize); - resp->has_tx_size = true; - resp->tx_size = transactionEstimateSize(msg->inputs_count, msg->outputs_count); - msg_write(MessageType_MessageType_TxSize, resp); -} - void fsm_msgRecoveryDevice(RecoveryDevice *msg) { const bool dry_run = msg->has_dry_run ? msg->dry_run : false; diff --git a/firmware/fsm.h b/firmware/fsm.h index c440156111..f9e297bf84 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -55,7 +55,6 @@ void fsm_msgEncryptMessage(EncryptMessage *msg); void fsm_msgDecryptMessage(DecryptMessage *msg); */ //void fsm_msgPassphraseAck(PassphraseAck *msg); -void fsm_msgEstimateTxSize(EstimateTxSize *msg); void fsm_msgRecoveryDevice(RecoveryDevice *msg); void fsm_msgWordAck(WordAck *msg); void fsm_msgSetU2FCounter(SetU2FCounter *msg); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 940e9388da..55b8ba6ecf 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -97,7 +97,12 @@ CipherKeyValue.iv max_size:16 CipheredKeyValue.value max_size:1024 -EstimateTxSize.coin_name max_size:17 +# deprecated +EstimateTxSize skip_message:true +# EstimateTxSize.coin_name max_size:17 + +# deprecated +TxSize skip_message:true SignTx.coin_name max_size:17 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 04c5d04040..647059d73f 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -12,7 +12,6 @@ const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; const char VerifyMessage_coin_name_default[17] = "Bitcoin"; -const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; const uint32_t SignTx_version_default = 1u; const uint32_t SignTx_lock_time_default = 0u; @@ -26,7 +25,7 @@ const pb_field_t GetFeatures_fields[1] = { PB_LAST_FIELD }; -const pb_field_t Features_fields[19] = { +const pb_field_t Features_fields[20] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), @@ -45,6 +44,7 @@ const pb_field_t Features_fields[19] = { PB_FIELD2( 16, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_cached, imported, 0), PB_FIELD2( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), PB_FIELD2( 18, BOOL , OPTIONAL, STATIC , OTHER, Features, firmware_present, passphrase_cached, 0), + PB_FIELD2( 19, BOOL , OPTIONAL, STATIC , OTHER, Features, needs_backup, firmware_present, 0), PB_LAST_FIELD }; @@ -182,7 +182,7 @@ const pb_field_t LoadDevice_fields[9] = { PB_LAST_FIELD }; -const pb_field_t ResetDevice_fields[8] = { +const pb_field_t ResetDevice_fields[9] = { PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), @@ -190,6 +190,11 @@ const pb_field_t ResetDevice_fields[8] = { PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, u2f_counter, label, 0), + PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, skip_backup, u2f_counter, 0), + PB_LAST_FIELD +}; + +const pb_field_t BackupDevice_fields[1] = { PB_LAST_FIELD }; @@ -262,18 +267,6 @@ const pb_field_t CipheredKeyValue_fields[2] = { PB_LAST_FIELD }; -const pb_field_t EstimateTxSize_fields[4] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, EstimateTxSize, outputs_count, outputs_count, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, EstimateTxSize, inputs_count, outputs_count, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, EstimateTxSize, coin_name, inputs_count, &EstimateTxSize_coin_name_default), - PB_LAST_FIELD -}; - -const pb_field_t TxSize_fields[2] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxSize, tx_size, tx_size, 0), - PB_LAST_FIELD -}; - const pb_field_t SignTx_fields[6] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), @@ -420,7 +413,7 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index c474cfef0c..5a3d3f9b56 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -42,6 +42,7 @@ typedef enum _MessageType { MessageType_MessageType_ButtonAck = 27, MessageType_MessageType_GetAddress = 29, MessageType_MessageType_Address = 30, + MessageType_MessageType_BackupDevice = 34, MessageType_MessageType_EntropyRequest = 35, MessageType_MessageType_EntropyAck = 36, MessageType_MessageType_SignMessage = 38, @@ -82,6 +83,10 @@ typedef enum _MessageType { } MessageType; /* Struct definitions */ +typedef struct _BackupDevice { + uint8_t dummy_field; +} BackupDevice; + typedef struct _ButtonAck { uint8_t dummy_field; } ButtonAck; @@ -302,13 +307,6 @@ typedef struct _EntropyAck { EntropyAck_entropy_t entropy; } EntropyAck; -typedef struct _EstimateTxSize { - uint32_t outputs_count; - uint32_t inputs_count; - bool has_coin_name; - char coin_name[17]; -} EstimateTxSize; - typedef struct { size_t size; uint8_t bytes[20]; @@ -461,6 +459,8 @@ typedef struct _Features { bool passphrase_cached; bool has_firmware_present; bool firmware_present; + bool has_needs_backup; + bool needs_backup; } Features; typedef struct _GetAddress { @@ -602,6 +602,8 @@ typedef struct _ResetDevice { char label[33]; bool has_u2f_counter; uint32_t u2f_counter; + bool has_skip_backup; + bool skip_backup; } ResetDevice; typedef struct _SetU2FCounter { @@ -687,11 +689,6 @@ typedef struct _TxRequest { TxRequestSerializedType serialized; } TxRequest; -typedef struct _TxSize { - bool has_tx_size; - uint32_t tx_size; -} TxSize; - typedef struct { size_t size; uint8_t bytes[65]; @@ -732,7 +729,6 @@ extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; extern const char SignMessage_coin_name_default[17]; extern const char VerifyMessage_coin_name_default[17]; -extern const char EstimateTxSize_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const uint32_t SignTx_version_default; extern const uint32_t SignTx_lock_time_default; @@ -740,7 +736,7 @@ extern const uint32_t SignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_default {false, 0} @@ -764,7 +760,8 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumAddress_init_default {{0, {0}}} #define WipeDevice_init_default {0} #define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0, false, 0} -#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0} +#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0, false, 0} +#define BackupDevice_init_default {0} #define EntropyRequest_init_default {0} #define EntropyAck_init_default {false, {0, {0}}} #define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0, false, 0} @@ -775,8 +772,6 @@ extern const uint32_t SignTx_lock_time_default; #define MessageSignature_init_default {false, "", false, {0, {0}}} #define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_default {false, {0, {0}}} -#define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} -#define TxSize_init_default {false, 0} #define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} #define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} #define TxAck_init_default {false, TransactionType_init_default} @@ -799,7 +794,7 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ChangePin_init_zero {false, 0} @@ -823,7 +818,8 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumAddress_init_zero {{0, {0}}} #define WipeDevice_init_zero {0} #define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0, false, 0} -#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0} +#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} +#define BackupDevice_init_zero {0} #define EntropyRequest_init_zero {0} #define EntropyAck_init_zero {false, {0, {0}}} #define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0, false, 0} @@ -834,8 +830,6 @@ extern const uint32_t SignTx_lock_time_default; #define MessageSignature_init_zero {false, "", false, {0, {0}}} #define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} #define CipheredKeyValue_init_zero {false, {0, {0}}} -#define EstimateTxSize_init_zero {0, 0, false, ""} -#define TxSize_init_zero {false, 0} #define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} #define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero} @@ -898,9 +892,6 @@ extern const uint32_t SignTx_lock_time_default; #define ECDHSessionKey_session_key_tag 1 #define Entropy_entropy_tag 1 #define EntropyAck_entropy_tag 1 -#define EstimateTxSize_outputs_count_tag 1 -#define EstimateTxSize_inputs_count_tag 2 -#define EstimateTxSize_coin_name_tag 3 #define EthereumAddress_address_tag 1 #define EthereumGetAddress_address_n_tag 1 #define EthereumGetAddress_show_display_tag 2 @@ -938,6 +929,7 @@ extern const uint32_t SignTx_lock_time_default; #define Features_pin_cached_tag 16 #define Features_passphrase_cached_tag 17 #define Features_firmware_present_tag 18 +#define Features_needs_backup_tag 19 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 @@ -986,6 +978,7 @@ extern const uint32_t SignTx_lock_time_default; #define ResetDevice_language_tag 5 #define ResetDevice_label_tag 6 #define ResetDevice_u2f_counter_tag 7 +#define ResetDevice_skip_backup_tag 8 #define SetU2FCounter_u2f_counter_tag 1 #define SignIdentity_identity_tag 1 #define SignIdentity_challenge_hidden_tag 2 @@ -1007,7 +1000,6 @@ extern const uint32_t SignTx_lock_time_default; #define TxRequest_request_type_tag 1 #define TxRequest_details_tag 2 #define TxRequest_serialized_tag 3 -#define TxSize_tx_size_tag 1 #define VerifyMessage_address_tag 1 #define VerifyMessage_signature_tag 2 #define VerifyMessage_message_tag 3 @@ -1018,7 +1010,7 @@ extern const uint32_t SignTx_lock_time_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; extern const pb_field_t GetFeatures_fields[1]; -extern const pb_field_t Features_fields[19]; +extern const pb_field_t Features_fields[20]; extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[5]; extern const pb_field_t ChangePin_fields[2]; @@ -1042,7 +1034,8 @@ extern const pb_field_t Address_fields[2]; extern const pb_field_t EthereumAddress_fields[2]; extern const pb_field_t WipeDevice_fields[1]; extern const pb_field_t LoadDevice_fields[9]; -extern const pb_field_t ResetDevice_fields[8]; +extern const pb_field_t ResetDevice_fields[9]; +extern const pb_field_t BackupDevice_fields[1]; extern const pb_field_t EntropyRequest_fields[1]; extern const pb_field_t EntropyAck_fields[2]; extern const pb_field_t RecoveryDevice_fields[10]; @@ -1053,8 +1046,6 @@ extern const pb_field_t VerifyMessage_fields[5]; extern const pb_field_t MessageSignature_fields[3]; extern const pb_field_t CipherKeyValue_fields[8]; extern const pb_field_t CipheredKeyValue_fields[2]; -extern const pb_field_t EstimateTxSize_fields[4]; -extern const pb_field_t TxSize_fields[2]; extern const pb_field_t SignTx_fields[6]; extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxAck_fields[2]; @@ -1079,7 +1070,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (257 + 8*CoinType_size) +#define Features_size (260 + 8*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ChangePin_size 2 @@ -1103,7 +1094,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define EthereumAddress_size 22 #define WipeDevice_size 0 #define LoadDevice_size (326 + HDNodeType_size) -#define ResetDevice_size 72 +#define ResetDevice_size 74 +#define BackupDevice_size 0 #define EntropyRequest_size 0 #define EntropyAck_size 131 #define RecoveryDevice_size 80 @@ -1114,8 +1106,6 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define MessageSignature_size 110 #define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 -#define EstimateTxSize_size 31 -#define TxSize_size 6 #define SignTx_size 43 #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index 120b965c94..aa71e0507d 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -26,7 +26,7 @@ { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, { 'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *)) fsm_msgVerifyMessage }, // Message PassphraseAck is used in tiny mode - { 'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *)) fsm_msgEstimateTxSize }, + // Message EstimateTxSize is deprecated { 'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *)) fsm_msgRecoveryDevice }, { 'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *)) fsm_msgWordAck }, // Message EncryptMessage is deprecated @@ -54,7 +54,7 @@ { 'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0 }, { 'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0 }, { 'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0 }, + // Message TxSize is deprecated { 'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0 }, { 'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0 }, // Message EncryptedMessage is deprecated diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index fd33888094..42b05bbca1 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -5,7 +5,7 @@ -const pb_field_t Storage_fields[12] = { +const pb_field_t Storage_fields[13] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -17,6 +17,7 @@ const pb_field_t Storage_fields[12] = { PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), PB_FIELD2( 11, UINT32 , OPTIONAL, STATIC , OTHER, Storage, u2f_counter, homescreen, 0), + PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Storage, needs_backup, u2f_counter, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index 7e8f5840ff..c8f20325c4 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -39,13 +39,15 @@ typedef struct _Storage { Storage_homescreen_t homescreen; bool has_u2f_counter; uint32_t u2f_counter; + bool has_needs_backup; + bool needs_backup; } Storage; /* Default values for struct fields */ /* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0} +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 @@ -59,12 +61,13 @@ typedef struct _Storage { #define Storage_imported_tag 9 #define Storage_homescreen_tag 10 #define Storage_u2f_counter_tag 11 +#define Storage_needs_backup_tag 12 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[12]; +extern const pb_field_t Storage_fields[13]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (1365 + HDNodeType_size) +#define Storage_size (1367 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/transaction.h b/firmware/transaction.h index 06d07f765e..5c80904fcf 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -72,6 +72,4 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); -uint32_t transactionEstimateSizeKb(uint32_t inputs, uint32_t outputs); - #endif diff --git a/vendor/trezor-common b/vendor/trezor-common index ae1900a2bc..68f5246e2f 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit ae1900a2bcc9a140f636d9ef2c5e029fe397441a +Subproject commit 68f5246e2f6e8a7265c297b05958df4e2b2b2ad9 From 9298e4d9e39f4f8e171de2b2ed631b076a696fd1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jun 2017 19:17:40 +0200 Subject: [PATCH 0474/1154] reset: make backup workflow independent of initialization --- firmware/fsm.c | 11 +++++++++- firmware/fsm.h | 1 + firmware/protob/messages_map.h | 1 + firmware/recovery.c | 2 +- firmware/reset.c | 38 +++++++++++++++++++++++++++------- firmware/reset.h | 3 ++- 6 files changed, 46 insertions(+), 10 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 60a7082b1c..4cd9babc57 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -442,10 +442,19 @@ void fsm_msgResetDevice(ResetDevice *msg) msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0 + msg->has_u2f_counter ? msg->u2f_counter : 0, + msg->has_skip_backup ? msg->skip_backup : false ); } +void fsm_msgBackupDevice(BackupDevice *msg) +{ + CHECK_INITIALIZED + + (void)msg; + reset_backup(); +} + void fsm_msgSignTx(SignTx *msg) { CHECK_INITIALIZED diff --git a/firmware/fsm.h b/firmware/fsm.h index f9e297bf84..6d4fc06cf7 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -36,6 +36,7 @@ void fsm_msgGetEntropy(GetEntropy *msg); void fsm_msgGetPublicKey(GetPublicKey *msg); void fsm_msgLoadDevice(LoadDevice *msg); void fsm_msgResetDevice(ResetDevice *msg); +void fsm_msgBackupDevice(BackupDevice *msg); void fsm_msgSignTx(SignTx *msg); //void fsm_msgPinMatrixAck(PinMatrixAck *msg); void fsm_msgCancel(Cancel *msg); diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index aa71e0507d..ab6ca97bf2 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -22,6 +22,7 @@ { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, // Message ButtonAck is used in tiny mode { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, + { 'n', 'i', MessageType_MessageType_BackupDevice, BackupDevice_fields, (void (*)(void *)) fsm_msgBackupDevice }, { 'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *)) fsm_msgEntropyAck }, { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, { 'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *)) fsm_msgVerifyMessage }, diff --git a/firmware/recovery.c b/firmware/recovery.c index 878736d37c..ee2903ff0a 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -179,7 +179,7 @@ static void recovery_done(void) { _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); protectButton(ButtonRequestType_ButtonRequest_Other, true); } - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid mnemonic, are words in correct order?")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); } awaiting_word = 0; layoutHome(); diff --git a/firmware/reset.c b/firmware/reset.c index 4428753e48..d200fc0e3c 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -33,12 +33,14 @@ static uint32_t strength; static uint8_t int_entropy[32]; static bool awaiting_entropy = false; +static bool skip_backup = false; -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter) +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup) { if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; + skip_backup = _skip_backup; random_buffer(int_entropy, 32); @@ -75,8 +77,6 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect awaiting_entropy = true; } -static char current_word[10], current_word_display[11]; - void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { if (!awaiting_entropy) { @@ -92,6 +92,33 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memset(int_entropy, 0, 32); awaiting_entropy = false; + storage.has_mnemonic = true; + storage.has_needs_backup = true; + storage.needs_backup = true; + + if (skip_backup) { + storage_commit(); + fsm_sendSuccess(_("Device successfully initialized")); + layoutHome(); + } else { + reset_backup(); + } + +} + +static char current_word[10], current_word_display[11]; + +void reset_backup(void) +{ + if (!storage.has_needs_backup || !storage.needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + return; + } else { + storage.has_needs_backup = false; + storage.needs_backup = false; + storage_commit(); + } + int pass, word_pos, i = 0, j; for (pass = 0; pass < 2; pass++) { @@ -146,10 +173,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) } } } - - storage.has_mnemonic = true; - storage_commit(); - fsm_sendSuccess(_("Device reset")); + fsm_sendSuccess(_("Seed successfully backed up")); layoutHome(); } diff --git a/firmware/reset.h b/firmware/reset.h index 1cb8575edc..26ac06895f 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -23,8 +23,9 @@ #include #include -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter); +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool skip_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); +void reset_backup(void); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); From 97fa33de46036f7b1f0acdf9a6e43199499b3858 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jun 2017 19:45:12 +0200 Subject: [PATCH 0475/1154] reset: show needs backup signed when storage is not backed up --- firmware/layout2.c | 4 ++++ firmware/reset.c | 2 +- firmware/storage.c | 6 ++++++ firmware/storage.h | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 64a8fa2034..0b7ecced5d 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -83,6 +83,10 @@ void layoutHome(void) oledDrawBitmap(40, 0, &bmp_logo64); } } + if (storage_needsBackup()) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(0, "NEEDS BACKUP!"); + } oledRefresh(); // Reset lock screen timeout diff --git a/firmware/reset.c b/firmware/reset.c index d200fc0e3c..ff2dd3918b 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -110,7 +110,7 @@ static char current_word[10], current_word_display[11]; void reset_backup(void) { - if (!storage.has_needs_backup || !storage.needs_backup) { + if (!storage_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } else { diff --git a/firmware/storage.c b/firmware/storage.c index 0976c44fee..ad3aea4d26 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -580,6 +580,12 @@ bool storage_isInitialized(void) return storage.has_node || storage.has_mnemonic; } +bool storage_needsBackup(void) +{ + return storage.has_needs_backup && storage.needs_backup; +} + + uint32_t storage_nextU2FCounter(void) { uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); diff --git a/firmware/storage.h b/firmware/storage.h index 89e2cfc4fe..d72b4d33d3 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -68,6 +68,8 @@ void storage_setU2FCounter(uint32_t u2fcounter); bool storage_isInitialized(void); +bool storage_needsBackup(void); + extern Storage storage; extern char storage_uuid_str[25]; From b65068c15926013deeb0aa326888ea1b440a0def Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 26 Jun 2017 19:51:43 +0200 Subject: [PATCH 0476/1154] reset: add Features.needs_backup --- firmware/fsm.c | 1 + firmware/reset.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4cd9babc57..6349fc664d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -234,6 +234,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); + resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/reset.c b/firmware/reset.c index ff2dd3918b..89b62cf252 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -114,7 +114,7 @@ void reset_backup(void) fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } else { - storage.has_needs_backup = false; + storage.has_needs_backup = true; storage.needs_backup = false; storage_commit(); } From 8fa3ce7e1491bd79d47eff10ffac758fcaf5c45e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 28 Jun 2017 11:25:47 +0200 Subject: [PATCH 0477/1154] reset: distinguish between separated call and joined call, mark backup as done only when performed completely --- firmware/fsm.c | 2 +- firmware/reset.c | 24 ++++++++++++++++-------- firmware/reset.h | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 6349fc664d..b3e69e9467 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -453,7 +453,7 @@ void fsm_msgBackupDevice(BackupDevice *msg) CHECK_INITIALIZED (void)msg; - reset_backup(); + reset_backup(true); } void fsm_msgSignTx(SignTx *msg) diff --git a/firmware/reset.c b/firmware/reset.c index 89b62cf252..ae00bbe83c 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -101,22 +101,19 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendSuccess(_("Device successfully initialized")); layoutHome(); } else { - reset_backup(); + reset_backup(false); } } static char current_word[10], current_word_display[11]; -void reset_backup(void) +// separated == true if called as a separate workflow via BackupMessage +void reset_backup(bool separated) { if (!storage_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; - } else { - storage.has_needs_backup = true; - storage.needs_backup = false; - storage_commit(); } int pass, word_pos, i = 0, j; @@ -166,14 +163,25 @@ void reset_backup(void) } } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { - storage_reset(); + if (!separated) { + storage_reset(); + } layoutHome(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } } } - fsm_sendSuccess(_("Seed successfully backed up")); + + storage.has_needs_backup = true; + storage.needs_backup = false; + storage_commit(); + + if (separated) { + fsm_sendSuccess(_("Seed successfully backed up")); + } else { + fsm_sendSuccess(_("Device successfully initialized")); + } layoutHome(); } diff --git a/firmware/reset.h b/firmware/reset.h index 26ac06895f..65b0230890 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -25,7 +25,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool skip_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); -void reset_backup(void); +void reset_backup(bool separated); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); From 3c0a9c2a87c0ebea9b08908b506adfad3b9086f3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 29 Jun 2017 14:16:34 +0200 Subject: [PATCH 0478/1154] update submodules --- vendor/libopencm3 | 2 +- vendor/trezor-qrenc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/libopencm3 b/vendor/libopencm3 index 383fafc862..b76d853a72 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit 383fafc862c0d47f30965f00409d03a328049278 +Subproject commit b76d853a723d39bbc083495bb7460cf3f071476c diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 392ee5654f..91115b1806 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 392ee5654f4862f2e2b49b69a4e802997715d34f +Subproject commit 91115b1806aa506d819c0063893984a28a5ae3a5 From 2bf807878dfac4cc8e70f99c739d01a811d4705f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 29 Jun 2017 17:31:23 +0200 Subject: [PATCH 0479/1154] bootloader: add SelfTest --- bootloader/usb.c | 4 ++++ firmware/protob/messages.options | 1 + firmware/protob/messages.pb.h | 1 + firmware/protob/messages_map.h | 1 + vendor/trezor-common | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 9d5675b14c..a266833528 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -318,6 +318,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) send_msg_success(dev); return; } + if (msg_id == 0x0020) { // SelfTest message (id 32) + send_msg_success(dev); + return; + } } if (flash_state == STATE_OPEN) { diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 55b8ba6ecf..ca54a39419 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -140,6 +140,7 @@ SimpleSignTx skip_message:true FirmwareErase skip_message:true FirmwareRequest skip_message:true FirmwareUpload skip_message:true +SelfTest skip_message:true # used only in debug firmware diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 5a3d3f9b56..d232504fe2 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -42,6 +42,7 @@ typedef enum _MessageType { MessageType_MessageType_ButtonAck = 27, MessageType_MessageType_GetAddress = 29, MessageType_MessageType_Address = 30, + MessageType_MessageType_SelfTest = 32, MessageType_MessageType_BackupDevice = 34, MessageType_MessageType_EntropyRequest = 35, MessageType_MessageType_EntropyAck = 36, diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index ab6ca97bf2..1fd9a39d22 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -22,6 +22,7 @@ { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, // Message ButtonAck is used in tiny mode { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, + // Message SelfTest is used in bootloader mode only { 'n', 'i', MessageType_MessageType_BackupDevice, BackupDevice_fields, (void (*)(void *)) fsm_msgBackupDevice }, { 'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *)) fsm_msgEntropyAck }, { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, diff --git a/vendor/trezor-common b/vendor/trezor-common index 68f5246e2f..c2a40f4b67 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 68f5246e2f6e8a7265c297b05958df4e2b2b2ad9 +Subproject commit c2a40f4b675ed3bf137360a6fa22ff72775f38ff From 425341ba44fab7c88b83bc03b3544ff34b3d29b2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 29 Jun 2017 18:11:19 +0200 Subject: [PATCH 0480/1154] bootloader: add small test to SelfTest (erase/restore metadata), small refactor --- bootloader/usb.c | 64 +++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index a266833528..9fb33514f3 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -282,15 +282,36 @@ static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) , 64) != 64) {} } +static void erase_metadata_sectors(void) +{ + flash_unlock(); + for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_lock(); +} + +static void backup_metadata(uint8_t *backup) +{ + memcpy(backup, (void *)FLASH_META_START, FLASH_META_LEN); +} + +static void restore_metadata(const uint8_t *backup) +{ + flash_unlock(); + for (int i = 0; i < FLASH_META_LEN / 4; i++) { + const uint32_t *w = (const uint32_t *)(backup + i * 4); + flash_program_word(FLASH_META_START + i * 4, *w); + } + flash_lock(); +} + static void hid_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); - uint8_t *p; static uint8_t towrite[4] __attribute__((aligned(4))); static int wi; - int i; - uint32_t *w; static SHA256_CTX ctx; if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; @@ -319,6 +340,12 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } if (msg_id == 0x0020) { // SelfTest message (id 32) + // backup metadata + backup_metadata(meta_backup); + // erase metadata area + erase_metadata_sectors(); + // copy metadata back + restore_metadata(meta_backup); send_msg_success(dev); return; } @@ -335,16 +362,16 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } if (!firmware_present || button.YesUp) { // backup metadata - memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); + backup_metadata(meta_backup); flash_unlock(); // erase metadata area - for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000*(i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } // erase code area - for (i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000*(i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } layoutProgress("INSTALLING ... Please wait", 0); @@ -370,7 +397,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } // read payload length - p = buf + 10; + uint8_t *p = buf + 10; flash_len = readprotobufint(&p); if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big send_msg_failure(dev); @@ -387,7 +414,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) towrite[wi] = *p; wi++; if (wi == 4) { - w = (uint32_t *)towrite; + const uint32_t *w = (uint32_t *)towrite; flash_program_word(FLASH_META_START + flash_pos, *w); flash_pos += 4; wi = 0; @@ -407,7 +434,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); return; } - p = buf + 1; + const uint8_t *p = buf + 1; if (flash_anim % 32 == 4) { layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); } @@ -417,7 +444,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) towrite[wi] = *p; wi++; if (wi == 4) { - w = (uint32_t *)towrite; + const uint32_t *w = (const uint32_t *)towrite; if (flash_pos < FLASH_META_DESC_LEN) { flash_program_word(FLASH_META_START + flash_pos, *w); // the first 256 bytes of firmware is metadata descriptor } else { @@ -466,17 +493,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) meta_backup[2] = 0; meta_backup[3] = 0; } - flash_unlock(); // erase storage - for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // copy it back - for (i = 0; i < FLASH_META_LEN / 4; i++) { - w = (uint32_t *)(meta_backup + i * 4); - flash_program_word(FLASH_META_START + i * 4, *w); - } - flash_lock(); + erase_metadata_sectors(); + // copy storage from backup + restore_metadata(meta_backup); } else { // replace "TRZR" in header with 0000 when hash not confirmed if (!hash_check_ok) { From 87b815d6ec5423c86c291c0d055e2486a2eea544 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 29 Jun 2017 18:36:19 +0200 Subject: [PATCH 0481/1154] bootloader: selftest now writes and checks various bit patterns --- bootloader/usb.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 9fb33514f3..ef574b7494 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -340,13 +340,40 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } if (msg_id == 0x0020) { // SelfTest message (id 32) + const uint32_t patterns[] = { 0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x66666666, 0x99999999, 0x33333333, 0xCCCCCCCC }; + // backup metadata backup_metadata(meta_backup); - // erase metadata area - erase_metadata_sectors(); + + // write/read test patterns + sha256_Init(&ctx); + + for (int p = 0; p < 8; p++) { + erase_metadata_sectors(); + flash_unlock(); + for (int i = 0; i < FLASH_META_LEN / 4; i++) { + flash_program_word(FLASH_META_START + i * 4, patterns[p]); + } + flash_lock(); + sha256_Update(&ctx, (unsigned char *)FLASH_META_START, FLASH_META_LEN); + } + // copy metadata back + erase_metadata_sectors(); restore_metadata(meta_backup); - send_msg_success(dev); + + // compare against known hash + uint8_t hash[32]; + sha256_Final(&ctx, hash); + + // hash computed via the following Python3 script: + // hashlib.sha256(b''.join([binascii.unhexlify(c * 2 * 32768) for c in '0F5A693C'])).hexdigest() + + if (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)) { + send_msg_success(dev); + } else { + send_msg_failure(dev); + } return; } } @@ -458,8 +485,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_lock(); // flashing done if (flash_pos == flash_len) { - sha256_Update(&ctx, (unsigned char*) FLASH_APP_START, - flash_len - FLASH_META_DESC_LEN); + sha256_Update(&ctx, (unsigned char *)FLASH_APP_START, flash_len - FLASH_META_DESC_LEN); flash_state = STATE_CHECK; send_msg_buttonrequest_firmwarecheck(dev); } From d15dd7c94495acc177314da14bac0ccbe0661e5f Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Fri, 30 Jun 2017 09:55:12 +0300 Subject: [PATCH 0482/1154] recovery: zero new_mnemonic memory before returning to the user --- firmware/recovery.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index ee2903ff0a..fcbc606b88 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -144,6 +144,7 @@ static void recovery_done(void) { // Update mnemonic on storage. storage.has_mnemonic = true; strlcpy(storage.mnemonic, new_mnemonic, sizeof(new_mnemonic)); + memset(new_mnemonic, 0, sizeof(new_mnemonic)); if (!enforce_wordlist) { // not enforcing => mark storage as imported storage.has_imported = true; @@ -153,7 +154,9 @@ static void recovery_done(void) { fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - if (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)) { + bool match = (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)); + memset(new_mnemonic, 0, sizeof(new_mnemonic)); + if (match) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, _("The seed is valid"), _("and MATCHES"), @@ -172,6 +175,7 @@ static void recovery_done(void) { } } else { // New mnemonic is invalid. + memset(new_mnemonic, 0, sizeof(new_mnemonic)); if (!dry_run) { storage_reset(); } else { From 90d214eb4bffa103d44c679737f1ef66abdc4a9b Mon Sep 17 00:00:00 2001 From: mruddy Date: Fri, 30 Jun 2017 09:02:47 -0400 Subject: [PATCH 0483/1154] add ability for developers to easily avoid locking their flash memory sectors --- Makefile.include | 6 ++++++ memory.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Makefile.include b/Makefile.include index 15a7d9014e..773be5037f 100644 --- a/Makefile.include +++ b/Makefile.include @@ -59,6 +59,12 @@ else LDSCRIPT = $(TOP_DIR)/memory.ld endif +ifeq ($(MEMORY_PROTECT), 0) +CFLAGS += -DMEMORY_PROTECT=0 +else +CFLAGS += -DMEMORY_PROTECT=1 +endif + LDFLAGS += --static \ -Wl,--start-group \ -lc \ diff --git a/memory.c b/memory.c index f779c2037c..33bd007c6b 100644 --- a/memory.c +++ b/memory.c @@ -27,6 +27,7 @@ void memory_protect(void) { +#if MEMORY_PROTECT // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf // Section 2.6 Option bytes // set RDP level 2 WRP for sectors 0 and 1 @@ -45,6 +46,7 @@ void memory_protect(void) // Bit 0 OPTLOCK: Option lock: ignored by flash_program_option_bytes flash_program_option_bytes(0x0FFCCCEC); flash_lock_option_bytes(); +#endif } int memory_bootloader_hash(uint8_t *hash) From 0f42f64dfd7dec50893de6cb01cdcd86b03f182d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 30 Jun 2017 16:52:00 +0200 Subject: [PATCH 0484/1154] bootloader: do not show fingerprint on very first flash; refactor firmware_present, introduce brand_new_firmware --- bootloader/bootloader.c | 41 ++++++++++++++++++---------------------- bootloader/bootloader.h | 2 ++ bootloader/usb.c | 42 ++++++++++++++++++++--------------------- bootloader/usb.h | 3 +-- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 0e0bec13ae..e165c53ddf 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -84,13 +84,27 @@ void load_app(void) (*(void (**)())(FLASH_APP_START + 4))(); } -int firmware_present; +bool firmware_present(void) +{ +#ifndef APPVER + if (memcmp((const void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match + return false; + } + if (*((const uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB + return false; + } + if (*((const uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size + return false; + } +#endif + return true; +} void bootloader_loop(void) { oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); - if (firmware_present) { + if (firmware_present()) { oledDrawString(52, 0, "TREZOR"); static char serial[25]; fill_serialno_fixed(serial); @@ -106,24 +120,7 @@ void bootloader_loop(void) } oledRefresh(); - usbInit(); - usbLoop(); -} - -int check_firmware_sanity(void) -{ -#ifndef APPVER - if (memcmp((const void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match - return 0; - } - if (*((const uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB - return 0; - } - if (*((const uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size - return 0; - } -#endif - return 1; + usbLoop(firmware_present()); } uint32_t __stack_chk_guard; @@ -145,14 +142,12 @@ int main(void) oledInit(); #endif - firmware_present = check_firmware_sanity(); - #ifndef APPVER // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); - if (firmware_present && unpressed) { + if (firmware_present() && unpressed) { oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 93215356b0..45e61676d7 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -31,8 +31,10 @@ #define VERSION_MINOR_CHAR "\x03" #define VERSION_PATCH_CHAR "\x01" +#include #include "memory.h" void layoutFirmwareHash(const uint8_t *hash); +bool firmware_present(void); #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index ef574b7494..8901308138 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -37,6 +37,8 @@ #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) +static bool brand_new_firmware; + static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, @@ -214,8 +216,6 @@ static void send_msg_failure(usbd_device *dev) , 64) != 64) {} } -extern int firmware_present; - static void send_msg_features(usbd_device *dev) { // response: Features message (id 17), payload len 30 @@ -225,7 +225,7 @@ static void send_msg_features(usbd_device *dev) // - patch_version = VERSION_PATCH // - bootloader_mode = True // - firmware_present = True/False - if (firmware_present) { + if (brand_new_firmware) { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, // header "?##" @@ -239,7 +239,7 @@ static void send_msg_features(usbd_device *dev) "\x18" VERSION_MINOR_CHAR "\x20" VERSION_PATCH_CHAR "\x28" "\x01" - "\x90\x01" "\x01" + "\x90\x01" "\x00" // padding "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} @@ -257,7 +257,7 @@ static void send_msg_features(usbd_device *dev) "\x18" VERSION_MINOR_CHAR "\x20" VERSION_PATCH_CHAR "\x28" "\x01" - "\x90\x01" "\x00" + "\x90\x01" "\x01" // padding "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} @@ -380,14 +380,14 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_OPEN) { if (msg_id == 0x0006) { // FirmwareErase message (id 6) - if (firmware_present) { + if (!brand_new_firmware) { layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); do { delay(100000); buttonUpdate(); } while (!button.YesUp && !button.NoUp); } - if (!firmware_present || button.YesUp) { + if (brand_new_firmware || button.YesUp) { // backup metadata backup_metadata(meta_backup); flash_unlock(); @@ -498,13 +498,16 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } uint8_t hash[32]; sha256_Final(&ctx, hash); - layoutFirmwareHash(hash); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - bool hash_check_ok = button.YesUp; + if (!brand_new_firmware) { + layoutFirmwareHash(hash); + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + } + + bool hash_check_ok = brand_new_firmware || button.YesUp; layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); @@ -563,12 +566,6 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) static usbd_device *usbd_dev; static uint8_t usbd_control_buffer[128]; -void usbInit(void) -{ - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); -} - void checkButtons(void) { static bool btn_left = false, btn_right = false, btn_final = false; @@ -598,11 +595,14 @@ void checkButtons(void) } } -void usbLoop(void) +void usbLoop(bool firmware_present) { + brand_new_firmware = !firmware_present; + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); for (;;) { usbd_poll(usbd_dev); - if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { + if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { checkButtons(); } } diff --git a/bootloader/usb.h b/bootloader/usb.h index e054a488b5..5b2782c878 100644 --- a/bootloader/usb.h +++ b/bootloader/usb.h @@ -20,7 +20,6 @@ #ifndef __USB_H__ #define __USB_H__ -void usbInit(void); -void usbLoop(void); +void usbLoop(bool firmware_present); #endif From f274d8cd73cb46bfbb402542409ea41759d6e1cd Mon Sep 17 00:00:00 2001 From: mruddy Date: Fri, 30 Jun 2017 13:49:30 -0400 Subject: [PATCH 0485/1154] fix bootloader stack protector fault --- bootloader/bootloader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index e165c53ddf..4b9f757d72 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -76,12 +76,15 @@ void show_unofficial_warning(const uint8_t *hash) // everything is OK, user pressed 2x Continue -> continue program } -void load_app(void) +void __attribute__((noreturn)) load_app(void) { // jump to app SCB_VTOR = FLASH_APP_START; // & 0xFFFF; __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); (*(void (**)())(FLASH_APP_START + 4))(); + // forever loop to indicate to the compiler that this function does not return. + // this avoids the stack protector injecting code that faults with the new stack. + for (;;); } bool firmware_present(void) From 4603b0c8005a201adb7a8516a158447e9e0a5563 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 1 Jul 2017 16:22:22 +0200 Subject: [PATCH 0486/1154] bootloader: subtle changes in bootloader.c and fastflash.c to make them more similar --- bootloader/bootloader.c | 7 ++++++- firmware/fastflash.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 4b9f757d72..cb891a7bba 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -78,10 +78,15 @@ void show_unofficial_warning(const uint8_t *hash) void __attribute__((noreturn)) load_app(void) { - // jump to app + // Relocate vector tables SCB_VTOR = FLASH_APP_START; // & 0xFFFF; + + // Set stack pointer __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); + + // Jump to address (*(void (**)())(FLASH_APP_START + 4))(); + // forever loop to indicate to the compiler that this function does not return. // this avoids the stack protector injecting code that faults with the new stack. for (;;); diff --git a/firmware/fastflash.c b/firmware/fastflash.c index 85aef6ffb9..d2bc1b326d 100644 --- a/firmware/fastflash.c +++ b/firmware/fastflash.c @@ -29,11 +29,14 @@ extern uint32_t __bootloader_loadaddr__[]; extern uint32_t __bootloader_runaddr__[]; extern uint8_t __bootloader_size__[]; -void load_bootloader() { +void load_bootloader(void) +{ memcpy(__bootloader_runaddr__, __bootloader_loadaddr__, (size_t) __bootloader_size__); } -void run_bootloader() { +// adapted from load_app() in bootloader.c +void __attribute__((noreturn)) run_bootloader(void) +{ // Relocate vector tables SCB_VTOR = (uint32_t) __bootloader_runaddr__; @@ -43,5 +46,7 @@ void run_bootloader() { // Jump to address ((void (*)(void))(__bootloader_runaddr__[1]))(); - while (true); + // forever loop to indicate to the compiler that this function does not return. + // this avoids the stack protector injecting code that faults with the new stack. + for (;;); } From 95db902d28d4e82cdcdf1e279ad68068a2854fd0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Jul 2017 13:13:07 +0200 Subject: [PATCH 0487/1154] ethereum: update token list --- firmware/ethereum_tokens-gen.py | 2 +- firmware/ethereum_tokens.c | 25 +++++++++++++++++-------- firmware/ethereum_tokens.h | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 3f9181d057..11ab30bb0d 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -17,7 +17,7 @@ def get_tokens(chain): def print_tokens(chain, chain_id): tokens = get_tokens(chain) - for t in tokens: + for t in sorted(tokens, key=lambda x: x['symbol'].upper()): address, symbol, decimal = t['address'], t['symbol'], t['decimal'] s = (chain_id, symbol) if s in subst: diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index cf3de91b43..42a071908d 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -3,75 +3,84 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, + { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, - { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, + { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, + { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, + { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, { 1, "\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, + { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, + { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, { 1, "\xbb\xb1\xbd\x2d\x74\x1f\x05\xe1\x44\xe6\xc4\x51\x76\x76\xa1\x55\x54\xfd\x4b\x8d", " FUN", 8}, { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, - { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, { 1, "\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, + { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, - { 1, "\xb0\x4c\xfa\x8a\x26\xd6\x02\xfb\x50\x23\x2c\xee\x0d\xaf\x29\x06\x02\x64\xe0\x4b", " MCO", 8}, - { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, + { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, { 1, "\xd0\xb1\x71\xeb\x0b\x0f\x2c\xbd\x35\xcc\xd9\x7c\xdc\x5e\xdc\x3f\xfe\x48\x71\xaa", " MDA", 18}, + { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, - { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, + { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, { 1, "\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, - { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, + { 1, "\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97", " SKO1", 18}, + { 1, "\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04", " SNC", 18}, { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, + { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, + { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, + { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, + { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, { 1, "\x82\x66\x57\x64\xea\x0b\x58\x15\x7e\x1e\x5e\x9b\xab\x32\xf6\x8c\x76\xec\x0c\xdf", " VSM", 0}, - { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, - { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 1251cc7b5a..46910b70e3 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 71 +#define TOKENS_COUNT 80 typedef struct { uint8_t chain_id; From 498d689f98a2ec0b440390de124fa1f5d647da52 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Jul 2017 18:23:51 +0200 Subject: [PATCH 0488/1154] fix small issue with GetAddress for non-segwit coins --- firmware/fsm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index b3e69e9467..766b4d9b8c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -635,6 +635,8 @@ void fsm_msgGetAddress(GetAddress *msg) layoutProgress(_("Computing address"), 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); + layoutHome(); + return; } if (msg->has_show_display && msg->show_display) { From f23489050a5900297bcb7812ff18f0c686c03600 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 1 Jul 2017 20:08:26 +0100 Subject: [PATCH 0489/1154] util: Add load_vector_table --- bootloader/bootloader.c | 13 +------------ firmware/fastflash.c | 21 ++++----------------- timer.c | 1 + timer.h | 4 +++- util.h | 17 +++++++++++++++++ 5 files changed, 26 insertions(+), 30 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index cb891a7bba..7d6fe762cc 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -78,18 +78,7 @@ void show_unofficial_warning(const uint8_t *hash) void __attribute__((noreturn)) load_app(void) { - // Relocate vector tables - SCB_VTOR = FLASH_APP_START; // & 0xFFFF; - - // Set stack pointer - __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START)); - - // Jump to address - (*(void (**)())(FLASH_APP_START + 4))(); - - // forever loop to indicate to the compiler that this function does not return. - // this avoids the stack protector injecting code that faults with the new stack. - for (;;); + load_vector_table((const vector_table_t *) FLASH_APP_START); } bool firmware_present(void) diff --git a/firmware/fastflash.c b/firmware/fastflash.c index d2bc1b326d..76f31cfa7a 100644 --- a/firmware/fastflash.c +++ b/firmware/fastflash.c @@ -18,15 +18,14 @@ */ #include "fastflash.h" +#include "util.h" #include #include #include -#include - -extern uint32_t __bootloader_loadaddr__[]; -extern uint32_t __bootloader_runaddr__[]; +extern uint8_t __bootloader_loadaddr__[]; +extern uint8_t __bootloader_runaddr__[]; extern uint8_t __bootloader_size__[]; void load_bootloader(void) @@ -34,19 +33,7 @@ void load_bootloader(void) memcpy(__bootloader_runaddr__, __bootloader_loadaddr__, (size_t) __bootloader_size__); } -// adapted from load_app() in bootloader.c void __attribute__((noreturn)) run_bootloader(void) { - // Relocate vector tables - SCB_VTOR = (uint32_t) __bootloader_runaddr__; - - // Set stack pointer - __asm__ volatile("msr msp, %0":: "r" (__bootloader_runaddr__[0])); - - // Jump to address - ((void (*)(void))(__bootloader_runaddr__[1]))(); - - // forever loop to indicate to the compiler that this function does not return. - // this avoids the stack protector injecting code that faults with the new stack. - for (;;); + load_vector_table((const vector_table_t *) __bootloader_runaddr__); } diff --git a/timer.c b/timer.c index aad29663f9..bd19990049 100644 --- a/timer.c +++ b/timer.c @@ -22,6 +22,7 @@ #include #include +#include /* 1 tick = 1 ms */ volatile uint32_t system_millis; diff --git a/timer.h b/timer.h index 69759c33ff..a8753ee920 100644 --- a/timer.h +++ b/timer.h @@ -17,6 +17,8 @@ * along with this library. If not, see . */ +#ifndef __TIMER_H__ +#define __TIMER_H__ #include @@ -28,4 +30,4 @@ extern uint32_t system_millis_lock_start; void timer_init(void); -void sys_tick_handler(void); +#endif diff --git a/util.h b/util.h index e31c5801c8..ed6aaadc15 100644 --- a/util.h +++ b/util.h @@ -22,6 +22,9 @@ #include +#include +#include + void delay(uint32_t wait); // converts uint32 to hexa (8 digits) @@ -38,4 +41,18 @@ void __attribute__((noreturn)) system_halt(void); // reset system void __attribute__((noreturn)) system_reset(void); +static inline void __attribute__((noreturn)) load_vector_table(const vector_table_t *vector_table) { + // Relocate vector table + SCB_VTOR = (uint32_t) vector_table; + + // Set stack pointer + __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); + + // Jump to address + vector_table->reset(); + + // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) + for (;;); +} + #endif From 8581a9a37aacb5364572cdd8d926d4029a08f43b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Jul 2017 19:18:34 +0200 Subject: [PATCH 0490/1154] bootloader: add UI to SelfTest --- bootloader/usb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bootloader/usb.c b/bootloader/usb.c index 8901308138..d4e15558fa 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -342,6 +342,8 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (msg_id == 0x0020) { // SelfTest message (id 32) const uint32_t patterns[] = { 0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x66666666, 0x99999999, 0x33333333, 0xCCCCCCCC }; + layoutProgress("TESTING ... Please wait", 0); + // backup metadata backup_metadata(meta_backup); @@ -356,6 +358,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } flash_lock(); sha256_Update(&ctx, (unsigned char *)FLASH_META_START, FLASH_META_LEN); + layoutProgress("TESTING ... Please wait", (p * 100) + 100); } // copy metadata back @@ -366,13 +369,17 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) uint8_t hash[32]; sha256_Final(&ctx, hash); + layoutProgress("TESTING ... Please wait", 1000); + // hash computed via the following Python3 script: // hashlib.sha256(b''.join([binascii.unhexlify(c * 2 * 32768) for c in '0F5A693C'])).hexdigest() if (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)) { send_msg_success(dev); + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Test OK", NULL, NULL, NULL, NULL, NULL); } else { send_msg_failure(dev); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Test FAILED", NULL, NULL, NULL, NULL, NULL); } return; } From d4b9ea2287c46a5b87b2a6199f5b698ea735b77b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Jul 2017 19:34:25 +0200 Subject: [PATCH 0491/1154] bootloader: add cpu test --- bootloader/Makefile | 2 -- bootloader/usb.c | 48 +++++++++++++++++++++++++++++++++++------ fastflash/Makefile | 6 ++++++ memory_app_2.0.0.ld | 2 +- memory_app_fastflash.ld | 2 +- 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index 2067813e8a..8c1f18dff6 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -6,8 +6,6 @@ OBJS += usb.o OBJS += ../vendor/trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o -OBJS += ../vendor/trezor-crypto/hmac.o -OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/sha2.o diff --git a/bootloader/usb.c b/bootloader/usb.c index d4e15558fa..968284ca38 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -33,6 +33,8 @@ #include "util.h" #include "signatures.h" #include "sha2.h" +#include "ecdsa.h" +#include "secp256k1.h" #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -340,9 +342,32 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } if (msg_id == 0x0020) { // SelfTest message (id 32) + + // CPU TEST + + layoutProgress("TESTING CPU ...", 0); + + bool status_cpu = true; + + for (int i = 0; i < 10; i++) { + // privkey : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + // pubkey : 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd + // 5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235 + // digest : c84a4cc264100070c8be2acf4072efaadaedfef3d6209c0fe26387e6b1262bbf + // sig: : f7869c679bbed1817052affd0264ccc6486795f6d06d0c187651b8f3863670c8 + // 2ccf89be32a53eb65ea7c007859783d46717986fead0833ec60c5729cdc4a9ee + status_cpu &= (0 == ecdsa_verify_digest(&secp256k1, + (const uint8_t *)"\x04\xa3\x4b\x99\xf2\x2c\x79\x0c\x4e\x36\xb2\xb3\xc2\xc3\x5a\x36\xdb\x06\x22\x6e\x41\xc6\x92\xfc\x82\xb8\xb5\x6a\xc1\xc5\x40\xc5\xbd\x5b\x8d\xec\x52\x35\xa0\xfa\x87\x22\x47\x6c\x77\x09\xc0\x25\x59\xe3\xaa\x73\xaa\x03\x91\x8b\xa2\xd4\x92\xee\xa7\x5a\xbe\xa2\x35", + (const uint8_t *)"\xf7\x86\x9c\x67\x9b\xbe\xd1\x81\x70\x52\xaf\xfd\x02\x64\xcc\xc6\x48\x67\x95\xf6\xd0\x6d\x0c\x18\x76\x51\xb8\xf3\x86\x36\x70\xc8\x2c\xcf\x89\xbe\x32\xa5\x3e\xb6\x5e\xa7\xc0\x07\x85\x97\x83\xd4\x67\x17\x98\x6f\xea\xd0\x83\x3e\xc6\x0c\x57\x29\xcd\xc4\xa9\xee", + (const uint8_t *)"\xc8\x4a\x4c\xc2\x64\x10\x00\x70\xc8\xbe\x2a\xcf\x40\x72\xef\xaa\xda\xed\xfe\xf3\xd6\x20\x9c\x0f\xe2\x63\x87\xe6\xb1\x26\x2b\xbf")); + layoutProgress("TESTING CPU ...", 100 + (i * 100)); + } + + // FLASH TEST + const uint32_t patterns[] = { 0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x66666666, 0x99999999, 0x33333333, 0xCCCCCCCC }; - layoutProgress("TESTING ... Please wait", 0); + layoutProgress("TESTING FLASH ...", 0); // backup metadata backup_metadata(meta_backup); @@ -358,7 +383,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } flash_lock(); sha256_Update(&ctx, (unsigned char *)FLASH_META_START, FLASH_META_LEN); - layoutProgress("TESTING ... Please wait", (p * 100) + 100); + layoutProgress("TESTING FLASH ...", 100 + (p * 100)); } // copy metadata back @@ -369,18 +394,29 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) uint8_t hash[32]; sha256_Final(&ctx, hash); - layoutProgress("TESTING ... Please wait", 1000); + layoutProgress("TESTING FLASH ...", 1000); // hash computed via the following Python3 script: // hashlib.sha256(b''.join([binascii.unhexlify(c * 2 * 32768) for c in '0F5A693C'])).hexdigest() - if (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)) { + bool status_flash = (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)); + + bool status_all = status_cpu && status_flash; + + if (status_all) { send_msg_success(dev); - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Test OK", NULL, NULL, NULL, NULL, NULL); } else { send_msg_failure(dev); - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Test FAILED", NULL, NULL, NULL, NULL, NULL); } + layoutDialog(status_all ? &bmp_icon_info : &bmp_icon_error, + NULL, NULL, NULL, + status_cpu ? "Test CPU ... OK" : "Test CPU ... Failed", + status_flash ? "Test FLASH ... OK" : "Test FLASH ... Failed", + NULL, + NULL, + NULL, + NULL + ); return; } } diff --git a/fastflash/Makefile b/fastflash/Makefile index 9679981750..ee0c455cef 100644 --- a/fastflash/Makefile +++ b/fastflash/Makefile @@ -6,8 +6,14 @@ OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o +OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/ecdsa.small.o +OBJS += ../vendor/trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/sha2.o +CFLAGS += -DUSE_PRECOMPUTED_IV=0 +CFLAGS += -DUSE_PRECOMPUTED_CP=0 + include ../Makefile.include CFLAGS += -I../bootloader diff --git a/memory_app_2.0.0.ld b/memory_app_2.0.0.ld index 163eb75a33..bfd773a68c 100644 --- a/memory_app_2.0.0.ld +++ b/memory_app_2.0.0.ld @@ -3,7 +3,7 @@ MEMORY { rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K - bootloader (rx) : ORIGIN = 0x20000000, LENGTH = 20K + bootloader (rx) : ORIGIN = 0x20000000, LENGTH = 32K ram (rwx) : ORIGIN = 0x20000000 + LENGTH(bootloader), LENGTH = 128K - LENGTH(bootloader) } diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index f19e51f2fa..252158425b 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -1,7 +1,7 @@ /* STM32F205RE - 512K Flash, 128K RAM */ MEMORY { - rom (rx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x20000000, LENGTH = 32K ram (rwx) : ORIGIN = 0x20000000 + LENGTH(rom), LENGTH = 128K - LENGTH(rom) } From 683c5953bac89981b02c35305703fbfd3814359d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Jul 2017 19:38:49 +0200 Subject: [PATCH 0492/1154] travis: fix build --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06d5eed32f..72a6010cbc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,9 @@ addons: script: - CFLAGS="-std=c99" make -C vendor/libopencm3 - make + - OPTFLAGS="-Os" make -C bootloader + - OPTFLAGS="-Os" make -C fastflash - make -C firmware - - make -C bootloader - - make -C fastflash - make -C demo - make -C firmware clean && make -C firmware FASTFLASH=1 From 3d6bfddc5fd07eaab6dcbd0c3b668f03914c3e6b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Jul 2017 20:21:10 +0200 Subject: [PATCH 0493/1154] move -Os flag to Makefiles of bootloader and fastflash --- .travis.yml | 4 ++-- bootloader-docker-build.sh | 1 - bootloader/Makefile | 6 ++++-- fastflash/Makefile | 6 ++++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72a6010cbc..0fee46da0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,8 @@ addons: script: - CFLAGS="-std=c99" make -C vendor/libopencm3 - make - - OPTFLAGS="-Os" make -C bootloader - - OPTFLAGS="-Os" make -C fastflash + - make -C bootloader + - make -C fastflash - make -C firmware - make -C demo - make -C firmware clean && make -C firmware FASTFLASH=1 diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index 5a136f0534..7387d6314b 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -11,7 +11,6 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ git checkout $FIRMWARETAG && \ git submodule update --init && \ CFLAGS='-std=c99' make -C vendor/libopencm3 && \ - export OPTFLAGS=-Os make && \ make -C bootloader && \ cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin" diff --git a/bootloader/Makefile b/bootloader/Makefile index 8c1f18dff6..6a2dc5f847 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -4,14 +4,16 @@ OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o -OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/bignum.small.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o -OBJS += ../vendor/trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/sha2.small.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 +OPTFLAGS ?= -Os + include ../Makefile.include align: $(NAME).bin diff --git a/fastflash/Makefile b/fastflash/Makefile index ee0c455cef..24ca20a615 100644 --- a/fastflash/Makefile +++ b/fastflash/Makefile @@ -6,14 +6,16 @@ OBJS += bootloader.o OBJS += signatures.o OBJS += usb.o -OBJS += ../vendor/trezor-crypto/bignum.o +OBJS += ../vendor/trezor-crypto/bignum.small.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o -OBJS += ../vendor/trezor-crypto/sha2.o +OBJS += ../vendor/trezor-crypto/sha2.small.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 +OPTFLAGS ?= -Os + include ../Makefile.include CFLAGS += -I../bootloader From ba2b2f24da60b66f97fca9f9a1fc7f07a69e2ed7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Jul 2017 12:17:46 +0200 Subject: [PATCH 0494/1154] firmware: mark backup as done before giving away the mnemonic, not after --- firmware/reset.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/reset.c b/firmware/reset.c index ae00bbe83c..2aa6c046f6 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -116,6 +116,10 @@ void reset_backup(bool separated) return; } + storage.has_needs_backup = true; + storage.needs_backup = false; + storage_commit(); + int pass, word_pos, i = 0, j; for (pass = 0; pass < 2; pass++) { @@ -173,10 +177,6 @@ void reset_backup(bool separated) } } - storage.has_needs_backup = true; - storage.needs_backup = false; - storage_commit(); - if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { From 2ecc36cd899f3a6b589c00488fb81188187c8a70 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Jul 2017 14:22:00 +0200 Subject: [PATCH 0495/1154] ethereum: don't show unrecognized ERC-20 tokens as sending message --- firmware/ethereum.c | 4 ++++ firmware/ethereum_tokens.c | 4 +++- firmware/ethereum_tokens.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 7db5352727..df9c60f1e2 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -203,6 +203,10 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, bn_read_uint32(1000000000, &bn1e9); const char *suffix = NULL; int decimals = 18; + if (token == UnknownToken) { + strlcpy(buf, "Unrecognized Token", buflen); + return; + } else if (token != NULL) { suffix = token->ticker; decimals = token->decimals; diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 42a071908d..0d49397d75 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -84,6 +84,8 @@ const TokenType tokens[TOKENS_COUNT] = { {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; +const TokenType *UnknownToken = (const TokenType *)1; + const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) { if (!address) return 0; @@ -92,5 +94,5 @@ const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) return &(tokens[i]); } } - return 0; + return UnknownToken; } diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 46910b70e3..ef458b4cf1 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -33,6 +33,8 @@ typedef struct { extern const TokenType tokens[TOKENS_COUNT]; +extern const TokenType *UnknownToken; + const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address); #endif From f826b1fa460ea8180e9a661ec777c9e1a8ee7f04 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Jul 2017 16:38:56 +0200 Subject: [PATCH 0496/1154] ethereum: add new tokens --- firmware/ethereum_tokens.c | 7 +++++++ firmware/ethereum_tokens.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 0d49397d75..2ffdaf2ea9 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -3,7 +3,9 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, + { 1, "\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", " ADST", 0}, { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, + { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, @@ -18,6 +20,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, { 1, "\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, + { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, @@ -43,12 +46,14 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, + { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, @@ -58,6 +63,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, + { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, @@ -81,6 +87,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x82\x66\x57\x64\xea\x0b\x58\x15\x7e\x1e\x5e\x9b\xab\x32\xf6\x8c\x76\xec\x0c\xdf", " VSM", 0}, { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, + { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index ef458b4cf1..c5250f4898 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 80 +#define TOKENS_COUNT 87 typedef struct { uint8_t chain_id; From 7ca4b11c3abf7790f5b80adc6609e93a83a5823a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Jul 2017 19:10:25 +0200 Subject: [PATCH 0497/1154] add USB test to SelfTest --- bootloader/usb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 968284ca38..716dcf1706 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -328,7 +328,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } // struct.unpack(">HL") => msg, size msg_id = (buf[3] << 8) + buf[4]; - msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; } if (flash_state == STATE_READY || flash_state == STATE_OPEN) { @@ -343,6 +343,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } if (msg_id == 0x0020) { // SelfTest message (id 32) + // USB TEST + + bool status_usb = (buf[9] == 0x0a) && (buf[10] == 53) && (0 == memcmp(buf + 11, "\x00\xFF\x55\xAA\x66\x99\x33\xCC" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!" "\x00\xFF\x55\xAA\x66\x99\x33\xCC", 53)); + // CPU TEST layoutProgress("TESTING CPU ...", 0); @@ -401,7 +405,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) bool status_flash = (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)); - bool status_all = status_cpu && status_flash; + bool status_all = status_usb && status_cpu && status_flash; if (status_all) { send_msg_success(dev); @@ -410,11 +414,11 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } layoutDialog(status_all ? &bmp_icon_info : &bmp_icon_error, NULL, NULL, NULL, + status_usb ? "Test USB ... OK" : "Test USB ... Failed", status_cpu ? "Test CPU ... OK" : "Test CPU ... Failed", status_flash ? "Test FLASH ... OK" : "Test FLASH ... Failed", NULL, NULL, - NULL, NULL ); return; From 5b66c0b956976555783473b96a2a100508a8e9d4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 21:30:01 +0200 Subject: [PATCH 0498/1154] refactor Address dialog (QR code on left button click), use checksum for Ethereum addresses --- firmware/ethereum.c | 17 +++++---- firmware/fsm.c | 28 ++++++++------ firmware/layout2.c | 87 +++++++++++++++++++++++--------------------- firmware/layout2.h | 2 +- vendor/trezor-crypto | 2 +- 5 files changed, 73 insertions(+), 63 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index df9c60f1e2..686b1d1f50 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -29,6 +29,7 @@ #include "crypto.h" #include "secp256k1.h" #include "sha3.h" +#include "address.h" #include "util.h" #include "gettext.h" #include "ethereum_tokens.h" @@ -249,16 +250,16 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui ethereumFormatAmount(&val, token, amount, sizeof(amount)); } - static char _to1[17] = {0}; - static char _to2[17] = {0}; - static char _to3[17] = {0}; + char _to1[] = "to 0x__________"; + char _to2[] = "_______________"; + char _to3[] = "_______________?"; if (to_len) { - strcpy(_to1, _("to ")); - data2hex(to, 6, _to1 + 3); - data2hex(to + 6, 7, _to2); - data2hex(to + 13, 7, _to3); - _to3[14] = '?'; _to3[15] = 0; + char to_str[41]; + ethereum_address_checksum(to, to_str); + memcpy(_to1 + 5, to_str, 10); + memcpy(_to2, to_str + 10, 15); + memcpy(_to3, to_str + 25, 15); } else { strlcpy(_to1, _("to new contract?"), sizeof(_to1)); strlcpy(_to2, "", sizeof(_to2)); diff --git a/firmware/fsm.c b/firmware/fsm.c index 766b4d9b8c..58821bff9c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -652,11 +652,13 @@ void fsm_msgGetAddress(GetAddress *msg) } else { strlcpy(desc, _("Address:"), sizeof(desc)); } - layoutAddress(resp->address, desc); - if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; + bool qrcode = false; + for (;;) { + layoutAddress(resp->address, desc, qrcode); + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + break; + } + qrcode = !qrcode; } } @@ -684,14 +686,16 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) char desc[16]; strlcpy(desc, "Address:", sizeof(desc)); - char address[41]; - data2hex(resp->address.bytes, 20, address); + char address[43] = { '0', 'x' }; + ethereum_address_checksum(resp->address.bytes, address + 2); - layoutAddress(address, desc); - if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; + bool qrcode = false; + for (;;) { + layoutAddress(address, desc, qrcode); + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + break; + } + qrcode = !qrcode; } } diff --git a/firmware/layout2.c b/firmware/layout2.c index 0b7ecced5d..23e5ea1882 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -225,57 +225,62 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutAddress(const char *address, const char *desc) +void layoutAddress(const char *address, const char *desc, bool qrcode) { - oledSwipeLeft(); + if (layoutLast != layoutAddress) { + oledSwipeLeft(); + } else { + oledClear(); + } layoutLast = layoutAddress; - static unsigned char bitdata[QR_MAX_BITDATA]; - int a, i, j; - int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata); - int startx; + if (qrcode) { + static unsigned char bitdata[QR_MAX_BITDATA]; + int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata); - if (side > 0 && side <= 29) { - oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); - for (i = 0; i < side; i++) { - for (j = 0; j< side; j++) { - a = j * side + i; - if (bitdata[a / 8] & (1 << (7 - a % 8))) { - oledClearPixel(2 + i * 2, 2 + j * 2); - oledClearPixel(3 + i * 2, 2 + j * 2); - oledClearPixel(2 + i * 2, 3 + j * 2); - oledClearPixel(3 + i * 2, 3 + j * 2); + if (side > 0 && side <= 29) { + oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); + for (int i = 0; i < side; i++) { + for (int j = 0; j< side; j++) { + int a = j * side + i; + if (bitdata[a / 8] & (1 << (7 - a % 8))) { + oledClearPixel(2 + i * 2, 2 + j * 2); + oledClearPixel(3 + i * 2, 2 + j * 2); + oledClearPixel(2 + i * 2, 3 + j * 2); + oledClearPixel(3 + i * 2, 3 + j * 2); + } + } + } + } else if (side > 0 && side <= 60) { + oledInvert(0, 0, (side + 3), (side + 3)); + for (int i = 0; i < side; i++) { + for (int j = 0; j< side; j++) { + int a = j * side + i; + if (bitdata[a / 8] & (1 << (7 - a % 8))) { + oledClearPixel(2 + i, 2 + j); + } } } } - startx = 68; - } else if (side > 0 && side <= 60) { - oledInvert(0, 0, (side + 3), (side + 3)); - for (i = 0; i < side; i++) { - for (j = 0; j< side; j++) { - a = j * side + i; - if (bitdata[a / 8] & (1 << (7 - a % 8))) { - oledClearPixel(2 + i, 2 + j); - } - } - } - startx = side + 6; } else { - startx = 0; + uint32_t addrlen = strlen(address); + uint32_t rowlen = addrlen / 2; + if (addrlen % 2) { + rowlen++; + } + const char **str = split_message((const uint8_t *)address, addrlen, rowlen); + if (desc) { + oledDrawString(0, 0 * 9, desc); + } + for (int i = 0; i < 4; i++) { + oledDrawString(0, (i + 1) * 9 + 4, str[i]); + } } - uint32_t addrlen = strlen(address); - uint32_t rowlen = addrlen / 4; - if (addrlen % 4) { - rowlen++; - } - const char **str = split_message((const uint8_t *)address, addrlen, rowlen); - - if (desc) { - oledDrawString(startx, 0 * 9, desc); - } - for (i = 0; i < 4; i++) { - oledDrawString(startx, (i+1) * 9 + 4, str[i]); + if (!qrcode) { + static const char *btnNo = _("QR Code"); + oledDrawString(2, OLED_HEIGHT - 8, btnNo); + oledInvert(0, OLED_HEIGHT - 9, oledStringWidth(btnNo) + 3, OLED_HEIGHT - 1); } static const char *btnYes = _("Continue"); diff --git a/firmware/layout2.h b/firmware/layout2.h index 2ed72614e7..c1e368a91b 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -40,7 +40,7 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); -void layoutAddress(const char *address, const char *desc); +void layoutAddress(const char *address, const char *desc, bool qrcode); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 5331935626..f49fe75e15 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 533193562601780c8705ecb80c908916bb80b427 +Subproject commit f49fe75e15eafaa69ab687857c4ffd0c9410a0e1 From 069f11858591259c324ddb44861bd0d0c66bc45b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 21:35:16 +0200 Subject: [PATCH 0499/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f49fe75e15..cfe8f39cd4 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f49fe75e15eafaa69ab687857c4ffd0c9410a0e1 +Subproject commit cfe8f39cd436bf98e864775a9131e81e554e7bf1 From 86bcede12d7c174412e560e3be998849668a2759 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 11 Jul 2017 23:45:08 +0200 Subject: [PATCH 0500/1154] bootloader: add changelog, bump version to 1.3.2 --- bootloader/ChangeLog | 8 ++++++++ bootloader/bootloader.h | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index 15453e7ac1..9bc863fed3 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,3 +1,11 @@ +Version 1.3.2 +* Don't show recovery seed warning if firmware is flashed for the first time +* Don't show fingerprint if firmware is flashed for the first time +* Compute firmware hash before checking signatures +* Add self-test +* Fix usage of RNG before setup +* Fix stack protector fault + Version 1.3.1 * Fix button testing so it does not break USB communication diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 45e61676d7..723b9bac91 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x03" -#define VERSION_PATCH_CHAR "\x01" +#define VERSION_PATCH_CHAR "\x02" #include #include "memory.h" From ccb0cd82b60594c74096ef3d8e37a83c06c06821 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Jul 2017 14:19:05 +0200 Subject: [PATCH 0501/1154] firmware: add changelog, bump version to 1.5.1 --- firmware/ChangeLog | 9 +++++++++ firmware/storage.c | 1 - firmware/trezor.h | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 293345a0d7..c4fbf764aa 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,12 @@ +Version 1.5.1 +* Stable release, optional update +* Allow "dry run" recovery procedure +* Allow separated backup procedure +* Add more ERC-20 tokens +* Handle unrecognized ERC-20 tokens +* Make address dialog nicer +* Use checksum for Ethereum addresses + Version 1.5.0 * Stable release, optional update * Enable Segwit for Testnet and Litecoin diff --git a/firmware/storage.c b/firmware/storage.c index ad3aea4d26..6b535c07b6 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -585,7 +585,6 @@ bool storage_needsBackup(void) return storage.has_needs_backup && storage.needs_backup; } - uint32_t storage_nextU2FCounter(void) { uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); diff --git a/firmware/trezor.h b/firmware/trezor.h index 8005e8ac65..df6200b355 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 5 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) From c5e927fac2d8c2b7d4f80d4c9d67b9f05b00d51c Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 2 Jul 2017 16:12:56 +0200 Subject: [PATCH 0502/1154] Ethereum Sign/Verify Message Implements issue trezor/trezor-mcu#163. --- firmware/ethereum.c | 101 +++++++++++++++++++++++++++++++++++++------- firmware/ethereum.h | 3 ++ firmware/fsm.c | 51 ++++++++++++++++++++++ firmware/fsm.h | 2 + 4 files changed, 141 insertions(+), 16 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 686b1d1f50..19641cfc13 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -36,7 +36,7 @@ static bool ethereum_signing = false; static uint32_t data_total, data_left; -static EthereumTxRequest resp; +static EthereumTxRequest msg_tx_request; static uint8_t privkey[32]; static uint8_t chain_id; struct SHA3_CTX keccak_ctx; @@ -138,9 +138,9 @@ static void send_request_chunk(void) ? data_left / (data_total/800) : data_left * 800 / data_total); layoutProgress(_("Signing"), progress); - resp.has_data_length = true; - resp.data_length = data_left <= 1024 ? data_left : 1024; - msg_write(MessageType_MessageType_EthereumTxRequest, &resp); + msg_tx_request.has_data_length = true; + msg_tx_request.data_length = data_left <= 1024 ? data_left : 1024; + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); } static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) @@ -173,24 +173,24 @@ static void send_signature(void) memset(privkey, 0, sizeof(privkey)); /* Send back the result */ - resp.has_data_length = false; + msg_tx_request.has_data_length = false; - resp.has_signature_v = true; + msg_tx_request.has_signature_v = true; if (chain_id) { - resp.signature_v = v + 2 * chain_id + 35; + msg_tx_request.signature_v = v + 2 * chain_id + 35; } else { - resp.signature_v = v + 27; + msg_tx_request.signature_v = v + 27; } - resp.has_signature_r = true; - resp.signature_r.size = 32; - memcpy(resp.signature_r.bytes, sig, 32); + msg_tx_request.has_signature_r = true; + msg_tx_request.signature_r.size = 32; + memcpy(msg_tx_request.signature_r.bytes, sig, 32); - resp.has_signature_s = true; - resp.signature_s.size = 32; - memcpy(resp.signature_s.bytes, sig + 32, 32); + msg_tx_request.has_signature_s = true; + msg_tx_request.signature_s.size = 32; + memcpy(msg_tx_request.signature_s.bytes, sig + 32, 32); - msg_write(MessageType_MessageType_EthereumTxRequest, &resp); + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); ethereum_signing_abort(); } @@ -401,7 +401,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) ethereum_signing = true; sha3_256_Init(&keccak_ctx); - memset(&resp, 0, sizeof(EthereumTxRequest)); + memset(&msg_tx_request, 0, sizeof(EthereumTxRequest)); /* set fields to 0, to avoid conditions later */ if (!msg->has_value) msg->value.size = 0; @@ -572,3 +572,72 @@ void ethereum_signing_abort(void) ethereum_signing = false; } } + +static void ethereum_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) +{ + struct SHA3_CTX ctx; + + sha3_256_Init(&ctx); + sha3_Update(&ctx, message, message_len); + keccak_Final(&ctx, hash); +} + +void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) +{ + uint8_t hash[32]; + + if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { + return; + } + resp->has_address = true; + resp->address.size = 20; + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + + uint8_t v; + if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + return; + } + + resp->has_signature = true; + resp->signature.bytes[64] = 27 + v; + resp->signature.size = 65; + msg_write(MessageType_MessageType_EthereumMessageSignature, resp); +} + +int ethereum_message_verify(EthereumVerifyMessage *msg) +{ + if (msg->signature.size != 65 + || msg->address.size != 20) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); + return 1; + } + + uint8_t pubkey[65]; + uint8_t hash[32]; + + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + + /* v should be 27, 28 but some implementations use 0,1. We are + * compatible with both. + */ + uint8_t v = msg->signature.bytes[64]; + if (v >= 27) + v -= 27; + + if (v >= 2 || + ecdsa_verify_digest_recover(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { + return 2; + } + + struct SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, pubkey + 1, 64); + keccak_Final(&ctx, hash); + + /* result are the least significant 160 bits */ + if (memcmp(msg->address.bytes, hash + 12, 20) != 0) { + return 2; + } + return 0; +} diff --git a/firmware/ethereum.h b/firmware/ethereum.h index 8c55d2db58..de8866242d 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -29,4 +29,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); void ethereum_signing_abort(void); void ethereum_signing_txack(EthereumTxAck *msg); +void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); +int ethereum_message_verify(EthereumVerifyMessage *msg); + #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 58821bff9c..c200a30cb4 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -703,6 +703,57 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) layoutHome(); } +void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) +{ + RESP_INIT(EthereumMessageSignature); + + CHECK_INITIALIZED + + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + ethereum_message_sign(msg, node, resp); + layoutHome(); +} + +void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) +{ + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + + if (ethereum_message_verify(msg) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + return; + } + + char address[41]; + data2hex(msg->address.bytes, 20, address); + layoutVerifyAddress(address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + + layoutHome(); +} + void fsm_msgEntropyAck(EntropyAck *msg) { if (msg->has_entropy) { diff --git a/firmware/fsm.h b/firmware/fsm.h index 6d4fc06cf7..128c0fb35a 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -62,6 +62,8 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg); void fsm_msgEthereumGetAddress(EthereumGetAddress *msg); void fsm_msgEthereumSignTx(EthereumSignTx *msg); void fsm_msgEthereumTxAck(EthereumTxAck *msg); +void fsm_msgEthereumSignMessage(EthereumSignMessage *msg); +void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); // debug message functions #if DEBUG_LINK From b0ac3a2af197ea023b133be34857b43a6ef374ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Jul 2017 17:51:34 +0200 Subject: [PATCH 0503/1154] add EthereumSignMessage/EthereumVerifyMessage --- firmware/ethereum.c | 12 +++--- firmware/fsm.c | 4 +- firmware/protob/messages.options | 10 +++++ firmware/protob/messages.pb.c | 21 ++++++++- firmware/protob/messages.pb.h | 74 ++++++++++++++++++++++++++++++++ firmware/protob/messages_map.h | 3 ++ vendor/trezor-common | 2 +- 7 files changed, 117 insertions(+), 9 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 19641cfc13..085d3a888f 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -576,8 +576,11 @@ void ethereum_signing_abort(void) static void ethereum_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) { struct SHA3_CTX ctx; - sha3_256_Init(&ctx); + sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + sha3_Update(&ctx, varint, l); sha3_Update(&ctx, message, message_len); keccak_Final(&ctx, hash); } @@ -607,8 +610,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu int ethereum_message_verify(EthereumVerifyMessage *msg) { - if (msg->signature.size != 65 - || msg->address.size != 20) { + if (msg->signature.size != 65 || msg->address.size != 20) { fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); return 1; } @@ -622,9 +624,9 @@ int ethereum_message_verify(EthereumVerifyMessage *msg) * compatible with both. */ uint8_t v = msg->signature.bytes[64]; - if (v >= 27) + if (v >= 27) { v -= 27; - + } if (v >= 2 || ecdsa_verify_digest_recover(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { return 2; diff --git a/firmware/fsm.c b/firmware/fsm.c index c200a30cb4..ca9176cf65 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -735,8 +735,8 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) return; } - char address[41]; - data2hex(msg->address.bytes, 20, address); + char address[43] = { '0', 'x' }; + ethereum_address_checksum(msg->address.bytes, address + 2); layoutVerifyAddress(address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index ca54a39419..d3ccac9ea0 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -65,6 +65,16 @@ VerifyMessage.coin_name max_size:17 MessageSignature.address max_size:41 MessageSignature.signature max_size:65 +EthereumSignMessage.address_n max_count:8 +EthereumSignMessage.message max_size:1024 + +EthereumVerifyMessage.address max_size:20 +EthereumVerifyMessage.signature max_size:65 +EthereumVerifyMessage.message max_size:1024 + +EthereumMessageSignature.address max_size:20 +EthereumMessageSignature.signature max_size:65 + # deprecated EncryptMessage skip_message:true # EncryptMessage.pubkey max_size:33 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 647059d73f..3e1cd9e01f 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -314,6 +314,25 @@ const pb_field_t EthereumTxAck_fields[2] = { PB_LAST_FIELD }; +const pb_field_t EthereumSignMessage_fields[3] = { + PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignMessage, address_n, address_n, 0), + PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, EthereumSignMessage, message, address_n, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumVerifyMessage_fields[4] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumVerifyMessage, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumVerifyMessage, signature, address, 0), + PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumVerifyMessage, message, signature, 0), + PB_LAST_FIELD +}; + +const pb_field_t EthereumMessageSignature_fields[3] = { + PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumMessageSignature, address, address, 0), + PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumMessageSignature, signature, address, 0), + PB_LAST_FIELD +}; + const pb_field_t SignIdentity_fields[5] = { PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), @@ -413,7 +432,7 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_EthereumSignMessage_EthereumVerifyMessage_EthereumMessageSignature_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index d232504fe2..1000e09725 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -72,6 +72,9 @@ typedef enum _MessageType { MessageType_MessageType_GetECDHSessionKey = 61, MessageType_MessageType_ECDHSessionKey = 62, MessageType_MessageType_SetU2FCounter = 63, + MessageType_MessageType_EthereumSignMessage = 64, + MessageType_MessageType_EthereumVerifyMessage = 65, + MessageType_MessageType_EthereumMessageSignature = 66, MessageType_MessageType_DebugLinkDecision = 100, MessageType_MessageType_DebugLinkGetState = 101, MessageType_MessageType_DebugLinkState = 102, @@ -324,6 +327,34 @@ typedef struct _EthereumGetAddress { bool show_display; } EthereumGetAddress; +typedef struct { + size_t size; + uint8_t bytes[20]; +} EthereumMessageSignature_address_t; + +typedef struct { + size_t size; + uint8_t bytes[65]; +} EthereumMessageSignature_signature_t; + +typedef struct _EthereumMessageSignature { + bool has_address; + EthereumMessageSignature_address_t address; + bool has_signature; + EthereumMessageSignature_signature_t signature; +} EthereumMessageSignature; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EthereumSignMessage_message_t; + +typedef struct _EthereumSignMessage { + size_t address_n_count; + uint32_t address_n[8]; + EthereumSignMessage_message_t message; +} EthereumSignMessage; + typedef struct { size_t size; uint8_t bytes[32]; @@ -406,6 +437,30 @@ typedef struct _EthereumTxRequest { EthereumTxRequest_signature_s_t signature_s; } EthereumTxRequest; +typedef struct { + size_t size; + uint8_t bytes[20]; +} EthereumVerifyMessage_address_t; + +typedef struct { + size_t size; + uint8_t bytes[65]; +} EthereumVerifyMessage_signature_t; + +typedef struct { + size_t size; + uint8_t bytes[1024]; +} EthereumVerifyMessage_message_t; + +typedef struct _EthereumVerifyMessage { + bool has_address; + EthereumVerifyMessage_address_t address; + bool has_signature; + EthereumVerifyMessage_signature_t signature; + bool has_message; + EthereumVerifyMessage_message_t message; +} EthereumVerifyMessage; + typedef struct _Failure { bool has_code; FailureType code; @@ -779,6 +834,9 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_default {false, {0, {0}}} +#define EthereumSignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}} +#define EthereumVerifyMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define EthereumMessageSignature_init_default {false, {0, {0}}, false, {0, {0}}} #define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} #define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} @@ -837,6 +895,9 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} #define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} #define EthereumTxAck_init_zero {false, {0, {0}}} +#define EthereumSignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}} +#define EthereumVerifyMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} +#define EthereumMessageSignature_init_zero {false, {0, {0}}, false, {0, {0}}} #define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} #define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} #define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} @@ -896,6 +957,10 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumAddress_address_tag 1 #define EthereumGetAddress_address_n_tag 1 #define EthereumGetAddress_show_display_tag 2 +#define EthereumMessageSignature_address_tag 1 +#define EthereumMessageSignature_signature_tag 2 +#define EthereumSignMessage_address_n_tag 1 +#define EthereumSignMessage_message_tag 2 #define EthereumSignTx_address_n_tag 1 #define EthereumSignTx_nonce_tag 2 #define EthereumSignTx_gas_price_tag 3 @@ -910,6 +975,9 @@ extern const uint32_t SignTx_lock_time_default; #define EthereumTxRequest_signature_v_tag 2 #define EthereumTxRequest_signature_r_tag 3 #define EthereumTxRequest_signature_s_tag 4 +#define EthereumVerifyMessage_address_tag 1 +#define EthereumVerifyMessage_signature_tag 2 +#define EthereumVerifyMessage_message_tag 3 #define Failure_code_tag 1 #define Failure_message_tag 2 #define Features_vendor_tag 1 @@ -1053,6 +1121,9 @@ extern const pb_field_t TxAck_fields[2]; extern const pb_field_t EthereumSignTx_fields[10]; extern const pb_field_t EthereumTxRequest_fields[5]; extern const pb_field_t EthereumTxAck_fields[2]; +extern const pb_field_t EthereumSignMessage_fields[3]; +extern const pb_field_t EthereumVerifyMessage_fields[4]; +extern const pb_field_t EthereumMessageSignature_fields[3]; extern const pb_field_t SignIdentity_fields[5]; extern const pb_field_t SignedIdentity_fields[4]; extern const pb_field_t GetECDHSessionKey_fields[4]; @@ -1113,6 +1184,9 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define EthereumSignTx_size 1245 #define EthereumTxRequest_size 80 #define EthereumTxAck_size 1027 +#define EthereumSignMessage_size 1075 +#define EthereumVerifyMessage_size 1116 +#define EthereumMessageSignature_size 89 #define SignIdentity_size (558 + IdentityType_size) #define SignedIdentity_size 145 #define GetECDHSessionKey_size (107 + IdentityType_size) diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index 1fd9a39d22..326e080d8a 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -40,6 +40,8 @@ { 'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *)) fsm_msgEthereumTxAck }, { 'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *)) fsm_msgGetECDHSessionKey }, { 'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *)) fsm_msgSetU2FCounter }, + { 'n', 'i', MessageType_MessageType_EthereumSignMessage, EthereumSignMessage_fields, (void (*)(void *)) fsm_msgEthereumSignMessage }, + { 'n', 'i', MessageType_MessageType_EthereumVerifyMessage, EthereumVerifyMessage_fields, (void (*)(void *)) fsm_msgEthereumVerifyMessage }, // out messages @@ -65,6 +67,7 @@ { 'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0 }, { 'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0 }, { 'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0 }, + { 'n', 'o', MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature_fields, 0 }, #if DEBUG_LINK diff --git a/vendor/trezor-common b/vendor/trezor-common index c2a40f4b67..b29b98d69b 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit c2a40f4b675ed3bf137360a6fa22ff72775f38ff +Subproject commit b29b98d69ba43571dcbe54dc927aa3ecd2b95113 From da71f7c45d31aed1029520f9e470356ba4dc9459 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Jul 2017 18:44:56 +0200 Subject: [PATCH 0504/1154] fix layoutVerifyAddress behaviour for long addresses --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 23e5ea1882..e1cb27cfbc 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -190,7 +190,7 @@ void layoutVerifyAddress(const char *address) layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), _("Confirm address?"), _("Message signed by:"), - NULL, str[0], str[1], str[2], NULL); + str[0], str[1], str[2], NULL, NULL); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) From 078142176202fe749550e15544e783db97902e10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 14 Jul 2017 18:41:48 +0200 Subject: [PATCH 0505/1154] ethereum: more tokens, use better wording for unknown token value --- firmware/ethereum.c | 2 +- firmware/ethereum_tokens-gen.py | 1 + firmware/ethereum_tokens.c | 3 +++ firmware/ethereum_tokens.h | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 085d3a888f..d2913cd6c6 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -205,7 +205,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, const char *suffix = NULL; int decimals = 18; if (token == UnknownToken) { - strlcpy(buf, "Unrecognized Token", buflen); + strlcpy(buf, "Unknown token value", buflen); return; } else if (token != NULL) { diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 11ab30bb0d..850b16690b 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -6,6 +6,7 @@ subst = { ( 1, 'CryptoCarbon'): 'CCRB', ( 1, 'DAO_extraBalance'): 'DAOe', ( 1, 'DGX 1.0'): 'DGX1', + ( 1, 'JetCoins'): 'JTC', ( 1, 'Unicorn \U0001F984 '): 'UNCRN', } diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 2ffdaf2ea9..7cabc1c0cd 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -16,6 +16,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, + { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, @@ -37,6 +38,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, + { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JTC", 18}, { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, @@ -78,6 +80,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, + { 1, "\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", " TIX", 18}, { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index c5250f4898..70a80b862e 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 87 +#define TOKENS_COUNT 90 typedef struct { uint8_t chain_id; From d2c90d70dc27077f5020dc38280194f7e4f87514 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 16 Jul 2017 18:43:58 +0100 Subject: [PATCH 0506/1154] strwidth: Initial commit --- gen/strwidth.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 gen/strwidth.c diff --git a/gen/strwidth.c b/gen/strwidth.c new file mode 100644 index 0000000000..c12f7b0b0d --- /dev/null +++ b/gen/strwidth.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include "fonts.h" + +static inline char convert(char c) { + if (c < 0x80) { + return c; + } else if (c >= 0xC0) { + return '_'; + } else { + return '\0'; + } +} + +int main(int argc, char **argv) { + char *line; + while ((line = readline(NULL)) != NULL) { + size_t length = strlen(line); + if (length) { + add_history(line); + } + + size_t width = 0; + for (size_t i = 0; i < length; i++) { + width += fontCharWidth(convert(line[i])) + 1; + } + + printf("%zu\n", width); + free(line); + } +} From a2226c410ef43b6e0117ad06340c57f271105c68 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Jul 2017 12:25:07 +0200 Subject: [PATCH 0507/1154] gen: add Makefile for strwidth --- gen/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 gen/Makefile diff --git a/gen/Makefile b/gen/Makefile new file mode 100644 index 0000000000..c518d9182c --- /dev/null +++ b/gen/Makefile @@ -0,0 +1,9 @@ +CC=gcc + +all: strwidth + +strwidth: strwidth.c fonts.c + $(CC) strwidth.c fonts.c -o strwidth -lreadline + +clean: + rm -f strwidth From 1a72a49ee5030b04ebdfeeb86f5090b1ca6af759 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Jul 2017 14:23:23 +0200 Subject: [PATCH 0508/1154] ethereum: update tokens --- firmware/ethereum_tokens-gen.py | 1 - firmware/ethereum_tokens.c | 7 +++++-- firmware/ethereum_tokens.h | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 850b16690b..2093545e66 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -4,7 +4,6 @@ import requests subst = { ( 1, 'BeerCoin \U0001F37A '): 'BEER', ( 1, 'CryptoCarbon'): 'CCRB', - ( 1, 'DAO_extraBalance'): 'DAOe', ( 1, 'DGX 1.0'): 'DGX1', ( 1, 'JetCoins'): 'JTC', ( 1, 'Unicorn \U0001F984 '): 'UNCRN', diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 7cabc1c0cd..b7c1d6f082 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -14,13 +14,14 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, + { 1, "\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", " CAT", 18}, { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, + { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, - { 1, "\x5c\x40\xef\x6f\x52\x7f\x4f\xba\x68\x36\x87\x74\xe6\x13\x0c\xe6\x51\x51\x23\xf2", " DAOe", 0}, { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, @@ -28,8 +29,9 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, + { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, - { 1, "\xbb\xb1\xbd\x2d\x74\x1f\x05\xe1\x44\xe6\xc4\x51\x76\x76\xa1\x55\x54\xfd\x4b\x8d", " FUN", 8}, + { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, { 1, "\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, @@ -57,6 +59,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, + { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 70a80b862e..8ea7d7396a 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 90 +#define TOKENS_COUNT 93 typedef struct { uint8_t chain_id; From cf042797743531504ff7a5c90fcab3b4692754ea Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Jul 2017 18:36:09 +0200 Subject: [PATCH 0509/1154] implement Storage.flags and related stuff --- firmware/fsm.c | 9 +++++++++ firmware/fsm.h | 1 + firmware/protob/messages.pb.c | 10 ++++++++-- firmware/protob/messages.pb.h | 22 ++++++++++++++++++---- firmware/protob/messages_map.h | 1 + firmware/protob/storage.pb.c | 3 ++- firmware/protob/storage.pb.h | 11 +++++++---- firmware/storage.c | 15 +++++++++++++++ firmware/storage.h | 3 +++ vendor/trezor-common | 2 +- 10 files changed, 65 insertions(+), 12 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index ca9176cf65..85c077bba0 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -235,6 +235,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); + resp->has_flags = true; resp->flags = storage_getFlags(); msg_write(MessageType_MessageType_Features, resp); } @@ -618,6 +619,14 @@ void fsm_msgApplySettings(ApplySettings *msg) layoutHome(); } +void fsm_msgApplyFlags(ApplyFlags *msg) +{ + if (msg->has_flags) { + storage_applyFlags(msg->flags); + } + fsm_sendSuccess(_("Flags applied")); +} + void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); diff --git a/firmware/fsm.h b/firmware/fsm.h index 128c0fb35a..cbd4712c44 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -44,6 +44,7 @@ void fsm_msgTxAck(TxAck *msg); void fsm_msgCipherKeyValue(CipherKeyValue *msg); void fsm_msgClearSession(ClearSession *msg); void fsm_msgApplySettings(ApplySettings *msg); +void fsm_msgApplyFlags(ApplyFlags *msg); //void fsm_msgButtonAck(ButtonAck *msg); void fsm_msgGetAddress(GetAddress *msg); void fsm_msgEntropyAck(EntropyAck *msg); diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 3e1cd9e01f..94abb6f5f2 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -25,7 +25,7 @@ const pb_field_t GetFeatures_fields[1] = { PB_LAST_FIELD }; -const pb_field_t Features_fields[20] = { +const pb_field_t Features_fields[21] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), @@ -45,6 +45,7 @@ const pb_field_t Features_fields[20] = { PB_FIELD2( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), PB_FIELD2( 18, BOOL , OPTIONAL, STATIC , OTHER, Features, firmware_present, passphrase_cached, 0), PB_FIELD2( 19, BOOL , OPTIONAL, STATIC , OTHER, Features, needs_backup, firmware_present, 0), + PB_FIELD2( 20, UINT32 , OPTIONAL, STATIC , OTHER, Features, flags, needs_backup, 0), PB_LAST_FIELD }; @@ -60,6 +61,11 @@ const pb_field_t ApplySettings_fields[5] = { PB_LAST_FIELD }; +const pb_field_t ApplyFlags_fields[2] = { + PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, ApplyFlags, flags, flags, 0), + PB_LAST_FIELD +}; + const pb_field_t ChangePin_fields[2] = { PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), PB_LAST_FIELD @@ -432,7 +438,7 @@ const pb_field_t DebugLinkFlashErase_fields[2] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_EthereumSignMessage_EthereumVerifyMessage_EthereumMessageSignature_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) +STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ApplyFlags_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_EthereumSignMessage_EthereumVerifyMessage_EthereumMessageSignature_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 1000e09725..26f39ec3af 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -40,6 +40,7 @@ typedef enum _MessageType { MessageType_MessageType_ApplySettings = 25, MessageType_MessageType_ButtonRequest = 26, MessageType_MessageType_ButtonAck = 27, + MessageType_MessageType_ApplyFlags = 28, MessageType_MessageType_GetAddress = 29, MessageType_MessageType_Address = 30, MessageType_MessageType_SelfTest = 32, @@ -135,6 +136,11 @@ typedef struct _Address { char address[60]; } Address; +typedef struct _ApplyFlags { + bool has_flags; + uint32_t flags; +} ApplyFlags; + typedef struct { size_t size; uint8_t bytes[1024]; @@ -517,6 +523,8 @@ typedef struct _Features { bool firmware_present; bool has_needs_backup; bool needs_backup; + bool has_flags; + uint32_t flags; } Features; typedef struct _GetAddress { @@ -792,9 +800,10 @@ extern const uint32_t SignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} +#define ApplyFlags_init_default {false, 0} #define ChangePin_init_default {false, 0} #define Ping_init_default {false, "", false, 0, false, 0, false, 0} #define Success_init_default {false, ""} @@ -853,9 +862,10 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} +#define ApplyFlags_init_zero {false, 0} #define ChangePin_init_zero {false, 0} #define Ping_init_zero {false, "", false, 0, false, 0, false, 0} #define Success_init_zero {false, ""} @@ -915,6 +925,7 @@ extern const uint32_t SignTx_lock_time_default; /* Field tags (for use in manual encoding/decoding) */ #define Address_address_tag 1 +#define ApplyFlags_flags_tag 1 #define ApplySettings_language_tag 1 #define ApplySettings_label_tag 2 #define ApplySettings_use_passphrase_tag 3 @@ -999,6 +1010,7 @@ extern const uint32_t SignTx_lock_time_default; #define Features_passphrase_cached_tag 17 #define Features_firmware_present_tag 18 #define Features_needs_backup_tag 19 +#define Features_flags_tag 20 #define GetAddress_address_n_tag 1 #define GetAddress_coin_name_tag 2 #define GetAddress_show_display_tag 3 @@ -1079,9 +1091,10 @@ extern const uint32_t SignTx_lock_time_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t Initialize_fields[1]; extern const pb_field_t GetFeatures_fields[1]; -extern const pb_field_t Features_fields[20]; +extern const pb_field_t Features_fields[21]; extern const pb_field_t ClearSession_fields[1]; extern const pb_field_t ApplySettings_fields[5]; +extern const pb_field_t ApplyFlags_fields[2]; extern const pb_field_t ChangePin_fields[2]; extern const pb_field_t Ping_fields[5]; extern const pb_field_t Success_fields[2]; @@ -1142,9 +1155,10 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (260 + 8*CoinType_size) +#define Features_size (267 + 8*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 +#define ApplyFlags_size 6 #define ChangePin_size 2 #define Ping_size 265 #define Success_size 259 diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h index 326e080d8a..958dfef57b 100644 --- a/firmware/protob/messages_map.h +++ b/firmware/protob/messages_map.h @@ -21,6 +21,7 @@ { 'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *)) fsm_msgClearSession }, { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, // Message ButtonAck is used in tiny mode + { 'n', 'i', MessageType_MessageType_ApplyFlags, ApplyFlags_fields, (void (*)(void *)) fsm_msgApplyFlags }, { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, // Message SelfTest is used in bootloader mode only { 'n', 'i', MessageType_MessageType_BackupDevice, BackupDevice_fields, (void (*)(void *)) fsm_msgBackupDevice }, diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c index 42b05bbca1..42e40039df 100644 --- a/firmware/protob/storage.pb.c +++ b/firmware/protob/storage.pb.c @@ -5,7 +5,7 @@ -const pb_field_t Storage_fields[13] = { +const pb_field_t Storage_fields[14] = { PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), @@ -18,6 +18,7 @@ const pb_field_t Storage_fields[13] = { PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), PB_FIELD2( 11, UINT32 , OPTIONAL, STATIC , OTHER, Storage, u2f_counter, homescreen, 0), PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Storage, needs_backup, u2f_counter, 0), + PB_FIELD2( 13, UINT32 , OPTIONAL, STATIC , OTHER, Storage, flags, needs_backup, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h index c8f20325c4..0478617268 100644 --- a/firmware/protob/storage.pb.h +++ b/firmware/protob/storage.pb.h @@ -41,13 +41,15 @@ typedef struct _Storage { uint32_t u2f_counter; bool has_needs_backup; bool needs_backup; + bool has_flags; + uint32_t flags; } Storage; /* Default values for struct fields */ /* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0} +#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0, false, 0} +#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0, false, 0} /* Field tags (for use in manual encoding/decoding) */ #define Storage_version_tag 1 @@ -62,12 +64,13 @@ typedef struct _Storage { #define Storage_homescreen_tag 10 #define Storage_u2f_counter_tag 11 #define Storage_needs_backup_tag 12 +#define Storage_flags_tag 13 /* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[13]; +extern const pb_field_t Storage_fields[14]; /* Maximum encoded size of messages (where known) */ -#define Storage_size (1367 + HDNodeType_size) +#define Storage_size (1373 + HDNodeType_size) #ifdef __cplusplus } /* extern "C" */ diff --git a/firmware/storage.c b/firmware/storage.c index 6b535c07b6..9764d266d4 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -585,6 +585,21 @@ bool storage_needsBackup(void) return storage.has_needs_backup && storage.needs_backup; } +void storage_applyFlags(uint32_t flags) +{ + if ((storage.flags | flags) == storage.flags) { + return; // no new flags + } + storage.has_flags = true; + storage.flags |= flags; + storage_commit(); +} + +uint32_t storage_getFlags(void) +{ + return storage.has_flags ? storage.flags : 0; +} + uint32_t storage_nextU2FCounter(void) { uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); diff --git a/firmware/storage.h b/firmware/storage.h index d72b4d33d3..18f85d4947 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -70,6 +70,9 @@ bool storage_isInitialized(void); bool storage_needsBackup(void); +void storage_applyFlags(uint32_t flags); +uint32_t storage_getFlags(void); + extern Storage storage; extern char storage_uuid_str[25]; diff --git a/vendor/trezor-common b/vendor/trezor-common index b29b98d69b..2eb9c7e352 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit b29b98d69ba43571dcbe54dc927aa3ecd2b95113 +Subproject commit 2eb9c7e352f708506d910f2d5b9aac1e85cafa10 From 9efc5bc93c91ddcaaaddb5f2d11071766e03acd1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 18 Jul 2017 13:08:27 +0200 Subject: [PATCH 0510/1154] Fixed array sizes again. (#194) This is the correct fix for 09917920ba313da4dcdc7c64d47b014440bf822d (how the code was meant to be written). --- firmware/transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index bb699b052b..5889c97142 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -64,8 +64,8 @@ bool compute_address(const CoinType *coin, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]) { - uint8_t raw[34]; - uint8_t digest[MAX_ADDR_RAW_SIZE]; + uint8_t raw[MAX_ADDR_RAW_SIZE]; + uint8_t digest[32]; size_t prelen; if (has_multisig) { From bf374f17694707c2c754ff26b47c17c7480662bd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Jul 2017 00:08:13 +0200 Subject: [PATCH 0511/1154] bootloader: add RNG test --- bootloader/usb.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 716dcf1706..1760e5b894 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -347,6 +347,27 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) bool status_usb = (buf[9] == 0x0a) && (buf[10] == 53) && (0 == memcmp(buf + 11, "\x00\xFF\x55\xAA\x66\x99\x33\xCC" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!" "\x00\xFF\x55\xAA\x66\x99\x33\xCC", 53)); + // RNG TEST + + layoutProgress("TESTING RNG ...", 0); + uint32_t cnt[256]; + memset(cnt, 0, sizeof(cnt)); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 256000; j++) { + uint32_t r = random32(); + cnt[r & 0xFF]++; + cnt[(r >> 8)& 0xFF]++; + cnt[(r >> 16)& 0xFF]++; + cnt[(r >> 24)& 0xFF]++; + } + layoutProgress("TESTING RNG ...", 100 + (i * 100)); + } + + bool status_rng = true; + for (int i = 0; i < 256; i++) { + status_rng = status_rng && (cnt[i] >= 39000) && (cnt[i] <= 41000); + } + // CPU TEST layoutProgress("TESTING CPU ...", 0); @@ -360,7 +381,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // digest : c84a4cc264100070c8be2acf4072efaadaedfef3d6209c0fe26387e6b1262bbf // sig: : f7869c679bbed1817052affd0264ccc6486795f6d06d0c187651b8f3863670c8 // 2ccf89be32a53eb65ea7c007859783d46717986fead0833ec60c5729cdc4a9ee - status_cpu &= (0 == ecdsa_verify_digest(&secp256k1, + status_cpu = status_cpu && (0 == ecdsa_verify_digest(&secp256k1, (const uint8_t *)"\x04\xa3\x4b\x99\xf2\x2c\x79\x0c\x4e\x36\xb2\xb3\xc2\xc3\x5a\x36\xdb\x06\x22\x6e\x41\xc6\x92\xfc\x82\xb8\xb5\x6a\xc1\xc5\x40\xc5\xbd\x5b\x8d\xec\x52\x35\xa0\xfa\x87\x22\x47\x6c\x77\x09\xc0\x25\x59\xe3\xaa\x73\xaa\x03\x91\x8b\xa2\xd4\x92\xee\xa7\x5a\xbe\xa2\x35", (const uint8_t *)"\xf7\x86\x9c\x67\x9b\xbe\xd1\x81\x70\x52\xaf\xfd\x02\x64\xcc\xc6\x48\x67\x95\xf6\xd0\x6d\x0c\x18\x76\x51\xb8\xf3\x86\x36\x70\xc8\x2c\xcf\x89\xbe\x32\xa5\x3e\xb6\x5e\xa7\xc0\x07\x85\x97\x83\xd4\x67\x17\x98\x6f\xea\xd0\x83\x3e\xc6\x0c\x57\x29\xcd\xc4\xa9\xee", (const uint8_t *)"\xc8\x4a\x4c\xc2\x64\x10\x00\x70\xc8\xbe\x2a\xcf\x40\x72\xef\xaa\xda\xed\xfe\xf3\xd6\x20\x9c\x0f\xe2\x63\x87\xe6\xb1\x26\x2b\xbf")); @@ -405,7 +426,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) bool status_flash = (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)); - bool status_all = status_usb && status_cpu && status_flash; + bool status_all = status_usb && status_rng && status_cpu && status_flash; if (status_all) { send_msg_success(dev); @@ -415,10 +436,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutDialog(status_all ? &bmp_icon_info : &bmp_icon_error, NULL, NULL, NULL, status_usb ? "Test USB ... OK" : "Test USB ... Failed", + status_rng ? "Test RNG ... OK" : "Test RNG ... Failed", status_cpu ? "Test CPU ... OK" : "Test CPU ... Failed", status_flash ? "Test FLASH ... OK" : "Test FLASH ... Failed", NULL, - NULL, NULL ); return; From 61417822700ae0ab96381fb4c6fd27d5f25229d0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Jul 2017 00:12:22 +0200 Subject: [PATCH 0512/1154] bootloader: fix whitespace --- bootloader/usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 1760e5b894..198d21b627 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -356,9 +356,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) for (int j = 0; j < 256000; j++) { uint32_t r = random32(); cnt[r & 0xFF]++; - cnt[(r >> 8)& 0xFF]++; - cnt[(r >> 16)& 0xFF]++; - cnt[(r >> 24)& 0xFF]++; + cnt[(r >> 8) & 0xFF]++; + cnt[(r >> 16) & 0xFF]++; + cnt[(r >> 24) & 0xFF]++; } layoutProgress("TESTING RNG ...", 100 + (i * 100)); } From 980bae6cb5a87f2a5b6e63e2af19e5837afbf2e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Jul 2017 11:39:04 +0200 Subject: [PATCH 0513/1154] bootloader: in self-test perform each step just once --- bootloader/usb.c | 92 ++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 58 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 198d21b627..94639c87e4 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -344,87 +344,63 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (msg_id == 0x0020) { // SelfTest message (id 32) // USB TEST - + layoutProgress("TESTING USB ...", 0); bool status_usb = (buf[9] == 0x0a) && (buf[10] == 53) && (0 == memcmp(buf + 11, "\x00\xFF\x55\xAA\x66\x99\x33\xCC" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!" "\x00\xFF\x55\xAA\x66\x99\x33\xCC", 53)); // RNG TEST - - layoutProgress("TESTING RNG ...", 0); + layoutProgress("TESTING RNG ...", 250); uint32_t cnt[256]; memset(cnt, 0, sizeof(cnt)); - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 256000; j++) { - uint32_t r = random32(); - cnt[r & 0xFF]++; - cnt[(r >> 8) & 0xFF]++; - cnt[(r >> 16) & 0xFF]++; - cnt[(r >> 24) & 0xFF]++; - } - layoutProgress("TESTING RNG ...", 100 + (i * 100)); + for (int i = 0; i < (256 * 2000); i++) { + uint32_t r = random32(); + cnt[r & 0xFF]++; + cnt[(r >> 8) & 0xFF]++; + cnt[(r >> 16) & 0xFF]++; + cnt[(r >> 24) & 0xFF]++; } - bool status_rng = true; for (int i = 0; i < 256; i++) { - status_rng = status_rng && (cnt[i] >= 39000) && (cnt[i] <= 41000); + status_rng = status_rng && (cnt[i] >= 7600) && (cnt[i] <= 8400); } // CPU TEST - - layoutProgress("TESTING CPU ...", 0); - - bool status_cpu = true; - - for (int i = 0; i < 10; i++) { - // privkey : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - // pubkey : 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd - // 5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235 - // digest : c84a4cc264100070c8be2acf4072efaadaedfef3d6209c0fe26387e6b1262bbf - // sig: : f7869c679bbed1817052affd0264ccc6486795f6d06d0c187651b8f3863670c8 - // 2ccf89be32a53eb65ea7c007859783d46717986fead0833ec60c5729cdc4a9ee - status_cpu = status_cpu && (0 == ecdsa_verify_digest(&secp256k1, - (const uint8_t *)"\x04\xa3\x4b\x99\xf2\x2c\x79\x0c\x4e\x36\xb2\xb3\xc2\xc3\x5a\x36\xdb\x06\x22\x6e\x41\xc6\x92\xfc\x82\xb8\xb5\x6a\xc1\xc5\x40\xc5\xbd\x5b\x8d\xec\x52\x35\xa0\xfa\x87\x22\x47\x6c\x77\x09\xc0\x25\x59\xe3\xaa\x73\xaa\x03\x91\x8b\xa2\xd4\x92\xee\xa7\x5a\xbe\xa2\x35", - (const uint8_t *)"\xf7\x86\x9c\x67\x9b\xbe\xd1\x81\x70\x52\xaf\xfd\x02\x64\xcc\xc6\x48\x67\x95\xf6\xd0\x6d\x0c\x18\x76\x51\xb8\xf3\x86\x36\x70\xc8\x2c\xcf\x89\xbe\x32\xa5\x3e\xb6\x5e\xa7\xc0\x07\x85\x97\x83\xd4\x67\x17\x98\x6f\xea\xd0\x83\x3e\xc6\x0c\x57\x29\xcd\xc4\xa9\xee", - (const uint8_t *)"\xc8\x4a\x4c\xc2\x64\x10\x00\x70\xc8\xbe\x2a\xcf\x40\x72\xef\xaa\xda\xed\xfe\xf3\xd6\x20\x9c\x0f\xe2\x63\x87\xe6\xb1\x26\x2b\xbf")); - layoutProgress("TESTING CPU ...", 100 + (i * 100)); - } + layoutProgress("TESTING CPU ...", 500); + // privkey : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + // pubkey : 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd + // 5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235 + // digest : c84a4cc264100070c8be2acf4072efaadaedfef3d6209c0fe26387e6b1262bbf + // sig: : f7869c679bbed1817052affd0264ccc6486795f6d06d0c187651b8f3863670c8 + // 2ccf89be32a53eb65ea7c007859783d46717986fead0833ec60c5729cdc4a9ee + bool status_cpu = (0 == ecdsa_verify_digest(&secp256k1, + (const uint8_t *)"\x04\xa3\x4b\x99\xf2\x2c\x79\x0c\x4e\x36\xb2\xb3\xc2\xc3\x5a\x36\xdb\x06\x22\x6e\x41\xc6\x92\xfc\x82\xb8\xb5\x6a\xc1\xc5\x40\xc5\xbd\x5b\x8d\xec\x52\x35\xa0\xfa\x87\x22\x47\x6c\x77\x09\xc0\x25\x59\xe3\xaa\x73\xaa\x03\x91\x8b\xa2\xd4\x92\xee\xa7\x5a\xbe\xa2\x35", + (const uint8_t *)"\xf7\x86\x9c\x67\x9b\xbe\xd1\x81\x70\x52\xaf\xfd\x02\x64\xcc\xc6\x48\x67\x95\xf6\xd0\x6d\x0c\x18\x76\x51\xb8\xf3\x86\x36\x70\xc8\x2c\xcf\x89\xbe\x32\xa5\x3e\xb6\x5e\xa7\xc0\x07\x85\x97\x83\xd4\x67\x17\x98\x6f\xea\xd0\x83\x3e\xc6\x0c\x57\x29\xcd\xc4\xa9\xee", + (const uint8_t *)"\xc8\x4a\x4c\xc2\x64\x10\x00\x70\xc8\xbe\x2a\xcf\x40\x72\xef\xaa\xda\xed\xfe\xf3\xd6\x20\x9c\x0f\xe2\x63\x87\xe6\xb1\x26\x2b\xbf")); // FLASH TEST - - const uint32_t patterns[] = { 0x00000000, 0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x66666666, 0x99999999, 0x33333333, 0xCCCCCCCC }; - - layoutProgress("TESTING FLASH ...", 0); + layoutProgress("TESTING FLASH ...", 750); // backup metadata backup_metadata(meta_backup); - // write/read test patterns - sha256_Init(&ctx); - - for (int p = 0; p < 8; p++) { - erase_metadata_sectors(); - flash_unlock(); - for (int i = 0; i < FLASH_META_LEN / 4; i++) { - flash_program_word(FLASH_META_START + i * 4, patterns[p]); - } - flash_lock(); - sha256_Update(&ctx, (unsigned char *)FLASH_META_START, FLASH_META_LEN); - layoutProgress("TESTING FLASH ...", 100 + (p * 100)); + // write test pattern + erase_metadata_sectors(); + flash_unlock(); + for (int i = 0; i < FLASH_META_LEN / 4; i++) { + flash_program_word(FLASH_META_START + i * 4, 0x3C695A0F); } + flash_lock(); + + // compute hash of written test pattern + uint8_t hash[32]; + sha256_Raw((unsigned char *)FLASH_META_START, FLASH_META_LEN, hash); // copy metadata back erase_metadata_sectors(); restore_metadata(meta_backup); - // compare against known hash - uint8_t hash[32]; - sha256_Final(&ctx, hash); - - layoutProgress("TESTING FLASH ...", 1000); - - // hash computed via the following Python3 script: - // hashlib.sha256(b''.join([binascii.unhexlify(c * 2 * 32768) for c in '0F5A693C'])).hexdigest() - - bool status_flash = (0 == memcmp(hash, "\x49\x46\xe9\xa5\xf4\xc2\x57\xe9\xcf\xd1\x88\x78\xe9\x66\x9b\x0d\xcd\x4e\x82\x41\xb3\x9c\xee\xb7\x2c\x1d\x14\x4a\xe1\xe4\xcb\xd7", 32)); + // compare against known hash computed via the following Python3 script: + // hashlib.sha256(binascii.unhexlify('0F5A693C' * 8192)).hexdigest() + bool status_flash = (0 == memcmp(hash, "\xa6\xc2\x25\xa4\x76\xa1\xde\x76\x09\xe0\xb0\x07\xf8\xe2\x5a\xec\x1d\x75\x8d\x5c\x36\xc8\x4a\x6b\x75\x4e\xd5\x3d\xe6\x99\x97\x64", 32)); bool status_all = status_usb && status_rng && status_cpu && status_flash; From 1c55ec0fb379e96ca6c5da9df137b5c7b273c313 Mon Sep 17 00:00:00 2001 From: mruddy Date: Wed, 19 Jul 2017 05:54:26 -0400 Subject: [PATCH 0514/1154] fix hangs due to stale rng status (#195) --- Makefile.include | 6 ++++++ firmware/fsm.c | 2 ++ rng.c | 2 +- setup.c | 5 ++++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index 773be5037f..8fba930947 100644 --- a/Makefile.include +++ b/Makefile.include @@ -65,6 +65,12 @@ else CFLAGS += -DMEMORY_PROTECT=1 endif +ifeq ($(DEBUG_RNG), 1) +CFLAGS += -DDEBUG_RNG=1 +else +CFLAGS += -DDEBUG_RNG=0 +endif + LDFLAGS += --static \ -Wl,--start-group \ -lc \ diff --git a/firmware/fsm.c b/firmware/fsm.c index 85c077bba0..dfcef8badc 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -330,12 +330,14 @@ void fsm_msgWipeDevice(WipeDevice *msg) void fsm_msgGetEntropy(GetEntropy *msg) { +#if !DEBUG_RNG layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } +#endif RESP_INIT(Entropy); uint32_t len = msg->size; if (len > 1024) { diff --git a/rng.c b/rng.c index 39aea97710..f9aaf5dee9 100644 --- a/rng.c +++ b/rng.c @@ -27,7 +27,7 @@ uint32_t random32(void) { static uint32_t last = 0, new = 0; while (new == last) { - if (((RNG_SR & (RNG_SR_SEIS | RNG_SR_CEIS)) == 0) && ((RNG_SR & RNG_SR_DRDY) > 0)) { + if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) { new = RNG_DR; } } diff --git a/setup.c b/setup.c index 2537a01436..0795a9b963 100644 --- a/setup.c +++ b/setup.c @@ -42,7 +42,7 @@ void setup(void) // enable RNG rcc_periph_clock_enable(RCC_RNG); - RNG_CR |= RNG_CR_IE | RNG_CR_RNGEN; + RNG_CR |= RNG_CR_RNGEN; // to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1 // we don't use the first random number generated after setting the RNGEN bit in setup random32(); @@ -73,6 +73,9 @@ void setup(void) void setupApp(void) { + // for completeness, disable RNG peripheral interrupts for old bootloaders that had + // enabled them in RNG control register (the RNG interrupt was never enabled in the NVIC) + RNG_CR &= ~RNG_CR_IE; // the static variables in random32 are separate between the bootloader and firmware. // therefore, they need to be initialized here so that we can be sure to avoid dupes. // this is to try to comply with STM32F205xx Reference manual - Section 20.3.1: From 5fa82cc4cb9bc720ed240b1a6ceb63a3c8b97455 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Jul 2017 12:52:36 +0200 Subject: [PATCH 0515/1154] bootloader: align during docker build --- bootloader-docker-build.sh | 2 +- bootloader/firmware_align.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index 7387d6314b..529e1528b5 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -12,7 +12,7 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ git submodule update --init && \ CFLAGS='-std=c99' make -C vendor/libopencm3 && \ make && \ - make -C bootloader && \ + make -C bootloader align && \ cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin" echo "---------------------" diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index 5be6e7163d..b07bf0eb26 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -7,5 +7,5 @@ fs = os.stat(fn).st_size if fs > 32768: raise Exception('bootloader has to be smaller than 32768 bytes') with open(fn, 'ab') as f: - f.write(os.urandom(32768 - fs)) + f.write(b'\xFF' * (32768 - fs)) f.close() From e9fb5b08c7464868da15ea0470d98db7671a1001 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Jul 2017 13:06:10 +0200 Subject: [PATCH 0516/1154] bootloader: use double sha in docker build --- bootloader-docker-build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh index 529e1528b5..28778464e0 100755 --- a/bootloader-docker-build.sh +++ b/bootloader-docker-build.sh @@ -18,6 +18,6 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ echo "---------------------" echo "Bootloader fingerprint:" FILENAME=output/bootloader-$FIRMWARETAG.bin -sha256sum "$FILENAME" +/usr/bin/env python -c "import hashlib ; print(hashlib.sha256(hashlib.sha256(open('$FILENAME', 'rb').read()).digest()).hexdigest())" FILESIZE=$(stat -c%s "$FILENAME") echo "Bootloader size: $FILESIZE bytes (out of 32768 maximum)" From 3d7d0f07347c9e5d0f8e6585f8fb29c98ba6cf50 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 23 Jul 2017 22:20:51 +0200 Subject: [PATCH 0517/1154] use C99 for loop where possible --- firmware/crypto.c | 15 +++++------ firmware/debug.c | 5 ++-- firmware/ethereum.c | 6 ++--- firmware/fsm.c | 2 +- firmware/messages.c | 6 ++--- firmware/pinmatrix.c | 10 +++----- firmware/recovery.c | 43 ++++++++++++++----------------- firmware/reset.c | 10 +++----- firmware/signing.c | 10 +++----- firmware/storage.c | 3 +-- firmware/transaction.c | 22 +++++++--------- firmware/u2f.c | 7 +++-- oled.c | 58 ++++++++++++++++-------------------------- rng.c | 11 +++----- util.c | 6 ++--- 15 files changed, 86 insertions(+), 128 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 06019fbe2d..b27a38946d 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -289,8 +289,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) return 0; } layoutProgressUpdate(true); - uint32_t i; - for (i = 0; i < hdnodepath->address_n_count; i++) { + for (uint32_t i = 0; i < hdnodepath->address_n_count; i++) { if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { return 0; } @@ -301,8 +300,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { - size_t i; - for (i = 0; i < multisig->pubkeys_count; i++) { + for (size_t i = 0; i < multisig->pubkeys_count; i++) { const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { return i; @@ -318,17 +316,16 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t if (n > 15) { return 0; } - uint32_t i, j; // check sanity if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; - for (i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { ptr[i] = &(multisig->pubkeys[i]); if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; if (ptr[i]->node.chain_code.size != 32) return 0; } // minsort according to pubkey - for (i = 0; i < n - 1; i++) { - for (j = n - 1; j > i; j--) { + for (uint32_t i = 0; i < n - 1; i++) { + for (uint32_t j = n - 1; j > i; j--) { if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, 33) > 0) { swap = ptr[i]; ptr[i] = ptr[j]; @@ -340,7 +337,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t SHA256_CTX ctx; sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); - for (i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), sizeof(uint32_t)); diff --git a/firmware/debug.c b/firmware/debug.c index 09d55db7fa..fd72ed29b8 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -26,15 +26,14 @@ void oledDebug(const char *line) { - int i; static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; static char id = 3; - for (i = 0; i < 7; i++) { + for (int i = 0; i < 7; i++) { lines[i] = lines[i + 1]; } lines[7] = line; oledClear(); - for (i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { if (lines[i]) { oledDrawChar(0, i * 8, '0' + (id + i) % 10, 1); oledDrawString(8, i * 8, lines[i]); diff --git a/firmware/ethereum.c b/firmware/ethereum.c index d2913cd6c6..ede2c27ed5 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -283,12 +283,12 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total { char hexdata[3][17]; char summary[20]; - int i; uint32_t printed = 0; - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { uint32_t linelen = len - printed; - if (linelen > 8) + if (linelen > 8) { linelen = 8; + } data2hex(data, linelen, hexdata[i]); data += linelen; printed += linelen; diff --git a/firmware/fsm.c b/firmware/fsm.c index dfcef8badc..47cf932916 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1169,7 +1169,7 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) if (msg->flash) { flash_clear_status_flags(); flash_unlock(); - for (unsigned int i = 0; i < length; i += 4) { + for (uint32_t i = 0; i < length; i += 4) { uint32_t word; memcpy(&word, msg->memory.bytes + i, 4); flash_program_word(msg->address + i, word); diff --git a/firmware/messages.c b/firmware/messages.c index 1e152519be..ad89dc688f 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -143,8 +143,7 @@ static inline void msg_debug_out_pad(void) static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) { (void)stream; - size_t i; - for (i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { msg_out_append(buf[i]); } return true; @@ -155,8 +154,7 @@ static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t cou static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) { (void)stream; - size_t i; - for (i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { msg_debug_out_append(buf[i]); } return true; diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 85d5ef7ed2..b55bfe0f4e 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -33,11 +33,10 @@ void pinmatrix_draw(const char *text) }; oledSwipeLeft(); const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; - int i, j, k; - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { // use (2 - j) instead of j to achieve 789456123 layout - k = pinmatrix_perm[i + (2 - j) * 3] - '0'; + int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; if (text) { oledDrawStringCenter(0, text); } @@ -49,8 +48,7 @@ void pinmatrix_draw(const char *text) void pinmatrix_start(const char *text) { - int i; - for (i = 0; i < 9; i++) { + for (int i = 0; i < 9; i++) { pinmatrix_perm[i] = '1' + i; } pinmatrix_perm[9] = 0; diff --git a/firmware/recovery.c b/firmware/recovery.c index fcbc606b88..473de42162 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -130,11 +130,10 @@ static void recovery_request(void) { * Check mnemonic and send success/failure. */ static void recovery_done(void) { - uint32_t i; char new_mnemonic[sizeof(storage.mnemonic)] = {0}; strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); - for (i = 1; i < word_count; i++) { + for (uint32_t i = 1; i < word_count; i++) { strlcat(new_mnemonic, " ", sizeof(new_mnemonic)); strlcat(new_mnemonic, words[i], sizeof(new_mnemonic)); } @@ -202,9 +201,8 @@ static void recovery_done(void) { */ static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { // assert prefixlen < 4 - int i; char *dest = choice; - for (i = 0; i < prefixlen; i++) { + for (int i = 0; i < prefixlen; i++) { *dest++ = toupper((int) first[i]); } if (first[0] != last[0]) { @@ -216,7 +214,7 @@ static void add_choice(char choice[12], int prefixlen, const char *first, const } else if (prefixlen < 3) { /* AB-AC, etc. */ *dest++ = '-'; - for (i = 0; i < prefixlen; i++) { + for (int i = 0; i < prefixlen; i++) { *dest++ = toupper((int) last[i]); } } else { @@ -240,11 +238,9 @@ static void add_choice(char choice[12], int prefixlen, const char *first, const */ static void display_choices(bool twoColumn, char choices[9][12], int num) { - int i; - int nColumns = twoColumn ? 2 : 3; - int displayedChoices = nColumns * 3; - int row, col; - for (i = 0; i < displayedChoices; i++) { + const int nColumns = twoColumn ? 2 : 3; + const int displayedChoices = nColumns * 3; + for (int i = 0; i < displayedChoices; i++) { word_matrix[i] = i; } /* scramble matrix */ @@ -259,9 +255,9 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) oledBox(0, 27, 127, 63, false); } - for (row = 0; row < 3; row ++) { + for (int row = 0; row < 3; row ++) { int y = 55 - row * 11; - for (col = 0; col < nColumns; col++) { + for (int col = 0; col < nColumns; col++) { int x = twoColumn ? 64 * col + 32 : 42 * col + 22; int choice = word_matrix[nColumns*row + col]; const char *text = choice < num ? choices[choice] : "-"; @@ -276,14 +272,14 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) oledRefresh(); /* avoid picking out of range numbers */ - for (i = 0; i < displayedChoices; i++) { + for (int i = 0; i < displayedChoices; i++) { if (word_matrix[i] > num) word_matrix[i] = 0; } /* two column layout: middle column = right column */ if (twoColumn) { static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 }; - for (i = 8; i >= 2; i--) { + for (int i = 8; i >= 2; i--) { word_matrix[i] = word_matrix[twolayout[i]]; } } @@ -295,15 +291,15 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) static void next_matrix(void) { const char * const *wl = mnemonic_wordlist(); char word_choices[9][12]; - uint32_t i, idx, first, num; + uint32_t idx, num; bool last = (word_index % 4) == 3; switch (word_index % 4) { case 3: idx = TABLE1(word_pincode / 9) + word_pincode % 9; - first = word_table2[idx] & 0xfff; - num = (word_table2[idx+1] & 0xfff) - first; - for (i = 0; i < num; i++) { + const uint32_t first = word_table2[idx] & 0xfff; + num = (word_table2[idx + 1] & 0xfff) - first; + for (uint32_t i = 0; i < num; i++) { strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); } break; @@ -311,7 +307,7 @@ static void next_matrix(void) { case 2: idx = TABLE1(word_pincode); num = TABLE1(word_pincode + 1) - idx; - for (i = 0; i < num; i++) { + for (uint32_t i = 0; i < num; i++) { add_choice(word_choices[i], (word_table2[idx + i] >> 12), wl[TABLE2(idx + i)], wl[TABLE2(idx + i + 1) - 1]); @@ -321,7 +317,7 @@ static void next_matrix(void) { case 1: idx = word_pincode * 9; num = 9; - for (i = 0; i < num; i++) { + for (uint32_t i = 0; i < num; i++) { add_choice(word_choices[i], (word_table1[idx + i] >> 12), wl[TABLE2(TABLE1(idx + i))], wl[TABLE2(TABLE1(idx + i + 1)) - 1]); @@ -330,7 +326,7 @@ static void next_matrix(void) { case 0: num = 9; - for (i = 0; i < num; i++) { + for (uint32_t i = 0; i < num; i++) { add_choice(word_choices[i], 1, wl[TABLE2(TABLE1(9*i))], wl[TABLE2(TABLE1(9*(i+1)))-1]); @@ -437,11 +433,10 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr word_index = 0; next_matrix(); } else { - uint32_t i; - for (i = 0; i < word_count; i++) { + for (uint32_t i = 0; i < word_count; i++) { word_order[i] = i + 1; } - for (i = word_count; i < 24; i++) { + for (uint32_t i = word_count; i < 24; i++) { word_order[i] = 0; } random_permute(word_order, 24); diff --git a/firmware/reset.c b/firmware/reset.c index 2aa6c046f6..5efe7be68b 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -120,13 +120,11 @@ void reset_backup(bool separated) storage.needs_backup = false; storage_commit(); - int pass, word_pos, i = 0, j; - - for (pass = 0; pass < 2; pass++) { - i = 0; - for (word_pos = 1; word_pos <= (int)strength/32*3; word_pos++) { + for (int pass = 0; pass < 2; pass++) { + int i = 0; + for (int word_pos = 1; word_pos <= (int)strength/32*3; word_pos++) { // copy current_word - j = 0; + int j = 0; while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { current_word[j] = storage.mnemonic[i]; i++; j++; diff --git a/firmware/signing.c b/firmware/signing.c index 96e4147325..db395b48cf 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -702,8 +702,6 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (txinput->has_multisig) { - uint32_t r, i, script_len; - int nwitnesses; // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), node.public_key); if (pubkey_idx < 0) { @@ -714,10 +712,10 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - r = 1; // skip number of items (filled in later) + uint32_t r = 1; // skip number of items (filled in later) resp.serialized.serialized_tx.bytes[r] = 0; r++; - nwitnesses = 2; - for (i = 0; i < txinput->multisig.signatures_count; i++) { + int nwitnesses = 2; + for (uint32_t i = 0; i < txinput->multisig.signatures_count; i++) { if (txinput->multisig.signatures[i].size == 0) { continue; } @@ -725,7 +723,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = 1; r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); } - script_len = compile_script_multisig(&txinput->multisig, 0); + uint32_t script_len = compile_script_multisig(&txinput->multisig, 0); r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); r += compile_script_multisig(&txinput->multisig, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.bytes[0] = nwitnesses; diff --git a/firmware/storage.c b/firmware/storage.c index 9764d266d4..35e6fc0634 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -212,8 +212,7 @@ void session_clear(bool clear_pin) } static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) { - int i; - for (i = 0; i < nwords; i++) { + for (int i = 0; i < nwords; i++) { flash_program_word(addr, *src++); addr += 4; } diff --git a/firmware/transaction.c b/firmware/transaction.c index 5889c97142..15674d74b6 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -249,10 +249,10 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 const uint32_t n = multisig->pubkeys_count; if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; - uint32_t i, r = 0; + uint32_t r = 0; if (out) { out[r] = 0x50 + m; r++; - for (i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { out[r] = 33; r++; // OP_PUSH 33 const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (!pubkey) return 0; @@ -279,8 +279,7 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t d[2]; d[0] = 0x50 + m; sha256_Update(&ctx, d, 1); - uint32_t i; - for (i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { d[0] = 33; sha256_Update(&ctx, d, 1); // OP_PUSH 33 const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (!pubkey) return 0; @@ -308,9 +307,9 @@ uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) { - uint32_t i, r = 0; + uint32_t r = 0; out[r] = 0x00; r++; - for (i = 0; i < multisig->signatures_count; i++) { + for (uint32_t i = 0; i < multisig->signatures_count; i++) { if (multisig->signatures[i].size == 0) { continue; } @@ -331,8 +330,7 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) { - int i; - for (i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) { sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1); } sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4); @@ -391,7 +389,6 @@ uint32_t tx_serialize_header_hash(TxStruct *tx) uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) { - int i; if (tx->have_inputs >= tx->inputs_len) { // already got all inputs return 0; @@ -400,7 +397,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out if (tx->have_inputs == 0) { r += tx_serialize_header(tx, out + r); } - for (i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) { *(out + r + i) = input->prev_hash.bytes[31 - i]; } r += 32; @@ -558,9 +555,8 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) sha256_Final(&(t->ctx), hash); sha256_Raw(hash, 32, hash); if (!reverse) return; - uint8_t i, k; - for (i = 0; i < 16; i++) { - k = hash[31 - i]; + for (uint8_t i = 0; i < 16; i++) { + uint8_t k = hash[31 - i]; hash[31 - i] = hash[i]; hash[i] = k; } diff --git a/firmware/u2f.c b/firmware/u2f.c index 7c4a6b899e..cc47b6fa19 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -431,10 +431,9 @@ void u2f_version(const APDU *a) } void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) { - unsigned int i; static char buf[8+2+8+1]; - for (i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { + for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { *appname = u2f_well_known[i].appname; *appicon = u2f_well_known[i].appicon; @@ -473,9 +472,9 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' - uint32_t i, key_path[KEY_PATH_ENTRIES]; + uint32_t key_path[KEY_PATH_ENTRIES]; key_path[0] = U2F_KEY_PATH; - for (i = 1; i < KEY_PATH_ENTRIES; i++) { + for (uint32_t i = 1; i < KEY_PATH_ENTRIES; i++) { // high bit for hardened keys key_path[i]= 0x80000000 | random32(); } diff --git a/oled.c b/oled.c index 095bb02fda..3e1f211410 100644 --- a/oled.c +++ b/oled.c @@ -81,9 +81,8 @@ static bool is_debug_link = 0; */ inline void SPISend(uint32_t base, uint8_t *data, int len) { - int i; delay(1); - for (i = 0; i < len; i++) { + for (int i = 0; i < len; i++) { spi_send(base, data[i]); } while (!(SPI_SR(base) & SPI_SR_TXE)); @@ -219,17 +218,13 @@ void oledClearPixel(int x, int y) void oledDrawChar(int x, int y, char c, int zoom) { - int char_width; - const uint8_t *char_data; - if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - char_width = fontCharWidth(c); - char_data = fontCharData(c); + int char_width = fontCharWidth(c); + const uint8_t *char_data = fontCharData(c); - int xo, yo; - for (xo = 0; xo < char_width; xo++) { - for (yo = 0; yo < FONT_HEIGHT; yo++) { + for (int xo = 0; xo < char_width; xo++) { + for (int yo = 0; yo < FONT_HEIGHT; yo++) { if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { if (zoom <= 1) { oledDrawPixel(x + xo, y + yo); @@ -254,9 +249,8 @@ char oledConvertChar(const char c) { int oledStringWidth(const char *text) { if (!text) return 0; int l = 0; - char c; for (; *text; text++) { - c = oledConvertChar(*text); + char c = oledConvertChar(*text); if (c) { l += fontCharWidth(c) + 1; } @@ -273,9 +267,8 @@ void oledDrawString(int x, int y, const char* text) size = 2; } int l = 0; - char c; for (; *text; text++) { - c = oledConvertChar(*text); + char c = oledConvertChar(*text); if (c) { oledDrawChar(x + l, y, c, size); l += size * (fontCharWidth(c) + 1); @@ -299,9 +292,8 @@ void oledDrawStringRight(int x, int y, const char* text) void oledDrawBitmap(int x, int y, const BITMAP *bmp) { - int i, j; - for (i = 0; i < min(bmp->width, OLED_WIDTH - x); i++) { - for (j = 0; j < min(bmp->height, OLED_HEIGHT - y); j++) { + for (int i = 0; i < min(bmp->width, OLED_WIDTH - x); i++) { + for (int j = 0; j < min(bmp->height, OLED_HEIGHT - y); j++) { if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { OLED_BUFSET(x + i, y + j); } else { @@ -314,9 +306,8 @@ void oledDrawBitmap(int x, int y, const BITMAP *bmp) void oledInvert(int x1, int y1, int x2, int y2) { if ((x1 >= OLED_WIDTH) || (y1 >= OLED_HEIGHT) || (x2 >= OLED_WIDTH) || (y2 >= OLED_HEIGHT)) return; - int x, y; - for (x = x1; x <= x2; x++) { - for (y = y1; y <= y2; y++) { + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { OLED_BUFTGL(x,y); } } @@ -327,17 +318,15 @@ void oledInvert(int x1, int y1, int x2, int y2) */ void oledBox(int x1, int y1, int x2, int y2, bool set) { - int x, y; - for (x = x1; x <= x2; x++) { - for (y = y1; y <= y2; y++) { + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { set ? oledDrawPixel(x, y) : oledClearPixel(x, y); } } } void oledHLine(int y) { - int x; - for (x = 0; x < OLED_WIDTH; x++) { + for (int x = 0; x < OLED_WIDTH; x++) { oledDrawPixel(x, y); } } @@ -347,12 +336,11 @@ void oledHLine(int y) { */ void oledFrame(int x1, int y1, int x2, int y2) { - int x, y; - for (x = x1; x <= x2; x++) { + for (int x = x1; x <= x2; x++) { oledDrawPixel(x, y1); oledDrawPixel(x, y2); } - for (y = y1 + 1; y < y2; y++) { + for (int y = y1 + 1; y < y2; y++) { oledDrawPixel(x1, y); oledDrawPixel(x2, y); } @@ -364,10 +352,9 @@ void oledFrame(int x1, int y1, int x2, int y2) */ void oledSwipeLeft(void) { - int i, j, k; - for (i = 0; i < OLED_WIDTH; i++) { - for (j = 0; j < OLED_HEIGHT / 8; j++) { - for (k = OLED_WIDTH-1; k > 0; k--) { + for (int i = 0; i < OLED_WIDTH; i++) { + for (int j = 0; j < OLED_HEIGHT / 8; j++) { + for (int k = OLED_WIDTH-1; k > 0; k--) { _oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1]; } _oledbuffer[j * OLED_WIDTH] = 0; @@ -382,10 +369,9 @@ void oledSwipeLeft(void) */ void oledSwipeRight(void) { - int i, j, k; - for (i = 0; i < OLED_WIDTH / 4; i++) { - for (j = 0; j < OLED_HEIGHT / 8; j++) { - for (k = 0; k < OLED_WIDTH / 4 - 1; k++) { + for (int i = 0; i < OLED_WIDTH / 4; i++) { + for (int j = 0; j < OLED_HEIGHT / 8; j++) { + for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) { _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 5 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; diff --git a/rng.c b/rng.c index f9aaf5dee9..1df238e872 100644 --- a/rng.c +++ b/rng.c @@ -44,9 +44,8 @@ uint32_t random_uniform(uint32_t n) void random_buffer(uint8_t *buf, size_t len) { - size_t i; uint32_t r = 0; - for (i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { if (i % 4 == 0) { r = random32(); } @@ -56,11 +55,9 @@ void random_buffer(uint8_t *buf, size_t len) void random_permute(char *str, size_t len) { - int i, j; - char t; - for (i = len - 1; i >= 1; i--) { - j = random_uniform(i + 1); - t = str[j]; + for (int i = len - 1; i >= 1; i--) { + int j = random_uniform(i + 1); + char t = str[j]; str[j] = str[i]; str[i] = t; } diff --git a/util.c b/util.c index 7f40f7de44..36b9449e7d 100644 --- a/util.c +++ b/util.c @@ -29,8 +29,7 @@ static const char *hexdigits = "0123456789ABCDEF"; void uint32hex(uint32_t num, char *str) { - uint32_t i; - for (i = 0; i < 8; i++) { + for (uint32_t i = 0; i < 8; i++) { str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; } } @@ -38,9 +37,8 @@ void uint32hex(uint32_t num, char *str) // converts data to hexa void data2hex(const void *data, uint32_t len, char *str) { - uint32_t i; const uint8_t *cdata = (uint8_t *)data; - for (i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { str[i * 2 ] = hexdigits[(cdata[i] >> 4) & 0xF]; str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; } From 184529bbfce81d8d32cc146b297fefd021d98af8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 14:39:15 +0200 Subject: [PATCH 0518/1154] bootloader: erase metadata backup after usage --- bootloader/usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 94639c87e4..f42b2c7441 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -394,9 +394,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) uint8_t hash[32]; sha256_Raw((unsigned char *)FLASH_META_START, FLASH_META_LEN, hash); - // copy metadata back + // restore metadata from backup erase_metadata_sectors(); restore_metadata(meta_backup); + memset(meta_backup, 0, sizeof(meta_backup)); // compare against known hash computed via the following Python3 script: // hashlib.sha256(binascii.unhexlify('0F5A693C' * 8192)).hexdigest() @@ -568,8 +569,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } // erase storage erase_metadata_sectors(); - // copy storage from backup + // restore metadata from backup restore_metadata(meta_backup); + memset(meta_backup, 0, sizeof(meta_backup)); } else { // replace "TRZR" in header with 0000 when hash not confirmed if (!hash_check_ok) { From 37e55bf5a63efaffef092ffa40bbbc95d28ebc56 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 19:44:10 +0200 Subject: [PATCH 0519/1154] build: rework docker build scripts, update readme --- .gitignore | 1 + README.md | 14 ++++++-------- bootloader-docker-build.sh | 23 ----------------------- build-bootloader.sh | 30 ++++++++++++++++++++++++++++++ build-firmware.sh | 30 ++++++++++++++++++++++++++++++ firmware-docker-build.sh | 24 ------------------------ firmware-fingerprint.sh | 18 ------------------ 7 files changed, 67 insertions(+), 73 deletions(-) delete mode 100755 bootloader-docker-build.sh create mode 100755 build-bootloader.sh create mode 100755 build-firmware.sh delete mode 100755 firmware-docker-build.sh delete mode 100755 firmware-fingerprint.sh diff --git a/.gitignore b/.gitignore index 02982714d0..4490fece64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ _attic/ +build/ *.o *.a *.d diff --git a/README.md b/README.md index 0b1c82d7a9..62d2377bb8 100644 --- a/README.md +++ b/README.md @@ -9,25 +9,23 @@ https://trezor.io/ 1. Install Docker 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` -4. `./firmware-docker-build.sh TAG` (where TAG is v1.3.2 for example, if left blank the script builds latest commit) +4. `./build-firmware.sh TAG` (where TAG is v1.5.0 for example, if left blank the script builds latest commit in master branch) -This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log. +This creates file `build/trezor-TAG.bin` and prints its fingerprint and size at the end of the build log. ## How to build TREZOR bootloader? 1. Install Docker 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` -4. `./bootloader-docker-build.sh` +4. `./build-bootloader.sh TAG` (where TAG is bl1.3.2 for example, if left blank the script builds latest commit in master branch) -This creates file `output/bootloader.bin` and prints its fingerprint and size at the last line of the build log. +This creates file `build/bootloader-TAG.bin` and prints its fingerprint and size at the end of the build log. ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? 1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/releases.json 2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/trezor-1.3.6.bin` -3. `./firmware-fingerprint.sh trezor.signed.bin` +3. Compute fingerprint: `tail -c +257 trezor.signed.bin | sha256sum` -Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). - -The reasoning for `firmware-fingerprint.sh` script is that signed firmware has special header holding signatures themselves, which must be avoided while calculating the fingerprint. +Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). Firmware has a special header (of length 256 bytes) holding signatures themselves, which must be avoided while calculating the fingerprint, that's why tail command has to be used. diff --git a/bootloader-docker-build.sh b/bootloader-docker-build.sh deleted file mode 100755 index 28778464e0..0000000000 --- a/bootloader-docker-build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -e - -IMAGETAG=trezor-mcu-build -FIRMWARETAG=${1:-master} - -docker build -t $IMAGETAG . -docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ - cd trezor-mcu && \ - git checkout $FIRMWARETAG && \ - git submodule update --init && \ - CFLAGS='-std=c99' make -C vendor/libopencm3 && \ - make && \ - make -C bootloader align && \ - cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin" - -echo "---------------------" -echo "Bootloader fingerprint:" -FILENAME=output/bootloader-$FIRMWARETAG.bin -/usr/bin/env python -c "import hashlib ; print(hashlib.sha256(hashlib.sha256(open('$FILENAME', 'rb').read()).digest()).hexdigest())" -FILESIZE=$(stat -c%s "$FILENAME") -echo "Bootloader size: $FILESIZE bytes (out of 32768 maximum)" diff --git a/build-bootloader.sh b/build-bootloader.sh new file mode 100755 index 0000000000..1b268935d1 --- /dev/null +++ b/build-bootloader.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +IMAGE=trezor-mcu-build +TAG=${1:-master} +BINFILE=build/bootloader-$TAG.bin + +docker build -t $IMAGE . +docker run -t -v $(pwd)/build:/build $IMAGE /bin/sh -c "\ + git clone https://github.com/trezor/trezor-mcu && \ + cd trezor-mcu && \ + git checkout $TAG && \ + git submodule update --init && \ + CFLAGS='-std=c99' make -C vendor/libopencm3 && \ + make && \ + make -C bootloader && \ + make -C bootloader align && \ + cp bootloader/bootloader.bin /$BINFILE" + +/usr/bin/env python -c " +from __future__ import print_function +import hashlib +import sys +fn = sys.argv[1] +data = open(fn, 'rb').read() +print('\n\n') +print('Filename :', fn) +print('Fingerprint :', hashlib.sha256(hashlib.sha256(data).digest()).hexdigest()) +print('Size : %d bytes (out of %d maximum)' % (len(data), 32768)) +" $BINFILE diff --git a/build-firmware.sh b/build-firmware.sh new file mode 100755 index 0000000000..0603504aee --- /dev/null +++ b/build-firmware.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +IMAGE=trezor-mcu-build +TAG=${1:-master} +BINFILE=build/trezor-$TAG.bin + +docker build -t $IMAGE . +docker run -t -v $(pwd)/build:/build $IMAGE /bin/sh -c "\ + git clone https://github.com/trezor/trezor-mcu && \ + cd trezor-mcu && \ + git checkout $TAG && \ + git submodule update --init && \ + CFLAGS='-std=c99' make -C vendor/libopencm3 && \ + make && \ + make -C firmware && \ + make -C firmware sign && \ + cp firmware/trezor.bin /$BINFILE" + +/usr/bin/env python -c " +from __future__ import print_function +import hashlib +import sys +fn = sys.argv[1] +data = open(fn, 'rb').read() +print('\n\n') +print('Filename :', fn) +print('Fingerprint :', hashlib.sha256(data[256:]).hexdigest()) +print('Size : %d bytes (out of %d maximum)' % (len(data), 491520)) +" $BINFILE diff --git a/firmware-docker-build.sh b/firmware-docker-build.sh deleted file mode 100755 index 7738a98c00..0000000000 --- a/firmware-docker-build.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -set -e - -IMAGETAG=trezor-mcu-build -FIRMWARETAG=${1:-master} - -docker build -t $IMAGETAG . -docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ - cd trezor-mcu && \ - git checkout $FIRMWARETAG && \ - git submodule update --init && \ - CFLAGS='-std=c99' make -C vendor/libopencm3 && \ - make && \ - make -C firmware && \ - make -C firmware sign && \ - cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin" - -echo "---------------------" -echo "Firmware fingerprint:" -FILENAME=output/trezor-$FIRMWARETAG.bin -tail -c +257 "$FILENAME" | sha256sum -FILESIZE=$(stat -c%s "$FILENAME") -echo "Firmware size: $FILESIZE bytes (out of 491520 maximum)" diff --git a/firmware-fingerprint.sh b/firmware-fingerprint.sh deleted file mode 100755 index 3e48bcdb08..0000000000 --- a/firmware-fingerprint.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -set -e - -if [ -z "$1" ]; then - echo "Please provide filename as argument" - exit 1 -fi - -MAGIC=`head -c +4 $1` - -if [ "x$MAGIC" != "xTRZR" ]; then - echo "Missing magic characters 'TRZR', invalid firmware" - exit 1 -fi - -echo "---------------------" -echo "Firmware fingerprint:" -tail -c +257 $1 | sha256sum From 4e58befe5d07fd4467a1cda51ecd0e1e9edc56e9 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 25 Jul 2017 14:24:45 +0200 Subject: [PATCH 0520/1154] Clean-up of oled code. (#197) Get rid of the macros. Use only the functions instead. Optimized some of the functions. --- oled.c | 115 ++++++++++++++++++++++++++++++++++++++------------------- oled.h | 1 + 2 files changed, 77 insertions(+), 39 deletions(-) diff --git a/oled.c b/oled.c index 3e1f211410..de834b2ca5 100644 --- a/oled.c +++ b/oled.c @@ -63,19 +63,48 @@ * display. */ -/* Macros to manipulate a single pixel in _oledbuffer: - * OLED_BUFSET(X,Y) sets pixel X,Y (white) - * OLED_BUFCLR(X,Y) clears pixel X,Y (black) - * OLED_BUFTGL(X,Y) toggles pixel X,Y (inverts it) - */ - -#define OLED_BUFSET(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] |= (1 << (7 - (Y)%8)) -#define OLED_BUFCLR(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] &= ~(1 << (7 - (Y)%8)) -#define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8)) - static uint8_t _oledbuffer[OLED_BUFSIZE]; static bool is_debug_link = 0; +/* + * macros to convert coordinate to bit position + */ +#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y)/8)*OLED_WIDTH) +#define OLED_MASK(x, y) (1 << (7 - (y) % 8)) + +/* + * Draws a white pixel at x, y + */ +void oledDrawPixel(int x, int y) +{ + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] |= OLED_MASK(x, y); +} + +/* + * Clears pixel at x, y + */ +void oledClearPixel(int x, int y) +{ + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] &= ~OLED_MASK(x, y); +} + +/* + * Inverts pixel at x, y + */ +void oledInvertPixel(int x, int y) +{ + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y); +} + /* * Send a block of data via the SPI bus. */ @@ -161,11 +190,11 @@ void oledRefresh() // draw triangle in upper right corner if (is_debug_link) { - OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); - OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); - OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); - OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3); - OLED_BUFTGL(OLED_WIDTH - 1, 4); + oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); + oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); + oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); + oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); + oledInvertPixel(OLED_WIDTH - 1, 4); } gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select @@ -180,11 +209,11 @@ void oledRefresh() // return it back if (is_debug_link) { - OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0); - OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1); - OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2); - OLED_BUFTGL(OLED_WIDTH - 2, 3); OLED_BUFTGL(OLED_WIDTH - 1, 3); - OLED_BUFTGL(OLED_WIDTH - 1, 4); + oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); + oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); + oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); + oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); + oledInvertPixel(OLED_WIDTH - 1, 4); } } @@ -204,25 +233,19 @@ void oledSetBuffer(uint8_t *buf) memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); } -void oledDrawPixel(int x, int y) -{ - if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - OLED_BUFSET(x,y); -} - -void oledClearPixel(int x, int y) -{ - if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; - OLED_BUFCLR(x,y); -} - void oledDrawChar(int x, int y, char c, int zoom) { - if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return; + if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { + return; + } int char_width = fontCharWidth(c); const uint8_t *char_data = fontCharData(c); + if (x <= -char_width) { + return; + } + for (int xo = 0; xo < char_width; xo++) { for (int yo = 0; yo < FONT_HEIGHT; yo++) { if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { @@ -288,27 +311,34 @@ void oledDrawStringRight(int x, int y, const char* text) oledDrawString(x, y, text); } +#define max(X,Y) ((X) > (Y) ? (X) : (Y)) #define min(X,Y) ((X) < (Y) ? (X) : (Y)) void oledDrawBitmap(int x, int y, const BITMAP *bmp) { - for (int i = 0; i < min(bmp->width, OLED_WIDTH - x); i++) { - for (int j = 0; j < min(bmp->height, OLED_HEIGHT - y); j++) { + for (int i = 0; i < bmp->width; i++) { + for (int j = 0; j < bmp->height; j++) { if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { - OLED_BUFSET(x + i, y + j); + oledDrawPixel(x + i, y + j); } else { - OLED_BUFCLR(x + i, y + j); + oledClearPixel(x + i, y + j); } } } } +/* + * Inverts box between (x1,y1) and (x2,y2) inclusive. + */ void oledInvert(int x1, int y1, int x2, int y2) { - if ((x1 >= OLED_WIDTH) || (y1 >= OLED_HEIGHT) || (x2 >= OLED_WIDTH) || (y2 >= OLED_HEIGHT)) return; + x1 = max(x1, 0); + y1 = max(y1, 0); + x2 = min(x2, OLED_WIDTH - 1); + y2 = min(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) { - OLED_BUFTGL(x,y); + oledInvertPixel(x,y); } } } @@ -318,6 +348,10 @@ void oledInvert(int x1, int y1, int x2, int y2) */ void oledBox(int x1, int y1, int x2, int y2, bool set) { + x1 = max(x1, 0); + y1 = max(y1, 0); + x2 = min(x2, OLED_WIDTH - 1); + y2 = min(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) { set ? oledDrawPixel(x, y) : oledClearPixel(x, y); @@ -326,6 +360,9 @@ void oledBox(int x1, int y1, int x2, int y2, bool set) } void oledHLine(int y) { + if (y < 0 || y >= OLED_HEIGHT) { + return; + } for (int x = 0; x < OLED_WIDTH; x++) { oledDrawPixel(x, y); } diff --git a/oled.h b/oled.h index 05b8b0b376..8bf37f79ad 100644 --- a/oled.h +++ b/oled.h @@ -39,6 +39,7 @@ void oledSetBuffer(uint8_t *buf); const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); void oledClearPixel(int x, int y); +void oledInvertPixel(int x, int y); void oledDrawChar(int x, int y, char c, int zoom); int oledStringWidth(const char *text); void oledDrawString(int x, int y, const char* text); From cb020cb1d8497394767c3bd659369b0c1a997478 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Jul 2017 17:24:40 +0200 Subject: [PATCH 0521/1154] bootloader: refactor calculate fingerprint part (not issue button request if brand new firmware) --- bootloader/usb.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index f42b2c7441..42dee2c977 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -314,7 +314,6 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) static uint8_t buf[64] __attribute__((aligned(4))); static uint8_t towrite[4] __attribute__((aligned(4))); static int wi; - static SHA256_CTX ctx; if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; @@ -477,7 +476,6 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } - sha256_Init(&ctx); flash_state = STATE_FLASHING; flash_pos = 0; wi = 0; @@ -530,21 +528,24 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_lock(); // flashing done if (flash_pos == flash_len) { - sha256_Update(&ctx, (unsigned char *)FLASH_APP_START, flash_len - FLASH_META_DESC_LEN); flash_state = STATE_CHECK; - send_msg_buttonrequest_firmwarecheck(dev); + if (!brand_new_firmware) { + send_msg_buttonrequest_firmwarecheck(dev); + return; + } + } else { + return; } - return; } if (flash_state == STATE_CHECK) { - if (msg_id != 0x001B) { // ButtonAck message (id 27) - return; - } - uint8_t hash[32]; - sha256_Final(&ctx, hash); if (!brand_new_firmware) { + if (msg_id != 0x001B) { // ButtonAck message (id 27) + return; + } + uint8_t hash[32]; + sha256_Raw((unsigned char *)FLASH_APP_START, flash_len - FLASH_META_DESC_LEN, hash); layoutFirmwareHash(hash); do { delay(100000); From d8ad44f60af01f1d23808d3f6050b9f2a34f247d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 17:08:09 +0200 Subject: [PATCH 0522/1154] protob: add SignMessage.script_type --- firmware/protob/messages.pb.c | 4 +++- firmware/protob/messages.pb.h | 12 ++++++++---- vendor/trezor-common | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 94abb6f5f2..870818d398 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -11,6 +11,7 @@ const uint32_t ResetDevice_strength_default = 256u; const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; const char SignMessage_coin_name_default[17] = "Bitcoin"; +const InputScriptType SignMessage_script_type_default = InputScriptType_SPENDADDRESS; const char VerifyMessage_coin_name_default[17] = "Bitcoin"; const char SignTx_coin_name_default[17] = "Bitcoin"; const uint32_t SignTx_version_default = 1u; @@ -236,10 +237,11 @@ const pb_field_t WordAck_fields[2] = { PB_LAST_FIELD }; -const pb_field_t SignMessage_fields[4] = { +const pb_field_t SignMessage_fields[5] = { PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), + PB_FIELD2( 4, ENUM , OPTIONAL, STATIC , OTHER, SignMessage, script_type, coin_name, &SignMessage_script_type_default), PB_LAST_FIELD }; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 26f39ec3af..b6166a5913 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -702,6 +702,8 @@ typedef struct _SignMessage { SignMessage_message_t message; bool has_coin_name; char coin_name[17]; + bool has_script_type; + InputScriptType script_type; } SignMessage; typedef struct _SignTx { @@ -792,6 +794,7 @@ extern const uint32_t ResetDevice_strength_default; extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; extern const char SignMessage_coin_name_default[17]; +extern const InputScriptType SignMessage_script_type_default; extern const char VerifyMessage_coin_name_default[17]; extern const char SignTx_coin_name_default[17]; extern const uint32_t SignTx_version_default; @@ -832,7 +835,7 @@ extern const uint32_t SignTx_lock_time_default; #define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0, false, 0} #define WordRequest_init_default {false, (WordRequestType)0} #define WordAck_init_default {""} -#define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin"} +#define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin", false, InputScriptType_SPENDADDRESS} #define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} #define MessageSignature_init_default {false, "", false, {0, {0}}} #define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} @@ -894,7 +897,7 @@ extern const uint32_t SignTx_lock_time_default; #define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0, false, 0} #define WordRequest_init_zero {false, (WordRequestType)0} #define WordAck_init_zero {""} -#define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, ""} +#define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "", false, (InputScriptType)0} #define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} #define MessageSignature_init_zero {false, "", false, {0, {0}}} #define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} @@ -1068,6 +1071,7 @@ extern const uint32_t SignTx_lock_time_default; #define SignMessage_address_n_tag 1 #define SignMessage_message_tag 2 #define SignMessage_coin_name_tag 3 +#define SignMessage_script_type_tag 4 #define SignTx_outputs_count_tag 1 #define SignTx_inputs_count_tag 2 #define SignTx_coin_name_tag 3 @@ -1123,7 +1127,7 @@ extern const pb_field_t EntropyAck_fields[2]; extern const pb_field_t RecoveryDevice_fields[10]; extern const pb_field_t WordRequest_fields[2]; extern const pb_field_t WordAck_fields[2]; -extern const pb_field_t SignMessage_fields[4]; +extern const pb_field_t SignMessage_fields[5]; extern const pb_field_t VerifyMessage_fields[5]; extern const pb_field_t MessageSignature_fields[3]; extern const pb_field_t CipherKeyValue_fields[8]; @@ -1187,7 +1191,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define RecoveryDevice_size 80 #define WordRequest_size 6 #define WordAck_size 14 -#define SignMessage_size 1094 +#define SignMessage_size 1100 #define VerifyMessage_size 1156 #define MessageSignature_size 110 #define CipherKeyValue_size 1358 diff --git a/vendor/trezor-common b/vendor/trezor-common index 2eb9c7e352..00900951e0 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 2eb9c7e352f708506d910f2d5b9aac1e85cafa10 +Subproject commit 00900951e072aaa2d7c48da807bb0032b6b898c1 From b5f9a5738f558002c3c41d67ff8230483a98047d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Jul 2017 17:40:46 +0200 Subject: [PATCH 0523/1154] segwit support for SignMessage, VerifyMessage --- firmware/crypto.c | 65 +++++++++++++++++++++++++------- firmware/crypto.h | 2 +- firmware/fsm.c | 11 ++++-- firmware/protob/messages.options | 8 ++-- firmware/protob/messages.pb.h | 12 +++--- firmware/transaction.c | 11 +----- vendor/trezor-crypto | 2 +- 7 files changed, 73 insertions(+), 38 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index b27a38946d..590675c3e6 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -20,6 +20,7 @@ #include #include "crypto.h" #include "sha2.h" +#include "ripemd160.h" #include "pbkdf2.h" #include "aes.h" #include "hmac.h" @@ -109,7 +110,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin } } -int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) +int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -124,34 +125,48 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message uint8_t pby; int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); if (result == 0) { - signature[0] = 27 + pby + 4; + switch (script_type) { + case InputScriptType_SPENDP2SHWITNESS: + // segwit-in-p2sh + signature[0] = 35 + pby; + break; + case InputScriptType_SPENDWITNESS: + // segwit + signature[0] = 39 + pby; + break; + default: + // p2pkh + signature[0] = 31 + pby; + break; + } } return result; } int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) { - SHA256_CTX ctx; - uint8_t pubkey[65], addr_raw[MAX_ADDR_RAW_SIZE], hash[32]; + // check for invalid signature prefix + if (signature[0] < 27 || signature[0] > 43) { + return 1; + } // calculate hash + SHA256_CTX ctx; sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); sha256_Update(&ctx, varint, l); sha256_Update(&ctx, message, message_len); + uint8_t hash[32]; sha256_Final(&ctx, hash); sha256_Raw(hash, 32, hash); - uint8_t recid = signature[0] - 27; - if (recid >= 8) { - return 1; - } - bool compressed = (recid >= 4); - recid &= 3; + uint8_t recid = (signature[0] - 27) % 4; + bool compressed = signature[0] >= 31; // check if signature verifies the digest and recover the public key + uint8_t pubkey[65]; if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) { return 3; } @@ -159,11 +174,35 @@ int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t mes if (compressed) { pubkey[0] = 0x02 | (pubkey[64] & 1); } + // check if the address is correct - ecdsa_get_address_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { - return 2; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + + // p2pkh + if (signature[0] >= 27 && signature[0] <= 34) { + if (address_type != coin->address_type) { + return 4; + } + ecdsa_get_address_raw(pubkey, address_type, addr_raw); + if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + return 2; + } + } else + // segwit-in-p2sh + if (signature[0] >= 35 && signature[0] <= 38) { + if (address_type != coin->address_type_p2sh) { + return 4; + } + ecdsa_get_address_segwit_p2sh_raw(pubkey, address_type, addr_raw); + if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + return 2; + } + } else + // segwit + if (signature[0] >= 39 && signature[0] <= 42) { + return 2; // not supported yet } + return 0; } diff --git a/firmware/crypto.h b/firmware/crypto.h index 1f211c37f4..2c52cb330f 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -37,7 +37,7 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageSign(const CoinType *coin, HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); diff --git a/firmware/fsm.c b/firmware/fsm.c index 47cf932916..44d7cc8506 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -795,9 +795,14 @@ void fsm_msgSignMessage(SignMessage *msg) if (!node) return; layoutProgressSwipe(_("Signing"), 0); - if (cryptoMessageSign(coin, node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { + if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { resp->has_address = true; - hdnode_get_address(node, coin->address_type, resp->address, sizeof(resp->address)); + hdnode_fill_public_key(node); + if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); + layoutHome(); + return; + } resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); @@ -890,7 +895,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(&(coins[0]), node, digest, 64, resp->signature.bytes); + result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); } if (result == 0) { diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index d3ccac9ea0..47d0d9b2ca 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -57,12 +57,12 @@ SignMessage.address_n max_count:8 SignMessage.message max_size:1024 SignMessage.coin_name max_size:17 -VerifyMessage.address max_size:41 +VerifyMessage.address max_size:60 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 VerifyMessage.coin_name max_size:17 -MessageSignature.address max_size:41 +MessageSignature.address max_size:60 MessageSignature.signature max_size:65 EthereumSignMessage.address_n max_count:8 @@ -97,7 +97,7 @@ DecryptMessage skip_message:true # deprecated DecryptedMessage skip_message:true -# DecryptedMessage.address max_size:41 +# DecryptedMessage.address max_size:60 # DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 @@ -133,7 +133,7 @@ SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 SignIdentity.ecdsa_curve_name max_size:32 -SignedIdentity.address max_size:41 +SignedIdentity.address max_size:60 SignedIdentity.public_key max_size:33 SignedIdentity.signature max_size:65 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index b6166a5913..3ebb54e19a 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -595,7 +595,7 @@ typedef struct { typedef struct _MessageSignature { bool has_address; - char address[41]; + char address[60]; bool has_signature; MessageSignature_signature_t signature; } MessageSignature; @@ -729,7 +729,7 @@ typedef struct { typedef struct _SignedIdentity { bool has_address; - char address[41]; + char address[60]; bool has_public_key; SignedIdentity_public_key_t public_key; bool has_signature; @@ -767,7 +767,7 @@ typedef struct { typedef struct _VerifyMessage { bool has_address; - char address[41]; + char address[60]; bool has_signature; VerifyMessage_signature_t signature; bool has_message; @@ -1192,8 +1192,8 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define WordRequest_size 6 #define WordAck_size 14 #define SignMessage_size 1100 -#define VerifyMessage_size 1156 -#define MessageSignature_size 110 +#define VerifyMessage_size 1175 +#define MessageSignature_size 129 #define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 #define SignTx_size 43 @@ -1206,7 +1206,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define EthereumVerifyMessage_size 1116 #define EthereumMessageSignature_size 89 #define SignIdentity_size (558 + IdentityType_size) -#define SignedIdentity_size 145 +#define SignedIdentity_size 164 #define GetECDHSessionKey_size (107 + IdentityType_size) #define ECDHSessionKey_size 67 #define SetU2FCounter_size 6 diff --git a/firmware/transaction.c b/firmware/transaction.c index 15674d74b6..7e0263279e 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -124,16 +124,7 @@ bool compute_address(const CoinType *coin, if (!coin->has_address_type_p2sh) { return 0; } - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - raw[0] = 0; // version byte - raw[1] = 20; // push 20 bytes - ecdsa_get_pubkeyhash(node->public_key, raw + 2); - sha256_Raw(raw, 22, digest); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { - return 0; - } + ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, address, MAX_ADDR_SIZE); } else { ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE); } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index cfe8f39cd4..dfdb4d2d76 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit cfe8f39cd436bf98e864775a9131e81e554e7bf1 +Subproject commit dfdb4d2d766506e9f54dd2c69c5e664fe4e39304 From c3bf0e4086665730bc8917fb00ac946dee19e4ad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 25 Jul 2017 19:30:54 +0200 Subject: [PATCH 0524/1154] enable segwit for bitcoin \o/ --- firmware/coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/coins.c b/firmware/coins.c index 5331732313..aea568101e 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,7 +26,7 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, + {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, }, {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, From 38b6332db525ba7550e9f8ff1df44f9d1fd9bfe5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 16:51:54 +0100 Subject: [PATCH 0525/1154] layout2: Extract BITCOIN_DIVISIBILITY constant --- firmware/layout2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index e1cb27cfbc..e9a5578f60 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -32,6 +32,8 @@ #include "bignum.h" #include "gettext.h" +#define BITCOIN_DIVISIBILITY (8) + void *layoutLast = layoutHome; void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) @@ -98,7 +100,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) char str_out[32]; bignum256 amnt; bn_read_uint64(out->amount, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_out, sizeof(str_out)); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_out, sizeof(str_out)); static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); layoutDialogSwipe(&bmp_icon_question, @@ -119,9 +121,9 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ char str_out[32], str_fee[32]; bignum256 amnt; bn_read_uint64(amount_out, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_out, sizeof(str_out)); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_out, sizeof(str_out)); bn_read_uint64(amount_fee, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), @@ -140,7 +142,7 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) char str_fee[32]; bignum256 amnt; bn_read_uint64(fee, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, 8, str_fee, sizeof(str_fee)); + bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), From 11d424cdef7992dee5bfad833d08e2b2117767f1 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 16:54:04 +0100 Subject: [PATCH 0526/1154] vendor: Update trezor-crypto --- firmware/ethereum.c | 2 +- firmware/layout2.c | 15 ++++----------- vendor/trezor-crypto | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index ede2c27ed5..cf8e9a7fc6 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -228,7 +228,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, default: suffix = " UNKN"; break; // unknown chain } } - bn_format(amnt, NULL, suffix, decimals, buf, buflen); + bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); } static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token) diff --git a/firmware/layout2.c b/firmware/layout2.c index e9a5578f60..c456987317 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -98,9 +98,7 @@ void layoutHome(void) void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) { char str_out[32]; - bignum256 amnt; - bn_read_uint64(out->amount, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_out, sizeof(str_out)); + bn_format_uint64(out->amount, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); layoutDialogSwipe(&bmp_icon_question, @@ -119,11 +117,8 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee) { char str_out[32], str_fee[32]; - bignum256 amnt; - bn_read_uint64(amount_out, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_out, sizeof(str_out)); - bn_read_uint64(amount_fee, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_fee, sizeof(str_fee)); + bn_format_uint64(amount_out, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); + bn_format_uint64(amount_fee, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), @@ -140,9 +135,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) { char str_fee[32]; - bignum256 amnt; - bn_read_uint64(fee, &amnt); - bn_format(&amnt, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, str_fee, sizeof(str_fee)); + bn_format_uint64(fee, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index dfdb4d2d76..66993f9e92 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit dfdb4d2d766506e9f54dd2c69c5e664fe4e39304 +Subproject commit 66993f9e9248d9d74a0c9997a95461bcd4a9dbe8 From e33e1ec0b1b009c9933cc6f2510dcc47b52ae700 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 29 Jul 2017 21:08:51 +0100 Subject: [PATCH 0527/1154] fsm: Do not wipe msg_resp in DebugLinkGetState --- firmware/fsm.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 44d7cc8506..9f6237d1fd 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1108,46 +1108,50 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg) void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) { (void)msg; - RESP_INIT(DebugLinkState); - resp->has_layout = true; - resp->layout.size = OLED_BUFSIZE; - memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + // Do not use RESP_INIT because it clears msg_resp, but another message + // might be being handled + DebugLinkState resp; + memset(&resp, 0, sizeof(resp)); + + resp.has_layout = true; + resp.layout.size = OLED_BUFSIZE; + memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); if (storage.has_pin) { - resp->has_pin = true; - strlcpy(resp->pin, storage.pin, sizeof(resp->pin)); + resp.has_pin = true; + strlcpy(resp.pin, storage.pin, sizeof(resp.pin)); } - resp->has_matrix = true; - strlcpy(resp->matrix, pinmatrix_get(), sizeof(resp->matrix)); + resp.has_matrix = true; + strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); - resp->has_reset_entropy = true; - resp->reset_entropy.size = reset_get_int_entropy(resp->reset_entropy.bytes); + resp.has_reset_entropy = true; + resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); - resp->has_reset_word = true; - strlcpy(resp->reset_word, reset_get_word(), sizeof(resp->reset_word)); + resp.has_reset_word = true; + strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); - resp->has_recovery_fake_word = true; - strlcpy(resp->recovery_fake_word, recovery_get_fake_word(), sizeof(resp->recovery_fake_word)); + resp.has_recovery_fake_word = true; + strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); - resp->has_recovery_word_pos = true; - resp->recovery_word_pos = recovery_get_word_pos(); + resp.has_recovery_word_pos = true; + resp.recovery_word_pos = recovery_get_word_pos(); if (storage.has_mnemonic) { - resp->has_mnemonic = true; - strlcpy(resp->mnemonic, storage.mnemonic, sizeof(resp->mnemonic)); + resp.has_mnemonic = true; + strlcpy(resp.mnemonic, storage.mnemonic, sizeof(resp.mnemonic)); } if (storage.has_node) { - resp->has_node = true; - memcpy(&(resp->node), &(storage.node), sizeof(HDNode)); + resp.has_node = true; + memcpy(&(resp.node), &(storage.node), sizeof(HDNode)); } - resp->has_passphrase_protection = true; - resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; + resp.has_passphrase_protection = true; + resp.passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; - msg_debug_write(MessageType_MessageType_DebugLinkState, resp); + msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } void fsm_msgDebugLinkStop(DebugLinkStop *msg) From 0760ff046863d0b23f03a4412248cdc4d0d6712a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 26 Jul 2017 16:50:52 +0200 Subject: [PATCH 0528/1154] setup: move stack smashing protection code to setup.c --- bootloader/bootloader.c | 8 +------- firmware/trezor.c | 8 +------- setup.c | 10 ++++++++++ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 7d6fe762cc..43fea05a0c 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -120,13 +120,7 @@ void bootloader_loop(void) usbLoop(firmware_present()); } -uint32_t __stack_chk_guard; - -void __attribute__((noreturn)) __stack_chk_fail(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever -} +extern uint32_t __stack_chk_guard; int main(void) { diff --git a/firmware/trezor.c b/firmware/trezor.c index d9febae6c4..56e096c39f 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -31,13 +31,7 @@ #include "buttons.h" #include "fastflash.h" -uint32_t __stack_chk_guard; - -void __attribute__((noreturn)) __stack_chk_fail(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever -} +extern uint32_t __stack_chk_guard; void check_lock_screen(void) { diff --git a/setup.c b/setup.c index 0795a9b963..512eaf72cc 100644 --- a/setup.c +++ b/setup.c @@ -21,7 +21,17 @@ #include #include #include + #include "rng.h" +#include "layout.h" + +uint32_t __stack_chk_guard; + +void __attribute__((noreturn)) __stack_chk_fail(void) +{ + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever +} void setup(void) { From c8ddd904099d4b082220a684980806108a2eae47 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 26 Jul 2017 16:51:27 +0200 Subject: [PATCH 0529/1154] setup: enable Clock Security System interrupt --- setup.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/setup.c b/setup.c index 512eaf72cc..cf2726a8a6 100644 --- a/setup.c +++ b/setup.c @@ -33,6 +33,15 @@ void __attribute__((noreturn)) __stack_chk_fail(void) for (;;) {} // loop forever } +void nmi_handler(void) +{ + // Clock Security System triggered NMI + if ((RCC_CIR & RCC_CIR_CSSF) != 0) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Clock instability", "detected.", NULL, "Please unplug", "the device.", NULL); + for (;;) {} // loop forever + } +} + void setup(void) { // setup clock @@ -57,6 +66,9 @@ void setup(void) // we don't use the first random number generated after setting the RNGEN bit in setup random32(); + // enable CSS (Clock Security System) + RCC_CR |= RCC_CR_CSSON; + // set GPIO for buttons gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5); @@ -92,6 +104,10 @@ void setupApp(void) // "Each subsequent generated random number has to be compared with the previously generated // number. The test fails if any two compared numbers are equal (continuous random number generator test)." random32(); + + // enable CSS (Clock Security System) + RCC_CR |= RCC_CR_CSSON; + // hotfix for old bootloader gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); From 91c4cbdbd0621ca4c3869cc03d9ac7b497eb162f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Jul 2017 21:50:36 +0200 Subject: [PATCH 0530/1154] setup: move stack protector variable to setup.h --- bootloader/bootloader.c | 2 -- demo/demo.c | 8 -------- firmware/trezor.c | 2 -- setup.h | 4 ++++ 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 43fea05a0c..1a3c0c2db4 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -120,8 +120,6 @@ void bootloader_loop(void) usbLoop(firmware_present()); } -extern uint32_t __stack_chk_guard; - int main(void) { #ifndef APPVER diff --git a/demo/demo.c b/demo/demo.c index d6f75c74b0..86c4c13a40 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -238,14 +238,6 @@ void usbInit(void) usbd_register_set_config_callback(usbd_dev, hid_set_config); } -uint32_t __stack_chk_guard; - -void __attribute__((noreturn)) __stack_chk_fail(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever -} - int main(void) { #ifndef APPVER diff --git a/firmware/trezor.c b/firmware/trezor.c index 56e096c39f..73462ba6e4 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -31,8 +31,6 @@ #include "buttons.h" #include "fastflash.h" -extern uint32_t __stack_chk_guard; - void check_lock_screen(void) { buttonUpdate(); diff --git a/setup.h b/setup.h index ece89a52c4..4e6865fef2 100644 --- a/setup.h +++ b/setup.h @@ -20,6 +20,10 @@ #ifndef __SETUP_H__ #define __SETUP_H__ +#include + +extern uint32_t __stack_chk_guard; + void setup(void); void setupApp(void); From 469073b3501aa229ca2494661fb03b0b89f69c41 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Jul 2017 21:57:32 +0200 Subject: [PATCH 0531/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 66993f9e92..6580044196 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 66993f9e9248d9d74a0c9997a95461bcd4a9dbe8 +Subproject commit 658004419635505ac75300870a0bbc049ad354ee From 841af5406108736ba89578b587ed145f710c54d9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 25 Jul 2017 15:23:10 +0100 Subject: [PATCH 0532/1154] vendor: Update trezor-common --- firmware/coins-gen.py | 5 ++++- firmware/coins.c | 18 ++++++++++-------- firmware/coins.h | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- firmware/protob/types.pb.c | 3 ++- firmware/protob/types.pb.h | 11 +++++++---- vendor/trezor-common | 2 +- 8 files changed, 30 insertions(+), 21 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 59c88a868f..ca05d43406 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -32,7 +32,10 @@ for c in coins: '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000', 'true' if c['segwit'] is not None else 'false', - 'true' if c['segwit'] else 'false' + 'true' if c['segwit'] else 'false', + + 'true' if c['forkid'] is not None else 'false', + '%d' % c['forkid'] if c['forkid'] else '0' ]) for j in range(len(fields[0])): diff --git a/firmware/coins.c b/firmware/coins.c index aea568101e..8525d05006 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,14 +26,16 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, }, - {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, }, - {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, }, - {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, }, - {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, }, - {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, }, - {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, }, - {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, }, + {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, false, 0, }, + {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, + {true, "Bitcoin Cash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, + {true, "Testnet Cash", true, " TBCH", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, true, 0, }, + {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, + {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, false, 0, }, + {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, false, 0, }, + {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, false, 0, }, + {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, + {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, false, 0, }, }; const CoinType *coinByName(const char *name) diff --git a/firmware/coins.h b/firmware/coins.h index 1ae87eb846..42e9e2f915 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 8 +#define COINS_COUNT 10 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 47d0d9b2ca..a6aa613c5f 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:8 +Features.coins max_count:10 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 3ebb54e19a..25beba025d 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -506,7 +506,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[8]; + CoinType coins[10]; bool has_initialized; bool initialized; bool has_revision; @@ -803,7 +803,7 @@ extern const uint32_t SignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_default {false, 0} @@ -865,7 +865,7 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_zero {false, 0} @@ -1159,7 +1159,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (267 + 8*CoinType_size) +#define Features_size (279 + 10*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ApplyFlags_size 6 diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c index c35f3d10d8..7974a2811f 100644 --- a/firmware/protob/types.pb.c +++ b/firmware/protob/types.pb.c @@ -28,7 +28,7 @@ const pb_field_t HDNodePathType_fields[3] = { PB_LAST_FIELD }; -const pb_field_t CoinType_fields[10] = { +const pb_field_t CoinType_fields[11] = { PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), @@ -38,6 +38,7 @@ const pb_field_t CoinType_fields[10] = { PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), PB_FIELD2( 11, BOOL , OPTIONAL, STATIC , OTHER, CoinType, segwit, xprv_magic, 0), + PB_FIELD2( 12, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, forkid, segwit, 0), PB_LAST_FIELD }; diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h index 8ddbee4ffe..9bfd3dd9df 100644 --- a/firmware/protob/types.pb.h +++ b/firmware/protob/types.pb.h @@ -100,6 +100,8 @@ typedef struct _CoinType { uint32_t xprv_magic; bool has_segwit; bool segwit; + bool has_forkid; + uint32_t forkid; } CoinType; typedef struct { @@ -299,7 +301,7 @@ extern const uint32_t IdentityType_index_default; /* Initializer values for message structs */ #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, "", false, 76067358u, false, 76066276u, false, 0} +#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, "", false, 76067358u, false, 76066276u, false, 0, false, 0} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} @@ -310,7 +312,7 @@ extern const uint32_t IdentityType_index_default; #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0} +#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} @@ -330,6 +332,7 @@ extern const uint32_t IdentityType_index_default; #define CoinType_xpub_magic_tag 9 #define CoinType_xprv_magic_tag 10 #define CoinType_segwit_tag 11 +#define CoinType_forkid_tag 12 #define HDNodeType_depth_tag 1 #define HDNodeType_fingerprint_tag 2 #define HDNodeType_child_num_tag 3 @@ -389,7 +392,7 @@ extern const uint32_t IdentityType_index_default; /* Struct field encoding specification for nanopb */ extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[10]; +extern const pb_field_t CoinType_fields[11]; extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxOutputType_fields[7]; @@ -402,7 +405,7 @@ extern const pb_field_t IdentityType_fields[7]; /* Maximum encoded size of messages (where known) */ #define HDNodeType_size 121 #define HDNodePathType_size 171 -#define CoinType_size 101 +#define CoinType_size 107 #define MultisigRedeemScriptType_size 3741 #define TxInputType_size 5508 #define TxOutputType_size 3947 diff --git a/vendor/trezor-common b/vendor/trezor-common index 00900951e0..dc1ed85c96 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 00900951e072aaa2d7c48da807bb0032b6b898c1 +Subproject commit dc1ed85c96e3766f9e99dc4c8af12ecf6de22f1e From a34554b091b36a1f44858e3dc37427c4b8275899 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 25 Jul 2017 15:24:24 +0100 Subject: [PATCH 0533/1154] signing: Add SIGHASH_FORKID support --- firmware/signing.c | 69 +++++++++++++++++++++++++++++++----------- firmware/transaction.c | 8 ++--- firmware/transaction.h | 4 +-- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index db395b48cf..e4baf14fdc 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -67,6 +67,11 @@ static uint8_t multisig_fp[32]; static uint32_t in_address_n[8]; static size_t in_address_n_count; +enum { + SIGHASH_ALL = 1, + SIGHASH_FORKID = 0x40, +}; + /* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. @@ -605,6 +610,23 @@ static void phase1_request_next_output(void) { } } +static void signing_hash_bip143(const TxInputType *txinput, uint8_t sighash, uint32_t forkid, uint8_t *hash) { + uint32_t hash_type = (forkid << 8) | sighash; + sha256_Init(&hashers[0]); + sha256_Update(&hashers[0], (const uint8_t *)&version, 4); + sha256_Update(&hashers[0], hash_prevouts, 32); + sha256_Update(&hashers[0], hash_sequence, 32); + tx_prevout_hash(&hashers[0], txinput); + tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); + sha256_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); + tx_sequence_hash(&hashers[0], txinput); + sha256_Update(&hashers[0], hash_outputs, 32); + sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); + sha256_Update(&hashers[0], (const uint8_t*) &hash_type, 4); + sha256_Final(&hashers[0], hash); + sha256_Raw(hash, 32, hash); +} + static bool signing_sign_input(void) { uint8_t hash[32]; sha256_Final(&hashers[0], hash); @@ -614,7 +636,33 @@ static bool signing_sign_input(void) { signing_abort(); return false; } - tx_hash_final(&ti, hash, false); + + uint8_t sighash; + if (coin->has_forkid) { + if (!compile_input_script_sig(&input)) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + signing_abort(); + return false; + } + if (!input.has_amount) { + fsm_sendFailure(FailureType_Failure_DataError, _("SIGHASH_FORKID input without amount")); + signing_abort(); + return false; + } + if (input.amount > to_spend) { + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + signing_abort(); + return false; + } + to_spend -= input.amount; + + sighash = SIGHASH_ALL | SIGHASH_FORKID; + signing_hash_bip143(&input, sighash, coin->forkid, hash); + } else { + sighash = SIGHASH_ALL; + tx_hash_final(&ti, hash, false); + } + resp.has_serialized = true; resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; @@ -637,14 +685,14 @@ static bool signing_sign_input(void) { } memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - input.script_sig.size = serialize_script_multisig(&(input.multisig), input.script_sig.bytes); + input.script_sig.size = serialize_script_multisig(&(input.multisig), sighash, input.script_sig.bytes); if (input.script_sig.size == 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); signing_abort(); return false; } } else { // SPENDADDRESS - input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, input.script_sig.bytes); + input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, sighash, input.script_sig.bytes); } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); return true; @@ -653,7 +701,6 @@ static bool signing_sign_input(void) { static bool signing_sign_segwit_input(TxInputType *txinput) { // idx1: index to sign uint8_t hash[32]; - uint32_t sighash = 1; if (txinput->script_type == InputScriptType_SPENDWITNESS || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { @@ -675,19 +722,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { } segwit_to_spend -= txinput->amount; - sha256_Init(&hashers[0]); - sha256_Update(&hashers[0], (const uint8_t *)&version, 4); - sha256_Update(&hashers[0], hash_prevouts, 32); - sha256_Update(&hashers[0], hash_sequence, 32); - tx_prevout_hash(&hashers[0], txinput); - tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); - sha256_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); - tx_sequence_hash(&hashers[0], txinput); - sha256_Update(&hashers[0], hash_outputs, 32); - sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); - sha256_Update(&hashers[0], (const uint8_t*) &sighash, 4); - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); + signing_hash_bip143(txinput, SIGHASH_ALL, 0, hash); resp.has_serialized = true; resp.serialized.has_signature_index = true; diff --git a/firmware/transaction.c b/firmware/transaction.c index 7e0263279e..c282e67c94 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -285,18 +285,18 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, return 1; } -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out) +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out) { uint32_t r = 0; r += op_push(signature_len + 1, out + r); memcpy(out + r, signature, signature_len); r += signature_len; - out[r] = 0x01; r++; + out[r] = sighash; r++; r += op_push(pubkey_len, out + r); memcpy(out + r, pubkey, pubkey_len); r += pubkey_len; return r; } -uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) +uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) { uint32_t r = 0; out[r] = 0x00; r++; @@ -306,7 +306,7 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin } r += op_push(multisig->signatures[i].size + 1, out + r); memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; - out[r] = 0x01; r++; + out[r] = sighash; r++; } uint32_t script_len = compile_script_multisig(multisig, 0); if (script_len == 0) { diff --git a/firmware/transaction.h b/firmware/transaction.h index 5c80904fcf..f43dd1ec29 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -49,8 +49,8 @@ bool compute_address(const CoinType *coin, InputScriptType script_type, const HD uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t *out); -uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); +uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); From 979a6ef266788c1eaadafb884327b154aae1a192 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 25 Jul 2017 16:49:55 +0100 Subject: [PATCH 0534/1154] signing: Skip TX_META with SIGHASH_FORKID --- firmware/signing.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index e4baf14fdc..4da3c1846e 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -644,11 +644,6 @@ static bool signing_sign_input(void) { signing_abort(); return false; } - if (!input.has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("SIGHASH_FORKID input without amount")); - signing_abort(); - return false; - } if (input.amount > to_spend) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); @@ -825,7 +820,23 @@ void signing_txack(TransactionType *tx) return; } #endif - send_req_2_prev_meta(); + + if (coin->has_forkid) { + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_DataError, _("SIGHASH_FORKID input without amount")); + signing_abort(); + return; + } + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } + to_spend += tx->inputs[0].amount; + phase1_request_next_input(); + } else { + send_req_2_prev_meta(); + } } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (!coin->has_segwit || !coin->segwit) { From 6b615ce40567cc0da0b3b38ff668916aaae9dd4b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 25 Jul 2017 22:35:09 +0200 Subject: [PATCH 0535/1154] No quadratic hashing for hardfork Don't hash the whole transaction if forkid is set. Instead use the same codepath as for segwit. Rename segwit_to_spend to authorized_amount and use it for forkid amount and segwit amount validity checks. Removed some duplicated code. --- firmware/signing.c | 164 ++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 84 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 4da3c1846e..0df8ad3dcd 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -57,7 +57,7 @@ static SHA256_CTX hashers[3]; static uint8_t privkey[32], pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; static uint8_t hash_check[32]; -static uint64_t to_spend, segwit_to_spend, spending, change_spend; +static uint64_t to_spend, authorized_amount, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; static uint32_t next_nonsegwit_input; @@ -426,7 +426,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp to_spend = 0; spending = 0; change_spend = 0; - segwit_to_spend = 0; + authorized_amount = 0; memset(&input, 0, sizeof(TxInputType)); memset(&resp, 0, sizeof(TxRequest)); @@ -523,9 +523,9 @@ static bool signing_check_output(TxOutputType *txoutput) { } } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS) { is_change = check_change_bip32_path(txoutput); - } else if (txoutput->script_type == OutputScriptType_PAYTOWITNESS && txoutput->amount < segwit_to_spend) { + } else if (txoutput->script_type == OutputScriptType_PAYTOWITNESS && txoutput->amount < authorized_amount) { is_change = check_change_bip32_path(txoutput); - } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS && txoutput->amount < segwit_to_spend) { + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS && txoutput->amount < authorized_amount) { is_change = check_change_bip32_path(txoutput); } } @@ -627,6 +627,40 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t sighash, uin sha256_Raw(hash, 32, hash); } +static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash, uint8_t sighash) { + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + if (ecdsa_sign_digest(&secp256k1, private_key, hash, sig, NULL, NULL) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + signing_abort(); + return false; + } + resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + + if (txinput->has_multisig) { + // fill in the signature + int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), public_key); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); + signing_abort(); + return false; + } + memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); + txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; + txinput->script_sig.size = serialize_script_multisig(&(txinput->multisig), sighash, txinput->script_sig.bytes); + if (txinput->script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); + signing_abort(); + return false; + } + } else { // SPENDADDRESS + txinput->script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, public_key, 33, sighash, txinput->script_sig.bytes); + } + return true; +} + static bool signing_sign_input(void) { uint8_t hash[32]; sha256_Final(&hashers[0], hash); @@ -637,58 +671,11 @@ static bool signing_sign_input(void) { return false; } - uint8_t sighash; - if (coin->has_forkid) { - if (!compile_input_script_sig(&input)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return false; - } - if (input.amount > to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return false; - } - to_spend -= input.amount; - - sighash = SIGHASH_ALL | SIGHASH_FORKID; - signing_hash_bip143(&input, sighash, coin->forkid, hash); - } else { - sighash = SIGHASH_ALL; - tx_hash_final(&ti, hash, false); - } - + uint8_t sighash = SIGHASH_ALL; + tx_hash_final(&ti, hash, false); resp.has_serialized = true; - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); - signing_abort(); + if (!signing_sign_hash(&input, privkey, pubkey, hash, sighash)) return false; - } - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - - if (input.has_multisig) { - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(input.multisig), pubkey); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); - signing_abort(); - return false; - } - memcpy(input.multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - input.multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - input.script_sig.size = serialize_script_multisig(&(input.multisig), sighash, input.script_sig.bytes); - if (input.script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); - signing_abort(); - return false; - } - } else { // SPENDADDRESS - input.script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, pubkey, 33, sighash, input.script_sig.bytes); - } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); return true; } @@ -710,38 +697,19 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { signing_abort(); return false; } - if (txinput->amount > segwit_to_spend) { + if (txinput->amount > authorized_amount) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } - segwit_to_spend -= txinput->amount; + authorized_amount -= txinput->amount; signing_hash_bip143(txinput, SIGHASH_ALL, 0, hash); resp.has_serialized = true; - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(&secp256k1, node.private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); - signing_abort(); + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash, SIGHASH_ALL)) return false; - } - - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); if (txinput->has_multisig) { - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), node.public_key); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); - signing_abort(); - return false; - } - memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - uint32_t r = 1; // skip number of items (filled in later) resp.serialized.serialized_tx.bytes[r] = 0; r++; int nwitnesses = 2; @@ -807,10 +775,6 @@ void signing_txack(TransactionType *tx) signing_check_input(&tx->inputs[0]); if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - // remember the first non-segwit input -- this is the first input - // we need to sign during phase2 - if (next_nonsegwit_input == 0xffffffff) - next_nonsegwit_input = idx1; memcpy(&input, tx->inputs, sizeof(TxInputType)); #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs @@ -833,8 +797,13 @@ void signing_txack(TransactionType *tx) return; } to_spend += tx->inputs[0].amount; + authorized_amount += tx->inputs[0].amount; phase1_request_next_input(); } else { + // remember the first non-segwit input -- this is the first input + // we need to sign during phase2 + if (next_nonsegwit_input == 0xffffffff) + next_nonsegwit_input = idx1; send_req_2_prev_meta(); } } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS @@ -873,7 +842,7 @@ void signing_txack(TransactionType *tx) to.is_segwit = true; #endif to_spend += tx->inputs[0].amount; - segwit_to_spend += tx->inputs[0].amount; + authorized_amount += tx->inputs[0].amount; phase1_request_next_input(); } else { fsm_sendFailure(FailureType_Failure_DataError, _("Wrong input script type")); @@ -1036,12 +1005,40 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_SEGWIT_INPUT: + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); resp.has_serialized = true; resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; resp.serialized.has_serialized_tx = true; - if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS - && !tx->inputs[0].has_multisig) { + if (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + if (!coin->has_forkid) { + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + signing_abort(); + return; + } + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + signing_abort(); + return; + } + if (tx->inputs[0].amount > authorized_amount) { + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + signing_abort(); + return; + } + authorized_amount -= tx->inputs[0].amount; + + uint8_t hash[32]; + signing_hash_bip143(&tx->inputs[0], SIGHASH_ALL | SIGHASH_FORKID, coin->forkid, hash); + if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash, SIGHASH_ALL | SIGHASH_FORKID)) + return; + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS + && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); @@ -1071,7 +1068,6 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.size = 0; } resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); - update_ctr = 0; if (idx1 < inputs_count - 1) { idx1++; phase2_request_next_input(); From 3c75d28c78ecdab78ec6fffa5eb3f87fdbdba048 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 27 Jul 2017 21:21:47 +0200 Subject: [PATCH 0536/1154] Check input bip32 path again on second pass. --- firmware/signing.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/firmware/signing.c b/firmware/signing.c index 0df8ad3dcd..5c47a90bbd 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -396,6 +396,17 @@ bool compile_input_script_sig(TxInputType *tinput) return false; } } + if (in_address_n_count >= 1) { + // check that input address didn't change + size_t count = tinput->address_n_count; + if (count != in_address_n_count) { + return false; + } + if (count >= 2 + && 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) { + return false; + } + } memcpy(&node, root, sizeof(HDNode)); if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count, NULL) == 0) { // Failed to derive private key From 5f6948e66b8756b18b128a1d3abb755b24322c40 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 28 Jul 2017 20:12:17 +0200 Subject: [PATCH 0537/1154] Remove progress update --- firmware/signing.c | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index 5c47a90bbd..423eb551c9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -1016,7 +1016,6 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_SEGWIT_INPUT: - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); resp.has_serialized = true; resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; From 3440ead4c9b3ec4f39a8faee558f1ec8f974b854 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 29 Jul 2017 21:58:49 +0200 Subject: [PATCH 0538/1154] Fix multisig for BCC --- firmware/crypto.c | 2 +- firmware/signing.c | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 590675c3e6..e81eb6f146 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -352,7 +352,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t { static const HDNodePathType *ptr[15], *swap; const uint32_t n = multisig->pubkeys_count; - if (n > 15) { + if (n < 1 || n > 15) { return 0; } // check sanity diff --git a/firmware/signing.c b/firmware/signing.c index 423eb551c9..dfca6e49dd 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -525,20 +525,27 @@ static bool signing_check_output(TxOutputType *txoutput) { signing_abort(); return false; } - if (txoutput->script_type == OutputScriptType_PAYTOMULTISIG) { + /* + * For multisig check that all inputs are multisig + */ + if (txoutput->has_multisig) { uint8_t h[32]; if (multisig_fp_set && !multisig_fp_mismatch - && cryptoMultisigFingerprint(&(txoutput->multisig), h) - && memcmp(multisig_fp, h, 32) == 0) { + && cryptoMultisigFingerprint(&(txoutput->multisig), h) + && memcmp(multisig_fp, h, 32) == 0) { is_change = check_change_bip32_path(txoutput); } - } else if (txoutput->script_type == OutputScriptType_PAYTOADDRESS) { - is_change = check_change_bip32_path(txoutput); - } else if (txoutput->script_type == OutputScriptType_PAYTOWITNESS && txoutput->amount < authorized_amount) { - is_change = check_change_bip32_path(txoutput); - } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS && txoutput->amount < authorized_amount) { + } else { is_change = check_change_bip32_path(txoutput); } + /* + * only allow segwit change if amount is smaller than what segwit inputs paid. + */ + if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS + || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) + && txoutput->amount > authorized_amount) { + is_change = false; + } } if (is_change) { @@ -1020,7 +1027,8 @@ void signing_txack(TransactionType *tx) resp.serialized.has_signature_index = false; resp.serialized.has_signature = false; resp.serialized.has_serialized_tx = true; - if (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG + || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { if (!coin->has_forkid) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); From fa2f5fb33fb5a12dccc3f2a5396ac39cd5ebd416 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Jul 2017 23:17:44 +0200 Subject: [PATCH 0539/1154] update coins --- firmware/coins-gen.py | 45 ++++++++++++++++---------------- firmware/coins.c | 3 +-- firmware/coins.h | 2 +- firmware/protob/messages.options | 16 ++++++------ firmware/protob/messages.pb.c | 10 +++---- firmware/protob/messages.pb.h | 38 +++++++++++++-------------- vendor/trezor-common | 2 +- 7 files changed, 58 insertions(+), 58 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index ca05d43406..57c8b38fa3 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -6,37 +6,38 @@ coins = json.load(open('../vendor/trezor-common/coins.json', 'r')) fields = [] for c in coins: - fields.append([ - 'true' if c['coin_name'] is not None else 'false', - '"%s"' % c['coin_name'] if c['coin_name'] is not None else 'NULL', + if c['firmware']: + fields.append([ + 'true' if c['coin_name'] is not None else 'false', + '"%s"' % c['coin_name'] if c['coin_name'] is not None else 'NULL', - 'true' if c['coin_shortcut'] is not None else 'false', - '" %s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', + 'true' if c['coin_shortcut'] is not None else 'false', + '" %s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', - 'true' if c['address_type'] is not None else 'false', - '%d' % c['address_type'] if c['address_type'] is not None else '0', + 'true' if c['address_type'] is not None else 'false', + '%d' % c['address_type'] if c['address_type'] is not None else '0', - 'true' if c['maxfee_kb'] is not None else 'false', - '%d' % c['maxfee_kb'] if c['maxfee_kb'] is not None else '0', + 'true' if c['maxfee_kb'] is not None else 'false', + '%d' % c['maxfee_kb'] if c['maxfee_kb'] is not None else '0', - 'true' if c['address_type_p2sh'] is not None else 'false', - '%d' % c['address_type_p2sh'] if c['address_type_p2sh'] is not None else '0', + 'true' if c['address_type_p2sh'] is not None else 'false', + '%d' % c['address_type_p2sh'] if c['address_type_p2sh'] is not None else '0', - 'true' if c['signed_message_header'] is not None else 'false', - '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', + 'true' if c['signed_message_header'] is not None else 'false', + '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', - 'true' if c['xpub_magic'] is not None else 'false', - '0x%s' % c['xpub_magic'] if c['xpub_magic'] is not None else '00000000', + 'true' if c['xpub_magic'] is not None else 'false', + '0x%s' % c['xpub_magic'] if c['xpub_magic'] is not None else '00000000', - 'true' if c['xprv_magic'] is not None else 'false', - '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000', + 'true' if c['xprv_magic'] is not None else 'false', + '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000', - 'true' if c['segwit'] is not None else 'false', - 'true' if c['segwit'] else 'false', + 'true' if c['segwit'] is not None else 'false', + 'true' if c['segwit'] else 'false', - 'true' if c['forkid'] is not None else 'false', - '%d' % c['forkid'] if c['forkid'] else '0' - ]) + 'true' if c['forkid'] is not None else 'false', + '%d' % c['forkid'] if c['forkid'] else '0' + ]) for j in range(len(fields[0])): l = max([len(x[j]) for x in fields]) + 1 diff --git a/firmware/coins.c b/firmware/coins.c index 8525d05006..3f8bd3b104 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -28,8 +28,7 @@ const CoinType coins[COINS_COUNT] = { {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, false, 0, }, {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, - {true, "Bitcoin Cash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, - {true, "Testnet Cash", true, " TBCH", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, true, 0, }, + {true, "Bcash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, false, 0, }, {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, false, 0, }, diff --git a/firmware/coins.h b/firmware/coins.h index 42e9e2f915..3276048cc3 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,7 @@ #include "types.pb.h" -#define COINS_COUNT 10 +#define COINS_COUNT 9 extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index a6aa613c5f..a4a2665a7e 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:10 +Features.coins max_count:9 Features.revision max_size:20 Features.bootloader_hash max_size:32 @@ -26,12 +26,12 @@ Entropy.entropy max_size:1024 GetPublicKey.address_n max_count:8 GetPublicKey.ecdsa_curve_name max_size:32 -GetPublicKey.coin_name max_size:17 +GetPublicKey.coin_name max_size:21 PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 -GetAddress.coin_name max_size:17 +GetAddress.coin_name max_size:21 Address.address max_size:60 @@ -55,12 +55,12 @@ WordAck.word max_size:12 SignMessage.address_n max_count:8 SignMessage.message max_size:1024 -SignMessage.coin_name max_size:17 +SignMessage.coin_name max_size:21 VerifyMessage.address max_size:60 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 -VerifyMessage.coin_name max_size:17 +VerifyMessage.coin_name max_size:21 MessageSignature.address max_size:60 MessageSignature.signature max_size:65 @@ -80,7 +80,7 @@ EncryptMessage skip_message:true # EncryptMessage.pubkey max_size:33 # EncryptMessage.message max_size:1024 # EncryptMessage.address_n max_count:8 -# EncryptMessage.coin_name max_size:17 +# EncryptMessage.coin_name max_size:21 # deprecated EncryptedMessage skip_message:true @@ -109,12 +109,12 @@ CipheredKeyValue.value max_size:1024 # deprecated EstimateTxSize skip_message:true -# EstimateTxSize.coin_name max_size:17 +# EstimateTxSize.coin_name max_size:21 # deprecated TxSize skip_message:true -SignTx.coin_name max_size:17 +SignTx.coin_name max_size:21 EthereumSignTx.address_n max_count:8 EthereumSignTx.nonce max_size:32 diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c index 870818d398..54de2aaa1e 100644 --- a/firmware/protob/messages.pb.c +++ b/firmware/protob/messages.pb.c @@ -3,17 +3,17 @@ #include "messages.pb.h" -const char GetPublicKey_coin_name_default[17] = "Bitcoin"; -const char GetAddress_coin_name_default[17] = "Bitcoin"; +const char GetPublicKey_coin_name_default[21] = "Bitcoin"; +const char GetAddress_coin_name_default[21] = "Bitcoin"; const InputScriptType GetAddress_script_type_default = InputScriptType_SPENDADDRESS; const char LoadDevice_language_default[17] = "english"; const uint32_t ResetDevice_strength_default = 256u; const char ResetDevice_language_default[17] = "english"; const char RecoveryDevice_language_default[17] = "english"; -const char SignMessage_coin_name_default[17] = "Bitcoin"; +const char SignMessage_coin_name_default[21] = "Bitcoin"; const InputScriptType SignMessage_script_type_default = InputScriptType_SPENDADDRESS; -const char VerifyMessage_coin_name_default[17] = "Bitcoin"; -const char SignTx_coin_name_default[17] = "Bitcoin"; +const char VerifyMessage_coin_name_default[21] = "Bitcoin"; +const char SignTx_coin_name_default[21] = "Bitcoin"; const uint32_t SignTx_version_default = 1u; const uint32_t SignTx_lock_time_default = 0u; diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index 25beba025d..f6d3670f81 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -506,7 +506,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[10]; + CoinType coins[9]; bool has_initialized; bool initialized; bool has_revision; @@ -531,7 +531,7 @@ typedef struct _GetAddress { size_t address_n_count; uint32_t address_n[8]; bool has_coin_name; - char coin_name[17]; + char coin_name[21]; bool has_show_display; bool show_display; bool has_multisig; @@ -566,7 +566,7 @@ typedef struct _GetPublicKey { bool has_show_display; bool show_display; bool has_coin_name; - char coin_name[17]; + char coin_name[21]; } GetPublicKey; typedef struct _LoadDevice { @@ -701,7 +701,7 @@ typedef struct _SignMessage { uint32_t address_n[8]; SignMessage_message_t message; bool has_coin_name; - char coin_name[17]; + char coin_name[21]; bool has_script_type; InputScriptType script_type; } SignMessage; @@ -710,7 +710,7 @@ typedef struct _SignTx { uint32_t outputs_count; uint32_t inputs_count; bool has_coin_name; - char coin_name[17]; + char coin_name[21]; bool has_version; uint32_t version; bool has_lock_time; @@ -773,7 +773,7 @@ typedef struct _VerifyMessage { bool has_message; VerifyMessage_message_t message; bool has_coin_name; - char coin_name[17]; + char coin_name[21]; } VerifyMessage; typedef struct _WordAck { @@ -786,24 +786,24 @@ typedef struct _WordRequest { } WordRequest; /* Default values for struct fields */ -extern const char GetPublicKey_coin_name_default[17]; -extern const char GetAddress_coin_name_default[17]; +extern const char GetPublicKey_coin_name_default[21]; +extern const char GetAddress_coin_name_default[21]; extern const InputScriptType GetAddress_script_type_default; extern const char LoadDevice_language_default[17]; extern const uint32_t ResetDevice_strength_default; extern const char ResetDevice_language_default[17]; extern const char RecoveryDevice_language_default[17]; -extern const char SignMessage_coin_name_default[17]; +extern const char SignMessage_coin_name_default[21]; extern const InputScriptType SignMessage_script_type_default; -extern const char VerifyMessage_coin_name_default[17]; -extern const char SignTx_coin_name_default[17]; +extern const char VerifyMessage_coin_name_default[21]; +extern const char SignTx_coin_name_default[21]; extern const uint32_t SignTx_version_default; extern const uint32_t SignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_default {false, 0} @@ -865,7 +865,7 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_zero {false, 0} @@ -1159,7 +1159,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (279 + 10*CoinType_size) +#define Features_size (273 + 9*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ApplyFlags_size 6 @@ -1176,9 +1176,9 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define PassphraseAck_size 53 #define GetEntropy_size 6 #define Entropy_size 1027 -#define GetPublicKey_size 103 +#define GetPublicKey_size 107 #define PublicKey_size (121 + HDNodeType_size) -#define GetAddress_size (81 + MultisigRedeemScriptType_size) +#define GetAddress_size (85 + MultisigRedeemScriptType_size) #define EthereumGetAddress_size 50 #define Address_size 62 #define EthereumAddress_size 22 @@ -1191,12 +1191,12 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; #define RecoveryDevice_size 80 #define WordRequest_size 6 #define WordAck_size 14 -#define SignMessage_size 1100 -#define VerifyMessage_size 1175 +#define SignMessage_size 1104 +#define VerifyMessage_size 1179 #define MessageSignature_size 129 #define CipherKeyValue_size 1358 #define CipheredKeyValue_size 1027 -#define SignTx_size 43 +#define SignTx_size 47 #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxAck_size (6 + TransactionType_size) #define EthereumSignTx_size 1245 diff --git a/vendor/trezor-common b/vendor/trezor-common index dc1ed85c96..e7832b2beb 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit dc1ed85c96e3766f9e99dc4c8af12ecf6de22f1e +Subproject commit e7832b2beb2085ea02130db8ad090eaacdf8b2ff From c778d7b9c325b0ace734d2f4c5718fc5d3e3297e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 02:26:28 +0200 Subject: [PATCH 0540/1154] storage: wipe storage after 15 wrong pins --- firmware/fsm.c | 5 +---- firmware/protect.c | 17 ++++++++++++++--- firmware/storage.c | 8 ++++++++ firmware/storage.h | 2 ++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9f6237d1fd..532ec14f8d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -318,10 +318,7 @@ void fsm_msgWipeDevice(WipeDevice *msg) layoutHome(); return; } - storage_reset(); - storage_reset_uuid(); - storage_commit(); - storage_clearPinArea(); + storage_wipe(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change fsm_sendSuccess(_("Device wiped")); diff --git a/firmware/protect.c b/firmware/protect.c index 53f5791a9b..205b91c798 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -30,6 +30,8 @@ #include "debug.h" #include "gettext.h" +#define MAX_WRONG_PINS 15 + bool protectAbortedByInitialize = false; bool protectButton(ButtonRequestType type, bool confirm_only) @@ -183,14 +185,23 @@ bool protectPin(bool use_cached) fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } - if (storage_increasePinFails(fails) && storage_containsPin(pin)) { + if (!storage_increasePinFails(fails)) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; + } + if (storage_containsPin(pin)) { session_cachePin(); storage_resetPinFails(fails); return true; } else { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; + if (~*fails > MAX_WRONG_PINS) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PINs"), _("entered. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); + storage_wipe(); + for (;;) {} // loop forever + } } + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; } bool protectChangePin(void) diff --git a/firmware/storage.c b/firmware/storage.c index 35e6fc0634..6eba0806ef 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -622,3 +622,11 @@ void storage_setU2FCounter(uint32_t u2fcounter) storage.u2f_counter = u2fcounter - storage_u2f_offset; storage_commit(); } + +void storage_wipe(void) +{ + storage_reset(); + storage_reset_uuid(); + storage_commit(); + storage_clearPinArea(); +} diff --git a/firmware/storage.h b/firmware/storage.h index 18f85d4947..0b27f3f200 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -73,6 +73,8 @@ bool storage_needsBackup(void); void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); +void storage_wipe(void); + extern Storage storage; extern char storage_uuid_str[25]; From 82a06ce3421da2a044fcde3dc3a14ed4fec80523 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 02:31:30 +0200 Subject: [PATCH 0541/1154] firmware: mark more strings with gettext --- firmware/trezor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index 73462ba6e4..5560421a01 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -29,6 +29,7 @@ #include "rng.h" #include "timer.h" #include "buttons.h" +#include "gettext.h" #include "fastflash.h" void check_lock_screen(void) @@ -44,7 +45,7 @@ void check_lock_screen(void) // button held for long enough (2 seconds) if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { - layoutDialog(&bmp_icon_question, "Cancel", "Lock Device", NULL, "Do you really want to", "lock your TREZOR?", NULL, NULL, NULL, NULL); + layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL, _("Do you really want to"), _("lock your TREZOR?"), NULL, NULL, NULL, NULL); // wait until NoButton is released usbTiny(1); From 45ca9bd583829615e73dec5b96af6930b9eaccea Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 02:35:53 +0200 Subject: [PATCH 0542/1154] protect: change wording --- firmware/protect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protect.c b/firmware/protect.c index 205b91c798..5f5dd0fb15 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -195,7 +195,7 @@ bool protectPin(bool use_cached) return true; } else { if (~*fails > MAX_WRONG_PINS) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PINs"), _("entered. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PIN"), _("attempts. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); storage_wipe(); for (;;) {} // loop forever } From 4ee52ab95f26fbfee06e50443b5a2493d0e6427c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 02:39:24 +0200 Subject: [PATCH 0543/1154] changelog: add more entries --- firmware/ChangeLog | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index c4fbf764aa..6a2eed6007 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,11 +1,14 @@ Version 1.5.1 * Stable release, optional update +* Wipe storage after 15 wrong attempts +* Enable Segwit for Bitcoin +* Bitcoin Cash aka Bcash support +* Message signing/verification for Ethereum and Segwit +* Make address dialog nicer (switch text/QR via button) +* Use checksum for Ethereum addresses +* Add more ERC-20 tokens, handle unrecognized ERC-20 tokens * Allow "dry run" recovery procedure * Allow separated backup procedure -* Add more ERC-20 tokens -* Handle unrecognized ERC-20 tokens -* Make address dialog nicer -* Use checksum for Ethereum addresses Version 1.5.0 * Stable release, optional update From 0feede5a01276980fe3fe3ff9310b80e97b4bc5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 10:06:27 +0200 Subject: [PATCH 0544/1154] build: switch from ubuntu to debian in docker build --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index dfb48d277f..ad05037a6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # initialize from the image -FROM ubuntu:16.04 +FROM debian:9 # update repositories From 33ed08ec32fca370f26a03fa49337fd25184b312 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 31 Jul 2017 13:02:44 +0200 Subject: [PATCH 0545/1154] Fix check for max try and add another check before --- firmware/protect.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 5f5dd0fb15..5c3881c4fa 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -144,6 +144,15 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } +static void protectCheckMaxTry(uint32_t wait) { + if (wait < (1 << MAX_WRONG_PINS)) + return; + + storage_wipe(); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PIN"), _("attempts. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); + for (;;) {} // loop forever +} + bool protectPin(bool use_cached) { if (!storage.has_pin || storage.pin[0] == 0 || (use_cached && session_isPinCached())) { @@ -151,6 +160,7 @@ bool protectPin(bool use_cached) } uint32_t *fails = storage_getPinFailsPtr(); uint32_t wait = ~*fails; + protectCheckMaxTry(wait); usbTiny(1); while (wait > 0) { // convert wait to secstr string @@ -194,14 +204,10 @@ bool protectPin(bool use_cached) storage_resetPinFails(fails); return true; } else { - if (~*fails > MAX_WRONG_PINS) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PIN"), _("attempts. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); - storage_wipe(); - for (;;) {} // loop forever - } + protectCheckMaxTry(~*fails); + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; } - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; } bool protectChangePin(void) From b1838d68679437d1101c0bea62ce2794f55ace3a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 14:15:10 +0200 Subject: [PATCH 0546/1154] ethereum: add more tokens --- firmware/ethereum_tokens.c | 17 ++++++++++++++++- firmware/ethereum_tokens.h | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index b7c1d6f082..ea3cbf4b7f 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -7,10 +7,12 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, + { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, + { 1, "\x72\x58\x03\x31\x55\x19\xde\x78\xd2\x32\x26\x5a\x8f\x10\x40\xf0\x54\xe7\x0b\x98", " BET", 18}, { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, @@ -26,18 +28,21 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, + { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, + { 1, "\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", " GELD", 18}, { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, { 1, "\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, + { 1, "\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", " ICE", 18}, { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JTC", 18}, @@ -52,22 +57,29 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, + { 1, "\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", " MYD", 16}, { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, + { 1, "\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", " NXX", 8}, { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, + { 1, "\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", " PLR", 18}, { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, + { 1, "\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", " PPT", 8}, + { 1, "\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", " PRO", 8}, { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, - { 1, "\x48\xc8\x0f\x1f\x4d\x53\xd5\x95\x1e\x5d\x54\x38\xb5\x4c\xba\x84\xf2\x9f\x32\xa5", " REP", 18}, + { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, + { 1, "\x99\xd4\x39\x45\x59\x91\xf7\xf4\x88\x5f\x20\xc6\x34\xc9\xa3\x19\x18\xd3\x66\xe5", " REX", 18}, { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, + { 1, "\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", " SAN", 18}, { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, @@ -77,6 +89,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, + { 1, "\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", " SPARC", 18}, { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, @@ -91,9 +104,11 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, { 1, "\x82\x66\x57\x64\xea\x0b\x58\x15\x7e\x1e\x5e\x9b\xab\x32\xf6\x8c\x76\xec\x0c\xdf", " VSM", 0}, + { 1, "\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63", " WCT", 18}, { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, + { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 8ea7d7396a..bb1aebabc9 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 93 +#define TOKENS_COUNT 108 typedef struct { uint8_t chain_id; From c2c3debd01028ad6752762a2e2ff9ebdba335cbe Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 16:31:33 +0200 Subject: [PATCH 0547/1154] changelog: fix typos --- firmware/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 6a2eed6007..00187bed2c 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,8 +1,8 @@ Version 1.5.1 * Stable release, optional update -* Wipe storage after 15 wrong attempts +* Wipe storage after 15 wrong PIN attempts * Enable Segwit for Bitcoin -* Bitcoin Cash aka Bcash support +* Bcash aka Bitcoin Cash support * Message signing/verification for Ethereum and Segwit * Make address dialog nicer (switch text/QR via button) * Use checksum for Ethereum addresses From a9a414df08992bf1b3c1416b23aa84eac9aca5b8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 19:40:35 +0200 Subject: [PATCH 0548/1154] fix typo --- firmware/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 00187bed2c..3bb83bb8b3 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,6 +1,6 @@ Version 1.5.1 * Stable release, optional update -* Wipe storage after 15 wrong PIN attempts +* Wipe storage after 16 wrong PIN attempts * Enable Segwit for Bitcoin * Bcash aka Bitcoin Cash support * Message signing/verification for Ethereum and Segwit From ace1d84265ac8d5eb64719853f35d3c4f0a57d00 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 20:49:34 +0200 Subject: [PATCH 0549/1154] recovery: don't reset storage on typos during dry-run recovery --- firmware/recovery.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index 473de42162..deb59cc379 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -450,7 +450,9 @@ static void recovery_scrambledword(const char *word) { if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { - storage_reset(); + if (!dry_run) { + storage_reset(); + } fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); layoutHome(); return; @@ -467,7 +469,9 @@ static void recovery_scrambledword(const char *word) wl++; } if (!found) { - storage_reset(); + if (!dry_run) { + storage_reset(); + } fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); layoutHome(); return; From f0d2e7a37142a6d4c7f7e45a6e4427e53123d614 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 22:43:28 +0200 Subject: [PATCH 0550/1154] storage: bump version --- firmware/storage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 6eba0806ef..8bb06b2593 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -102,7 +102,7 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char sessionPassphrase[51]; -#define STORAGE_VERSION 6 +#define STORAGE_VERSION 7 void storage_show_error(void) { @@ -132,6 +132,7 @@ bool storage_from_flash(void) // version 4: since 1.3.2 // version 5: since 1.3.3 // version 6: since 1.3.6 + // version 7: since 1.5.1 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; From 1d6329b1bf68de7a1d41f45da96e77672b8ddbc6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 31 Jul 2017 23:00:21 +0200 Subject: [PATCH 0551/1154] changelog: make last release mandatory --- firmware/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 3bb83bb8b3..237764b9a4 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,5 +1,5 @@ Version 1.5.1 -* Stable release, optional update +* Stable release, required update * Wipe storage after 16 wrong PIN attempts * Enable Segwit for Bitcoin * Bcash aka Bitcoin Cash support From dd9f7cd926245c5471f14473c36f7d0c1ff95f55 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 9 Aug 2017 15:18:31 +0200 Subject: [PATCH 0552/1154] fix typos in changelog --- firmware/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 237764b9a4..7fe838da60 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,5 +1,5 @@ Version 1.5.1 -* Stable release, required update +* Stable release, optional update * Wipe storage after 16 wrong PIN attempts * Enable Segwit for Bitcoin * Bcash aka Bitcoin Cash support @@ -59,7 +59,7 @@ Version 1.3.4 * Updated maxfee per kb for coins Version 1.3.3 -* Stable release, required update +* Stable release, mandatory update * Ask for PIN on GetAddress and GetPublicKey * Signing speed improved From f9af87091950ced7780df57e4a49e106d5369a7f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Aug 2017 16:58:52 +0200 Subject: [PATCH 0553/1154] docker: support build on SELinux enabled distros --- build-bootloader.sh | 2 +- build-firmware.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build-bootloader.sh b/build-bootloader.sh index 1b268935d1..b64c8ac1cb 100755 --- a/build-bootloader.sh +++ b/build-bootloader.sh @@ -6,7 +6,7 @@ TAG=${1:-master} BINFILE=build/bootloader-$TAG.bin docker build -t $IMAGE . -docker run -t -v $(pwd)/build:/build $IMAGE /bin/sh -c "\ +docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ git clone https://github.com/trezor/trezor-mcu && \ cd trezor-mcu && \ git checkout $TAG && \ diff --git a/build-firmware.sh b/build-firmware.sh index 0603504aee..a9a9a32cda 100755 --- a/build-firmware.sh +++ b/build-firmware.sh @@ -6,7 +6,7 @@ TAG=${1:-master} BINFILE=build/trezor-$TAG.bin docker build -t $IMAGE . -docker run -t -v $(pwd)/build:/build $IMAGE /bin/sh -c "\ +docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ git clone https://github.com/trezor/trezor-mcu && \ cd trezor-mcu && \ git checkout $TAG && \ From e69ef2e75aea0a94cf6cb32ae35bc55fa5154d97 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 13 Aug 2017 21:11:23 +0200 Subject: [PATCH 0554/1154] coins: include testnet coins just in debug builds + add more ethereum tokens --- firmware/coins-gen.py | 95 +++++++++++++++++++++------------ firmware/coins.c | 21 ++++---- firmware/coins.h | 6 ++- firmware/ethereum_tokens-gen.py | 16 ++++-- firmware/ethereum_tokens.c | 23 ++++++-- firmware/ethereum_tokens.h | 2 +- vendor/trezor-common | 2 +- 7 files changed, 111 insertions(+), 54 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 57c8b38fa3..6d78185d17 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -1,51 +1,78 @@ #!/usr/bin/env python3 import json -coins = json.load(open('../vendor/trezor-common/coins.json', 'r')) +coins_json = json.load(open('../vendor/trezor-common/coins.json', 'r')) -fields = [] +coins_stable, coins_debug = [], [] -for c in coins: - if c['firmware']: - fields.append([ - 'true' if c['coin_name'] is not None else 'false', - '"%s"' % c['coin_name'] if c['coin_name'] is not None else 'NULL', - 'true' if c['coin_shortcut'] is not None else 'false', - '" %s"' % c['coin_shortcut'] if c['coin_shortcut'] is not None else 'NULL', +def get_fields(coin): + return [ + 'true' if coin['coin_name'] is not None else 'false', + '"%s"' % coin['coin_name'] if coin['coin_name'] is not None else 'NULL', - 'true' if c['address_type'] is not None else 'false', - '%d' % c['address_type'] if c['address_type'] is not None else '0', + 'true' if coin['coin_shortcut'] is not None else 'false', + '" %s"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', - 'true' if c['maxfee_kb'] is not None else 'false', - '%d' % c['maxfee_kb'] if c['maxfee_kb'] is not None else '0', + 'true' if coin['address_type'] is not None else 'false', + '%d' % coin['address_type'] if coin['address_type'] is not None else '0', - 'true' if c['address_type_p2sh'] is not None else 'false', - '%d' % c['address_type_p2sh'] if c['address_type_p2sh'] is not None else '0', + 'true' if coin['maxfee_kb'] is not None else 'false', + '%d' % coin['maxfee_kb'] if coin['maxfee_kb'] is not None else '0', - 'true' if c['signed_message_header'] is not None else 'false', - '"\\x%02x" "%s"' % (len(c['signed_message_header']), c['signed_message_header'].replace('\n', '\\n')) if c['signed_message_header'] is not None else 'NULL', + 'true' if coin['address_type_p2sh'] is not None else 'false', + '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', - 'true' if c['xpub_magic'] is not None else 'false', - '0x%s' % c['xpub_magic'] if c['xpub_magic'] is not None else '00000000', + 'true' if coin['signed_message_header'] is not None else 'false', + '"\\x%02x" "%s"' % (len(coin['signed_message_header']), coin['signed_message_header'].replace('\n', '\\n')) if coin['signed_message_header'] is not None else 'NULL', - 'true' if c['xprv_magic'] is not None else 'false', - '0x%s' % c['xprv_magic'] if c['xprv_magic'] is not None else '00000000', + 'true' if coin['xpub_magic'] is not None else 'false', + '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '00000000', - 'true' if c['segwit'] is not None else 'false', - 'true' if c['segwit'] else 'false', + 'true' if coin['xprv_magic'] is not None else 'false', + '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '00000000', - 'true' if c['forkid'] is not None else 'false', - '%d' % c['forkid'] if c['forkid'] else '0' - ]) + 'true' if coin['segwit'] is not None else 'false', + 'true' if coin['segwit'] else 'false', -for j in range(len(fields[0])): - l = max([len(x[j]) for x in fields]) + 1 - for i in range(len(fields)): - if fields[i][j][0] in '0123456789': - fields[i][j] = (fields[i][j] + ',').rjust(l) - else: - fields[i][j] = (fields[i][j] + ',').ljust(l) + 'true' if coin['forkid'] is not None else 'false', + '%d' % coin['forkid'] if coin['forkid'] else '0' + ] -for row in fields: + +def justify_width(coins): + for j in range(len(coins[0])): + l = max([len(x[j]) for x in coins]) + 1 + for i in range(len(coins)): + if coins[i][j][0] in '0123456789': + coins[i][j] = (coins[i][j] + ',').rjust(l) + else: + coins[i][j] = (coins[i][j] + ',').ljust(l) + + +for coin in coins_json: + if coin['firmware'] == 'stable': + coins_stable.append(get_fields(coin)) + if coin['firmware'] == 'debug': + coins_debug.append(get_fields(coin)) + +justify_width(coins_stable) +justify_width(coins_debug) + +for row in coins_stable: print('\t{' + ' '.join(row) + ' },') + +print('#if DEBUG_LINK') + +for row in coins_debug: + print('\t{' + ' '.join(row) + ' },') + +print('#endif') + +print('-' * 32) + +print('#if DEBUG_LINK') +print('#define COINS_COUNT %d' % (len(coins_stable) + len(coins_debug))) +print('#else') +print('#define COINS_COUNT %d' % (len(coins_stable))) +print('#endif') diff --git a/firmware/coins.c b/firmware/coins.c index 3f8bd3b104..a7dfbf5081 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,15 +26,18 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, false, 0, }, - {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, - {true, "Bcash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, - {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, - {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, false, 0, }, - {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, false, 0, }, - {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, false, 0, }, - {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, - {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, false, 0, }, + {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, + {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, + {true, "Bcash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, + {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, + {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, false, 0, }, + {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, false, 0, }, + {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, false, 0, }, + {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, +#if DEBUG_LINK + {true, "Bcash Testnet", true, " TBCH", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, true, 0, }, + {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, false, 0, }, +#endif }; const CoinType *coinByName(const char *name) diff --git a/firmware/coins.h b/firmware/coins.h index 3276048cc3..7df4bccecc 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -22,7 +22,11 @@ #include "types.pb.h" -#define COINS_COUNT 9 +#if DEBUG_LINK +#define COINS_COUNT 10 +#else +#define COINS_COUNT 8 +#endif extern const CoinType coins[COINS_COUNT]; diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py index 2093545e66..99b305c70e 100755 --- a/firmware/ethereum_tokens-gen.py +++ b/firmware/ethereum_tokens-gen.py @@ -2,18 +2,21 @@ import requests subst = { - ( 1, 'BeerCoin \U0001F37A '): 'BEER', - ( 1, 'CryptoCarbon'): 'CCRB', - ( 1, 'DGX 1.0'): 'DGX1', - ( 1, 'JetCoins'): 'JTC', - ( 1, 'Unicorn \U0001F984 '): 'UNCRN', + (1, 'AVA \U0001F434'): 'AVA', + (1, 'BeerCoin \U0001F37A '): 'BEER', + (1, 'CryptoCarbon'): 'CCRB', + (1, 'DGX 1.0'): 'DGX1', + (1, 'JetCoins'): 'JTC', + (1, 'Unicorn \U0001F984 '): 'UNCRN', } + def get_tokens(chain): URL = 'https://raw.githubusercontent.com/kvhnuke/etherwallet/mercury/app/scripts/tokens/%sTokens.json' % chain r = requests.get(URL) return r.json() + def print_tokens(chain, chain_id): tokens = get_tokens(chain) @@ -27,9 +30,12 @@ def print_tokens(chain, chain_id): return len(tokens) + count = 0 count += print_tokens('eth', 1) count += print_tokens('etc', 61) +print('-' * 32) + print('#define TOKENS_COUNT %d' % count) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index ea3cbf4b7f..d1e605264b 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -3,16 +3,20 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, + { 1, "\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", " 300", 18}, { 1, "\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", " ADST", 0}, { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, + { 1, "\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10", " ATH", 18}, + { 1, "\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f", " AVA", 4}, { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, { 1, "\x72\x58\x03\x31\x55\x19\xde\x78\xd2\x32\x26\x5a\x8f\x10\x40\xf0\x54\xe7\x0b\x98", " BET", 18}, + { 1, "\x6d\xc7\x0d\x22\xee\x85\x40\x79\x6a\xb5\xb0\x2f\x98\xf9\xf2\x4d\xc8\x79\xe1\x0a", " BLX", 18}, { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, @@ -25,27 +29,34 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, + { 1, "\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", " DENT", 8}, { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, + { 1, "\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37", " DROP", 0}, { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, + { 1, "\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", " ECN", 2}, { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, + { 1, "\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", " FYN", 18}, { 1, "\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", " GELD", 18}, { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, - { 1, "\x1d\x92\x1e\xed\x55\xa6\xa9\xcc\xaa\x9c\x79\xb1\xa4\xf7\xb2\x55\x56\xe4\x43\x65", " GT", 0}, + { 1, "\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", " GTKT", 0}, { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, { 1, "\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", " ICE", 18}, { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, + { 1, "\xed\x19\x69\x8c\x0a\xbd\xe8\x63\x54\x13\xae\x7a\xd7\x22\x4d\xf6\xee\x30\xbf\x22", " IMT", 0}, { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JTC", 18}, + { 1, "\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", " LOK", 18}, + { 1, "\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53", " LUCK", 0}, { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, @@ -55,6 +66,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, + { 1, "\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", " MRV", 18}, { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, { 1, "\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", " MYD", 16}, @@ -64,6 +76,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, { 1, "\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", " NXX", 8}, { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, + { 1, "\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", " OHNI", 0}, { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, @@ -71,15 +84,17 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, { 1, "\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", " PPT", 8}, { 1, "\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", " PRO", 8}, + { 1, "\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b", " PRS", 18}, { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, - { 1, "\x99\xd4\x39\x45\x59\x91\xf7\xf4\x88\x5f\x20\xc6\x34\xc9\xa3\x19\x18\xd3\x66\xe5", " REX", 18}, + { 1, "\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", " REX", 18}, { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, { 1, "\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", " SAN", 18}, + { 1, "\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8", " SCL", 8}, { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, @@ -90,8 +105,9 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, { 1, "\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", " SPARC", 18}, - { 1, "\x1d\xce\x4f\xa0\x36\x39\xb7\xf0\xc3\x8e\xe5\xbb\x60\x65\x04\x5e\xdc\xf9\x81\x9a", " SRC", 8}, { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, + { 1, "\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96", " STRC", 8}, + { 1, "\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45", " STX", 18}, { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, @@ -109,6 +125,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, + { 1, "\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", " ZRX", 18}, {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, }; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index bb1aebabc9..ddc40b3b42 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 108 +#define TOKENS_COUNT 125 typedef struct { uint8_t chain_id; diff --git a/vendor/trezor-common b/vendor/trezor-common index e7832b2beb..ccff14d685 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit e7832b2beb2085ea02130db8ad090eaacdf8b2ff +Subproject commit ccff14d685958447740e4c3ffdf4296c818df54a From 7e56a62e8bbde2449679b01ef3fc40be16f9424e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:42:59 +0100 Subject: [PATCH 0555/1154] coins: Add _Static_assert for Features.coins max_count --- firmware/coins.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/coins.h b/firmware/coins.h index 7df4bccecc..a00709b63e 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -20,6 +20,7 @@ #ifndef __COINS_H__ #define __COINS_H__ +#include "messages.pb.h" #include "types.pb.h" #if DEBUG_LINK @@ -28,6 +29,8 @@ #define COINS_COUNT 8 #endif +_Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); + extern const CoinType coins[COINS_COUNT]; const CoinType *coinByName(const char *name); From fa7e32fadf86c8b95fbf4bddae4bc1573fa90b30 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:45:03 +0100 Subject: [PATCH 0556/1154] protob: Fix Features.coins max_count for DEBUG_LINK=1 --- firmware/protob/messages.options | 2 +- firmware/protob/messages.pb.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index a4a2665a7e..b42e5efad6 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:9 +Features.coins max_count:10 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h index f6d3670f81..9ac45f06e0 100644 --- a/firmware/protob/messages.pb.h +++ b/firmware/protob/messages.pb.h @@ -506,7 +506,7 @@ typedef struct _Features { bool has_label; char label[33]; size_t coins_count; - CoinType coins[9]; + CoinType coins[10]; bool has_initialized; bool initialized; bool has_revision; @@ -803,7 +803,7 @@ extern const uint32_t SignTx_lock_time_default; /* Initializer values for message structs */ #define Initialize_init_default {0} #define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_default {0} #define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_default {false, 0} @@ -865,7 +865,7 @@ extern const uint32_t SignTx_lock_time_default; #define DebugLinkFlashErase_init_default {false, 0} #define Initialize_init_zero {0} #define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define ClearSession_init_zero {0} #define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} #define ApplyFlags_init_zero {false, 0} @@ -1159,7 +1159,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2]; /* Maximum encoded size of messages (where known) */ #define Initialize_size 0 #define GetFeatures_size 0 -#define Features_size (273 + 9*CoinType_size) +#define Features_size (279 + 10*CoinType_size) #define ClearSession_size 0 #define ApplySettings_size 1083 #define ApplyFlags_size 6 From c121627a06970e8d11eaa795ab4332bd6b5c28ea Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 14:18:36 +0100 Subject: [PATCH 0557/1154] Travis CI: Test matrix of DEBUG_LINK and FASTFLASH This should catch inconsistencies with Features.coins or if there is a build configuration that makes the firmware too large. Also, add MAKEFLAGS and only build STM32F2 support in libopencm3 to speed up build time --- .travis.yml | 19 +++++++++++++------ firmware/Makefile | 7 +++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0fee46da0e..a260dbd762 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,19 +5,26 @@ language: c addons: apt: packages: - - build-essential - - git - - gcc-arm-none-eabi - - libnewlib-arm-none-eabi + - build-essential + - gcc-arm-none-eabi + - libnewlib-arm-none-eabi + +env: + global: + - MAKEFLAGS=-j2 + matrix: + - DEBUG_LINK=0 FASTFLASH=0 + - DEBUG_LINK=1 FASTFLASH=0 + - DEBUG_LINK=0 FASTFLASH=1 + - DEBUG_LINK=1 FASTFLASH=1 script: - - CFLAGS="-std=c99" make -C vendor/libopencm3 + - CFLAGS="-std=c99" make -C vendor/libopencm3 lib/stm32/f2 - make - make -C bootloader - make -C fastflash - make -C firmware - make -C demo - - make -C firmware clean && make -C firmware FASTFLASH=1 notifications: webhooks: diff --git a/firmware/Makefile b/firmware/Makefile index 32f2cd7bd6..61065a46fc 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -72,11 +72,14 @@ else CFLAGS += -DFASTFLASH=0 endif +DEBUG_LINK ?= 0 +DEBUG_LOG ?= 0 + CFLAGS += -Wno-sequence-point CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DQR_MAX_VERSION=0 -CFLAGS += -DDEBUG_LINK=0 -CFLAGS += -DDEBUG_LOG=0 +CFLAGS += -DDEBUG_LINK=$(DEBUG_LINK) +CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DUSE_ETHEREUM=1 From 9c25e03d98ddec9c27b3ced22c66c26a4e8590af Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 14 Aug 2017 13:59:17 +0100 Subject: [PATCH 0558/1154] vendor: Update trezor-crypto --- firmware/Makefile | 10 +++++++++- vendor/trezor-crypto | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 61065a46fc..95f43e2176 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -35,10 +35,18 @@ OBJS += ../vendor/trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o -OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o + +OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-donna-basepoint-table.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o +OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-scalarmult-base.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-sha3.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519-keccak.o + OBJS += ../vendor/trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip39.o diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 6580044196..8503bec352 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 658004419635505ac75300870a0bbc049ad354ee +Subproject commit 8503bec3523ec9c7d3a383ac405579b879500bd3 From a01ba51a2a05b68856d5b7852eedccb65e6fc6ef Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 7 Aug 2017 16:34:07 +0200 Subject: [PATCH 0559/1154] storage: copy only required bytes from old storage, bump storage version + backup_device: ask for pin, always use correct number of words --- firmware/fsm.c | 2 ++ firmware/reset.c | 12 ++++++++---- firmware/storage.c | 23 +++++++++++++++++++++-- firmware/trezor.h | 2 +- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 532ec14f8d..08bc5bee97 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -452,6 +452,8 @@ void fsm_msgBackupDevice(BackupDevice *msg) { CHECK_INITIALIZED + CHECK_PIN_UNCACHED + (void)msg; reset_backup(true); } diff --git a/firmware/reset.c b/firmware/reset.c index 5efe7be68b..7f8d2c3810 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -121,15 +121,18 @@ void reset_backup(bool separated) storage_commit(); for (int pass = 0; pass < 2; pass++) { - int i = 0; - for (int word_pos = 1; word_pos <= (int)strength/32*3; word_pos++) { + int i = 0, word_pos = 1; + while (storage.mnemonic[i] != 0) { // copy current_word int j = 0; while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { current_word[j] = storage.mnemonic[i]; i++; j++; } - current_word[j] = 0; if (storage.mnemonic[i] != 0) i++; + current_word[j] = 0; + if (storage.mnemonic[i] != 0) { + i++; + } char desc[] = "##th word is:"; if (word_pos < 10) { desc[0] = ' '; @@ -151,7 +154,7 @@ void reset_backup(bool separated) current_word_display[j + 1] = current_word[j] + 'A' - 'a'; } current_word_display[j + 1] = 0; - if (word_pos == (int)strength/32*3) { // last word + if (storage.mnemonic[i] == 0) { // last word if (pass == 1) { layoutDialogSwipe(&bmp_icon_info, NULL, _("Finish"), NULL, _("Please check the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); } else { @@ -172,6 +175,7 @@ void reset_backup(bool separated) fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } + word_pos++; } } diff --git a/firmware/storage.c b/firmware/storage.c index 8bb06b2593..e222928d83 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -102,7 +102,7 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char sessionPassphrase[51]; -#define STORAGE_VERSION 7 +#define STORAGE_VERSION 8 void storage_show_error(void) { @@ -133,6 +133,7 @@ bool storage_from_flash(void) // version 5: since 1.3.3 // version 6: since 1.3.6 // version 7: since 1.5.1 + // version 8: since 1.5.2 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; @@ -141,8 +142,26 @@ bool storage_from_flash(void) // load uuid memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + 4), sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); + // copy storage - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); + size_t old_storage_size = 0; + + if (version == 1 || version == 2) { + old_storage_size = 460; + } else + if (version == 3 || version == 4 || version == 5) { + old_storage_size = 1488; + } else + if (version == 6 || version == 7) { + old_storage_size = 1496; + } else + if (version == 8) { + old_storage_size = 1504; + } + + memset(&storage, 0, sizeof(Storage)); + memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), old_storage_size); + if (version <= 5) { // convert PIN failure counter from version 5 format uint32_t pinctr = storage.has_pin_failed_attempts diff --git a/firmware/trezor.h b/firmware/trezor.h index df6200b355..7abbe9ce8a 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -22,7 +22,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 5 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) From 98e617d8740b85ae01d7d6e0dd3f49e66057a210 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 8 Aug 2017 12:59:39 +0200 Subject: [PATCH 0560/1154] startup: use custom reset_handler + group confidential data in one place + zero all SRAM where needed --- Makefile | 1 + Makefile.include | 17 +++++++++++------ bootloader/bootloader.c | 3 +++ bootloader/bootloader.h | 4 ++-- firmware/Makefile | 9 ++++----- firmware/ethereum.c | 2 +- firmware/fastflash.c | 20 +++++++++++--------- firmware/fastflash.h | 1 - firmware/fsm.c | 2 +- firmware/signing.c | 5 +++-- firmware/storage.c | 6 +++--- firmware/transaction.c | 2 +- firmware/trezor.c | 1 - firmware/u2f.c | 2 +- memory.ld | 13 +++++++++++++ memory_app_1.0.0.ld | 13 +++++++++++++ memory_app_2.0.0.ld | 21 --------------------- memory_app_fastflash.ld | 13 +++++++++++++ setup.c | 9 +++++++++ startup.s | 39 +++++++++++++++++++++++++++++++++++++++ util.h | 25 ++++++++++++++++--------- 21 files changed, 145 insertions(+), 63 deletions(-) delete mode 100644 memory_app_2.0.0.ld create mode 100644 startup.s diff --git a/Makefile b/Makefile index 747da6dc67..27d58a0f44 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +OBJS += startup.o OBJS += buttons.o OBJS += layout.o OBJS += oled.o diff --git a/Makefile.include b/Makefile.include index 8fba930947..7bbcb3d825 100644 --- a/Makefile.include +++ b/Makefile.include @@ -7,11 +7,14 @@ LD = $(PREFIX)gcc OBJCOPY = $(PREFIX)objcopy OBJDUMP = $(PREFIX)objdump AR = $(PREFIX)ar +AS = $(PREFIX)as FLASH = st-flash OPENOCD = openocd OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG +CPUFLAGS ?= -mcpu=cortex-m3 -mthumb +FPUFLAGS ?= -msoft-float CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ @@ -40,10 +43,10 @@ CFLAGS += $(OPTFLAGS) \ -ffunction-sections \ -fdata-sections \ -fstack-protector-all \ - -mcpu=cortex-m3 \ - -mthumb \ - -msoft-float \ + $(CPUFLAGS) \ + $(FPUFLAGS) \ -DSTM32F2 \ + -DCONFIDENTIAL='__attribute__((section("confidential")))' \ -I$(TOOLCHAIN_DIR)/include \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ @@ -83,9 +86,8 @@ LDFLAGS += --static \ -T$(LDSCRIPT) \ -nostartfiles \ -Wl,--gc-sections \ - -mcpu=cortex-m3 \ - -mthumb \ - -msoft-float + $(CPUFLAGS) \ + $(FPUFLAGS) all: $(NAME).bin @@ -128,6 +130,9 @@ $(NAME).list: $(NAME).elf $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP_DIR)/libtrezor.a $(LD) -o $(NAME).elf $(OBJS) -ltrezor -lopencm3_stm32f2 $(LDFLAGS) +%.o: %.s Makefile + $(AS) $(CPUFLAGS) -o $@ $< + %.o: %.c Makefile $(CC) $(CFLAGS) -MMD -o $@ -c $< diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 1a3c0c2db4..6a7ba9e05e 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -78,6 +78,9 @@ void show_unofficial_warning(const uint8_t *hash) void __attribute__((noreturn)) load_app(void) { + // zero out SRAM + memset_reg(_ram_start, _ram_end, 0); + load_vector_table((const vector_table_t *) FLASH_APP_START); } diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 723b9bac91..7324909cf1 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 -#define VERSION_PATCH 2 +#define VERSION_PATCH 3 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x03" -#define VERSION_PATCH_CHAR "\x02" +#define VERSION_PATCH_CHAR "\x03" #include #include "memory.h" diff --git a/firmware/Makefile b/firmware/Makefile index 95f43e2176..4599627d26 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,10 +1,8 @@ -ifeq ($(FASTFLASH),1) -APPVER = 2.0.0 +APPVER = 1.0.0 +ifeq ($(FASTFLASH),1) OBJS += fastflash.o OBJS += bootloader.o -else -APPVER = 1.0.0 endif NAME = trezor @@ -93,6 +91,7 @@ CFLAGS += -DUSE_ETHEREUM=1 bootloader.o: ../fastflash/bootloader.bin $(OBJCOPY) -I binary -O elf32-littlearm -B arm \ + --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_start=__bootloader_start__ \ --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_size=__bootloader_size__ \ - --rename-section .data=.bootloader \ + --rename-section .data=.rodata \ $< $@ diff --git a/firmware/ethereum.c b/firmware/ethereum.c index cf8e9a7fc6..0b63cd60b2 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -37,7 +37,7 @@ static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest msg_tx_request; -static uint8_t privkey[32]; +static CONFIDENTIAL uint8_t privkey[32]; static uint8_t chain_id; struct SHA3_CTX keccak_ctx; diff --git a/firmware/fastflash.c b/firmware/fastflash.c index 76f31cfa7a..25f33e5d30 100644 --- a/firmware/fastflash.c +++ b/firmware/fastflash.c @@ -24,16 +24,18 @@ #include #include -extern uint8_t __bootloader_loadaddr__[]; -extern uint8_t __bootloader_runaddr__[]; -extern uint8_t __bootloader_size__[]; - -void load_bootloader(void) -{ - memcpy(__bootloader_runaddr__, __bootloader_loadaddr__, (size_t) __bootloader_size__); -} +#define bootloader_vec ((vector_table_t *) 0x20000000) void __attribute__((noreturn)) run_bootloader(void) { - load_vector_table((const vector_table_t *) __bootloader_runaddr__); + extern uint8_t __bootloader_start__[]; + extern uint8_t __bootloader_size__[]; + + // zero out SRAM + memset_reg(_ram_start, _ram_end, 0); + + // copy bootloader + memcpy(bootloader_vec, __bootloader_start__, (size_t) __bootloader_size__); + + load_vector_table(bootloader_vec); } diff --git a/firmware/fastflash.h b/firmware/fastflash.h index 20caf1ef7a..e35b443675 100644 --- a/firmware/fastflash.h +++ b/firmware/fastflash.h @@ -20,7 +20,6 @@ #ifndef __FASTFLASH_H__ #define __FASTFLASH_H__ -void load_bootloader(void); void __attribute__((noreturn)) run_bootloader(void); #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 08bc5bee97..e793c37428 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -177,7 +177,7 @@ const CoinType *fsm_getCoin(bool has_name, const char *name) HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) { - static HDNode node; + static CONFIDENTIAL HDNode node; if (!storage_getRootNode(&node, curve, true)) { fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); diff --git a/firmware/signing.c b/firmware/signing.c index dfca6e49dd..b8aaaa0823 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -32,7 +32,7 @@ static uint32_t inputs_count; static uint32_t outputs_count; static const CoinType *coin; static const HDNode *root; -static HDNode node; +static CONFIDENTIAL HDNode node; static bool signing = false; enum { STAGE_REQUEST_1_INPUT, @@ -54,7 +54,8 @@ static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; static SHA256_CTX hashers[3]; -static uint8_t privkey[32], pubkey[33], sig[64]; +static uint8_t CONFIDENTIAL privkey[32]; +static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; static uint8_t hash_check[32]; static uint64_t to_spend, authorized_amount, spending, change_spend; diff --git a/firmware/storage.c b/firmware/storage.c index e222928d83..a7a4ee3ce0 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -42,7 +42,7 @@ #include "usb.h" #include "gettext.h" -Storage storage; +Storage CONFIDENTIAL storage; uint32_t storage_uuid[12/sizeof(uint32_t)]; char storage_uuid_str[25]; @@ -95,12 +95,12 @@ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t static bool sessionSeedCached, sessionSeedUsesPassphrase; -static uint8_t sessionSeed[64]; +static uint8_t CONFIDENTIAL sessionSeed[64]; static bool sessionPinCached; static bool sessionPassphraseCached; -static char sessionPassphrase[51]; +static char CONFIDENTIAL sessionPassphrase[51]; #define STORAGE_VERSION 8 diff --git a/firmware/transaction.c b/firmware/transaction.c index c282e67c94..199045f212 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -152,7 +152,7 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T } if (in->address_n_count > 0) { - HDNode node; + static CONFIDENTIAL HDNode node; InputScriptType input_script_type; switch (in->script_type) { diff --git a/firmware/trezor.c b/firmware/trezor.c index 5560421a01..15ce9fbe79 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -95,7 +95,6 @@ int main(void) #if FASTFLASH uint16_t state = gpio_port_read(BTN_PORT); if ((state & BTN_PIN_NO) == 0) { - load_bootloader(); run_bootloader(); } #endif diff --git a/firmware/u2f.c b/firmware/u2f.c index cc47b6fa19..41c1f33452 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -450,7 +450,7 @@ void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { - static HDNode node; + static CONFIDENTIAL HDNode node; if (!storage_getRootNode(&node, NIST256P1_NAME, false)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); diff --git a/memory.ld b/memory.ld index 539837839b..94667b42d0 100644 --- a/memory.ld +++ b/memory.ld @@ -6,4 +6,17 @@ MEMORY ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } +SECTIONS +{ + .confidential (NOLOAD) : { + *(confidential) + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + } >ram +} + INCLUDE libopencm3_stm32f2.ld + +_ram_start = ORIGIN(ram); +_ram_end = ORIGIN(ram) + LENGTH(ram); + +_data_size = SIZEOF(.data); diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index a8188fb606..7a09b7899f 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -6,4 +6,17 @@ MEMORY ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } +SECTIONS +{ + .confidential (NOLOAD) : { + *(confidential) + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + } >ram +} + INCLUDE libopencm3_stm32f2.ld + +_ram_start = ORIGIN(ram); +_ram_end = ORIGIN(ram) + LENGTH(ram); + +_data_size = SIZEOF(.data); diff --git a/memory_app_2.0.0.ld b/memory_app_2.0.0.ld deleted file mode 100644 index bfd773a68c..0000000000 --- a/memory_app_2.0.0.ld +++ /dev/null @@ -1,21 +0,0 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ -/* program starts at 0x08010000 */ -MEMORY -{ - rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K - bootloader (rx) : ORIGIN = 0x20000000, LENGTH = 32K - ram (rwx) : ORIGIN = 0x20000000 + LENGTH(bootloader), - LENGTH = 128K - LENGTH(bootloader) -} - -INCLUDE libopencm3_stm32f2.ld - -SECTIONS -{ - .bootloader : { - __bootloader_runaddr__ = .; - KEEP (*(.bootloader*)) - } >bootloader AT >rom - - __bootloader_loadaddr__ = LOADADDR(.bootloader); -} diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index 252158425b..55b0fb65c0 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -6,4 +6,17 @@ MEMORY LENGTH = 128K - LENGTH(rom) } +SECTIONS +{ + .confidential (NOLOAD) : { + *(confidential) + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + } >ram +} + INCLUDE libopencm3_stm32f2.ld + +_ram_start = ORIGIN(ram); +_ram_end = ORIGIN(ram) + LENGTH(ram); + +_data_size = SIZEOF(.data); diff --git a/setup.c b/setup.c index cf2726a8a6..b84bdd37db 100644 --- a/setup.c +++ b/setup.c @@ -17,6 +17,7 @@ * along with this library. If not, see . */ +#include #include #include #include @@ -44,6 +45,14 @@ void nmi_handler(void) void setup(void) { + // set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect. + // This is not strictly necessary for the current TREZOR system. + // This is here to comply with guidance from section 3.3.3 "Binary compatibility with other Cortex processors" + // of the ARM Cortex-M3 Processor Technical Reference Manual. + // According to section 4.4.2 and 4.4.7 of the "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", + // STM32F2 series MCUs are r2p0 and always have this bit set on reset already. + SCB_CCR |= SCB_CCR_STKALIGN; + // setup clock struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; rcc_clock_setup_hse_3v3(&clock); diff --git a/startup.s b/startup.s new file mode 100644 index 0000000000..58aec193bb --- /dev/null +++ b/startup.s @@ -0,0 +1,39 @@ + .syntax unified + + .text + + .global memset_reg + .type memset_reg, STT_FUNC +memset_reg: + // call with the following (note that the arguments are not validated prior to use): + // r0 - address of first word to write (inclusive) + // r1 - address of first word following the address in r0 to NOT write (exclusive) + // r2 - word value to be written + // both addresses in r0 and r1 needs to be divisible by 4! + .L_loop_begin: + str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed + cmp r0, r1 + bne .L_loop_begin + bx lr + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + ldr r0, =_ram_start // r0 - point to beginning of SRAM + ldr r1, =_ram_end // r1 - point to byte after the end of SRAM + ldr r2, =0 // r2 - the byte-sized value to be written + bl memset_reg + + // copy .data section from flash to SRAM + ldr r0, =_data // dst addr + ldr r1, =_data_loadaddr // src addr + ldr r2, =_data_size // length in bytes + bl memcpy + + // enter the application code + bl main + + // loop forever if the application code returns + b . + + .end diff --git a/util.h b/util.h index ed6aaadc15..8e4c6cefdc 100644 --- a/util.h +++ b/util.h @@ -41,18 +41,25 @@ void __attribute__((noreturn)) system_halt(void); // reset system void __attribute__((noreturn)) system_reset(void); -static inline void __attribute__((noreturn)) load_vector_table(const vector_table_t *vector_table) { - // Relocate vector table - SCB_VTOR = (uint32_t) vector_table; +// defined in memory.ld +extern uint8_t _ram_start[], _ram_end[]; - // Set stack pointer - __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); +// defined in startup.s +extern void memset_reg(void *start, void *stop, uint32_t val); - // Jump to address - vector_table->reset(); +static inline void __attribute__((noreturn)) load_vector_table(const vector_table_t *vector_table) +{ + // Relocate vector table + SCB_VTOR = (uint32_t)vector_table; - // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) - for (;;); + // Set stack pointer + __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); + + // Jump to address + vector_table->reset(); + + // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) + for (;;); } #endif From 3e9ebe6c101e2e05b09252c9268cc9366c591be9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 16 Aug 2017 13:42:55 +0200 Subject: [PATCH 0561/1154] changelog: add 1.5.2 + update vendor/trezor-crypto --- firmware/ChangeLog | 5 +++++ vendor/trezor-crypto | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 7fe838da60..ffadf9b859 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,8 @@ +Version 1.5.2 +* Stable release, required update +* clean memory on start +* fix storage import from older versions + Version 1.5.1 * Stable release, optional update * Wipe storage after 16 wrong PIN attempts diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 8503bec352..9dfc6a4477 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 8503bec3523ec9c7d3a383ac405579b879500bd3 +Subproject commit 9dfc6a4477a7ac344ab630441e0b76d5d623a313 From e4cc08775fc9c204f295442f930326eb7877f2d4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 16 Aug 2017 14:28:21 +0200 Subject: [PATCH 0562/1154] vendor: update trezor-common, enable Bitcoin segwit manually --- firmware/coins.c | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index a7dfbf5081..6fe150906e 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,7 +26,7 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, + {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, false, 0, }, {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, {true, "Bcash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, diff --git a/vendor/trezor-common b/vendor/trezor-common index ccff14d685..5f7a1a7a5a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit ccff14d685958447740e4c3ffdf4296c818df54a +Subproject commit 5f7a1a7a5a4311fd71ed113624dd1d0fe9e72ff5 From e5d3a2169b4b466475e6773f0067762991736147 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 16 Aug 2017 18:25:55 +0200 Subject: [PATCH 0563/1154] build: update docker build scripts to copy also .elf files to output directory --- build-bootloader.sh | 5 +++-- build-firmware.sh | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/build-bootloader.sh b/build-bootloader.sh index b64c8ac1cb..d7c7afd784 100755 --- a/build-bootloader.sh +++ b/build-bootloader.sh @@ -4,6 +4,7 @@ set -e IMAGE=trezor-mcu-build TAG=${1:-master} BINFILE=build/bootloader-$TAG.bin +ELFFILE=build/bootloader-$TAG.elf docker build -t $IMAGE . docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ @@ -15,8 +16,8 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ make && \ make -C bootloader && \ make -C bootloader align && \ - cp bootloader/bootloader.bin /$BINFILE" - + cp bootloader/bootloader.bin /$BINFILE && \ + cp bootloader/bootloader.elf /$ELFFILE" /usr/bin/env python -c " from __future__ import print_function import hashlib diff --git a/build-firmware.sh b/build-firmware.sh index a9a9a32cda..3eb6365b66 100755 --- a/build-firmware.sh +++ b/build-firmware.sh @@ -4,6 +4,7 @@ set -e IMAGE=trezor-mcu-build TAG=${1:-master} BINFILE=build/trezor-$TAG.bin +ELFFILE=build/trezor-$TAG.elf docker build -t $IMAGE . docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ @@ -15,7 +16,8 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ make && \ make -C firmware && \ make -C firmware sign && \ - cp firmware/trezor.bin /$BINFILE" + cp firmware/trezor.bin /$BINFILE && \ + cp firmware/trezor.elf /$ELFFILE" /usr/bin/env python -c " from __future__ import print_function From 07f6e495b7b22c3259456c55ff19706cb5d7e1be Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Aug 2017 16:36:38 +0200 Subject: [PATCH 0564/1154] fsm: fix race condition in GetAddress --- firmware/fsm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index e793c37428..f460cd5956 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -642,8 +642,9 @@ void fsm_msgGetAddress(GetAddress *msg) if (!node) return; hdnode_fill_public_key(node); + char address[MAX_ADDR_SIZE]; layoutProgress(_("Computing address"), 0); - if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, resp->address)) { + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); layoutHome(); return; @@ -664,7 +665,7 @@ void fsm_msgGetAddress(GetAddress *msg) } bool qrcode = false; for (;;) { - layoutAddress(resp->address, desc, qrcode); + layoutAddress(address, desc, qrcode); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } @@ -672,6 +673,7 @@ void fsm_msgGetAddress(GetAddress *msg) } } + strlcpy(resp->address, address, sizeof(resp->address)); msg_write(MessageType_MessageType_Address, resp); layoutHome(); } From 724ce5e7ee3818a41c0de791d6b24cada937236f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 28 Aug 2017 12:41:45 +0100 Subject: [PATCH 0565/1154] buttons: Wrap macros with #ifndef (#216) --- buttons.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/buttons.h b/buttons.h index 08f0c8e036..3091081494 100644 --- a/buttons.h +++ b/buttons.h @@ -34,8 +34,16 @@ extern struct buttonState button; void buttonUpdate(void); +#ifndef BTN_PORT #define BTN_PORT GPIOC +#endif + +#ifndef BTN_PIN_YES #define BTN_PIN_YES GPIO2 +#endif + +#ifndef BTN_PIN_NO #define BTN_PIN_NO GPIO5 +#endif #endif From 6a04b2e90ec93e2c459390aab270094d52860d7e Mon Sep 17 00:00:00 2001 From: mcudev <29890609+mcudev@users.noreply.github.com> Date: Mon, 28 Aug 2017 07:47:15 -0400 Subject: [PATCH 0566/1154] cleanup build, update libopencm3 (#215) --- .travis.yml | 2 +- build-bootloader.sh | 3 +-- build-firmware.sh | 3 +-- vendor/libopencm3 | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a260dbd762..95eed0db96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ env: - DEBUG_LINK=1 FASTFLASH=1 script: - - CFLAGS="-std=c99" make -C vendor/libopencm3 lib/stm32/f2 + - make -C vendor/libopencm3 lib/stm32/f2 - make - make -C bootloader - make -C fastflash diff --git a/build-bootloader.sh b/build-bootloader.sh index d7c7afd784..fe413566ac 100755 --- a/build-bootloader.sh +++ b/build-bootloader.sh @@ -12,9 +12,8 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cd trezor-mcu && \ git checkout $TAG && \ git submodule update --init && \ - CFLAGS='-std=c99' make -C vendor/libopencm3 && \ + make -C vendor/libopencm3 && \ make && \ - make -C bootloader && \ make -C bootloader align && \ cp bootloader/bootloader.bin /$BINFILE && \ cp bootloader/bootloader.elf /$ELFFILE" diff --git a/build-firmware.sh b/build-firmware.sh index 3eb6365b66..a045e7cb8d 100755 --- a/build-firmware.sh +++ b/build-firmware.sh @@ -12,9 +12,8 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cd trezor-mcu && \ git checkout $TAG && \ git submodule update --init && \ - CFLAGS='-std=c99' make -C vendor/libopencm3 && \ + make -C vendor/libopencm3 && \ make && \ - make -C firmware && \ make -C firmware sign && \ cp firmware/trezor.bin /$BINFILE && \ cp firmware/trezor.elf /$ELFFILE" diff --git a/vendor/libopencm3 b/vendor/libopencm3 index b76d853a72..b0e050d10d 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit b76d853a723d39bbc083495bb7460cf3f071476c +Subproject commit b0e050d10d12c42be031c34822117cfd3c5a0ea7 From 5bb769a740ad427ef988b6c0baf37b2896cc60b7 Mon Sep 17 00:00:00 2001 From: mcudev <29890609+mcudev@users.noreply.github.com> Date: Thu, 31 Aug 2017 05:25:25 -0400 Subject: [PATCH 0567/1154] memory_protect: add flash interface register check (#218) --- memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/memory.c b/memory.c index 33bd007c6b..e49a3155f1 100644 --- a/memory.c +++ b/memory.c @@ -30,8 +30,8 @@ void memory_protect(void) #if MEMORY_PROTECT // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf // Section 2.6 Option bytes - // set RDP level 2 WRP for sectors 0 and 1 - if ((((*OPTION_BYTES_1) & 0xFFEC) == 0xCCEC) && (((*OPTION_BYTES_2) & 0xFFF) == 0xFFC)) { + // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches + if ((((*OPTION_BYTES_1) & 0xFFEC) == 0xCCEC) && (((*OPTION_BYTES_2) & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { return; // already set up correctly - bail out } flash_unlock_option_bytes(); From 0c30a193005f7121b6e38be208143f72abb8b26e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Aug 2017 11:25:34 +0200 Subject: [PATCH 0568/1154] memory_protect: update last commit --- memory.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/memory.c b/memory.c index e49a3155f1..496d39e6c1 100644 --- a/memory.c +++ b/memory.c @@ -22,16 +22,16 @@ #include "memory.h" #include "sha2.h" -#define OPTION_BYTES_1 ((uint64_t *)0x1FFFC000) -#define OPTION_BYTES_2 ((uint64_t *)0x1FFFC008) +#define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000) +#define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008) void memory_protect(void) { #if MEMORY_PROTECT // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf // Section 2.6 Option bytes - // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches - if ((((*OPTION_BYTES_1) & 0xFFEC) == 0xCCEC) && (((*OPTION_BYTES_2) & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { + // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches + if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && ((FLASH_OPTCR & 0x0FFFFFEC) == 0x0FFCCCED)) { return; // already set up correctly - bail out } flash_unlock_option_bytes(); From 5f9cd15b02dc71072c8c82c32b6b8b2c86f4bf84 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 31 Aug 2017 13:28:50 +0200 Subject: [PATCH 0569/1154] Support multi-byte chain-id. (#212) --- firmware/ethereum.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 0b63cd60b2..0fe343a61d 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -34,11 +34,14 @@ #include "gettext.h" #include "ethereum_tokens.h" +/* maximum supported chain id. v must fit in an uint32_t. */ +#define MAX_CHAIN_ID 2147483630 + static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest msg_tx_request; static CONFIDENTIAL uint8_t privkey[32]; -static uint8_t chain_id; +static uint32_t chain_id; struct SHA3_CTX keccak_ctx; static inline void hash_data(const uint8_t *buf, size_t size) @@ -157,8 +160,17 @@ static void send_signature(void) /* eip-155 replay protection */ if (chain_id != 0) { + uint8_t data[4]; + data[0] = (chain_id >> 24) & 0xff; + data[1] = (chain_id >> 16) & 0xff; + data[2] = (chain_id >> 8) & 0xff; + data[3] = (chain_id) & 0xff; + int offset = 0; + while (!data[offset]) { + offset++; + } /* hash v=chain_id, r=0, s=0 */ - hash_rlp_field(&chain_id, 1); + hash_rlp_field(data+offset, 4-offset); hash_rlp_length(0, 0); hash_rlp_length(0, 0); } @@ -225,6 +237,9 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan + case 2: suffix = " EXP"; break; // Expanse + case 8: suffix = " UBQ"; break; // UBIQ + case 7762959: suffix = " MUSIC"; break; // Musicoin default: suffix = " UNKN"; break; // unknown chain } } @@ -414,12 +429,12 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { - if (msg->chain_id < 1 || msg->chain_id > 109) { + if (msg->chain_id < 1 || msg->chain_id > MAX_CHAIN_ID) { fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); ethereum_signing_abort(); return; } - chain_id = (uint8_t) msg->chain_id; + chain_id = msg->chain_id; } else { chain_id = 0; } From ef89fc4e8940395ab531b89fbf83294dafb2e519 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Aug 2017 13:38:50 +0200 Subject: [PATCH 0570/1154] ethereum: refactor hash_rlp_number --- firmware/ethereum.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 0fe343a61d..67a7590247 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -114,6 +114,27 @@ static void hash_rlp_field(const uint8_t *buf, size_t size) hash_data(buf, size); } +/* + * Push an RLP encoded number to the hash buffer. + * Ethereum yellow paper says to convert to big endian and strip leading zeros. + */ +static void hash_rlp_number(uint32_t number) +{ + if (!number) { + return; + } + uint8_t data[4]; + data[0] = (number >> 24) & 0xff; + data[1] = (number >> 16) & 0xff; + data[2] = (number >> 8) & 0xff; + data[3] = (number) & 0xff; + int offset = 0; + while (!data[offset]) { + offset++; + } + hash_rlp_field(data + offset, 4 - offset); +} + /* * Calculate the number of bytes needed for an RLP length header. * NOTE: supports up to 16MB of data (how unlikely...) @@ -134,7 +155,6 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) } } - static void send_request_chunk(void) { int progress = 1000 - (data_total > 1000000 @@ -160,17 +180,8 @@ static void send_signature(void) /* eip-155 replay protection */ if (chain_id != 0) { - uint8_t data[4]; - data[0] = (chain_id >> 24) & 0xff; - data[1] = (chain_id >> 16) & 0xff; - data[2] = (chain_id >> 8) & 0xff; - data[3] = (chain_id) & 0xff; - int offset = 0; - while (!data[offset]) { - offset++; - } /* hash v=chain_id, r=0, s=0 */ - hash_rlp_field(data+offset, 4-offset); + hash_rlp_number(chain_id); hash_rlp_length(0, 0); hash_rlp_length(0, 0); } @@ -239,7 +250,6 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan case 2: suffix = " EXP"; break; // Expanse case 8: suffix = " UBQ"; break; // UBIQ - case 7762959: suffix = " MUSIC"; break; // Musicoin default: suffix = " UNKN"; break; // unknown chain } } From c796800b2b3c74f04bd936685a551c04fdd0b499 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Aug 2017 13:43:31 +0200 Subject: [PATCH 0571/1154] memory_protect: fix FLASH_OPTCR check --- memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/memory.c b/memory.c index 496d39e6c1..76014806d1 100644 --- a/memory.c +++ b/memory.c @@ -30,8 +30,8 @@ void memory_protect(void) #if MEMORY_PROTECT // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf // Section 2.6 Option bytes - // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches - if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && ((FLASH_OPTCR & 0x0FFFFFEC) == 0x0FFCCCED)) { + // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches + if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { return; // already set up correctly - bail out } flash_unlock_option_bytes(); From 30367bfad189312286092072c9ca8173929ca3dd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Sep 2017 08:12:33 +0200 Subject: [PATCH 0572/1154] reset: refactor code into layoutResetWord --- firmware/layout2.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ firmware/layout2.h | 1 + firmware/reset.c | 37 ++----------------------------- oled.c | 7 +----- oled.h | 5 ++++- 5 files changed, 63 insertions(+), 42 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index c456987317..b26c3be982 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -220,6 +220,61 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) str[0], str[1], str[2], str[3], NULL, NULL); } +void layoutResetWord(const char *word, int pass, int word_pos, bool last) +{ + layoutLast = layoutResetWord; + oledSwipeLeft(); + + const char *btnYes; + if (last) { + if (pass == 1) { + btnYes = _("Finish"); + } else { + btnYes = _("Again"); + } + } else { + btnYes = _("Next"); + } + + const char *action; + if (pass == 1) { + action = _("Please check the seed"); + } else { + action = _("Write down the seed"); + } + + char index_str[] = "##th word is:"; + if (word_pos < 10) { + index_str[0] = ' '; + } else { + index_str[0] = '0' + word_pos / 10; + } + index_str[1] = '0' + word_pos % 10; + if (word_pos == 1 || word_pos == 21) { + index_str[2] = 's'; index_str[3] = 't'; + } else + if (word_pos == 2 || word_pos == 22) { + index_str[2] = 'n'; index_str[3] = 'd'; + } else + if (word_pos == 3 || word_pos == 23) { + index_str[2] = 'r'; index_str[3] = 'd'; + } + + int left = 0; + oledClear(); + oledDrawBitmap(0, 0, &bmp_icon_info); + left = bmp_icon_info.width + 4; + + oledDrawString(left, 0 * 9, action); + oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str); + oledDrawStringDouble(left, 3 * 9, word); + oledHLine(OLED_HEIGHT - 13); + oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); + oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledRefresh(); +} + void layoutAddress(const char *address, const char *desc, bool qrcode) { if (layoutLast != layoutAddress) { diff --git a/firmware/layout2.h b/firmware/layout2.h index c1e368a91b..643aa4624b 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -40,6 +40,7 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); +void layoutResetWord(const char *word, int pass, int word_pos, bool last); void layoutAddress(const char *address, const char *desc, bool qrcode); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); diff --git a/firmware/reset.c b/firmware/reset.c index 7f8d2c3810..8217d27317 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -106,7 +106,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) } -static char current_word[10], current_word_display[11]; +static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage void reset_backup(bool separated) @@ -133,40 +133,7 @@ void reset_backup(bool separated) if (storage.mnemonic[i] != 0) { i++; } - char desc[] = "##th word is:"; - if (word_pos < 10) { - desc[0] = ' '; - } else { - desc[0] = '0' + word_pos / 10; - } - desc[1] = '0' + word_pos % 10; - if (word_pos == 1 || word_pos == 21) { - desc[2] = 's'; desc[3] = 't'; - } else - if (word_pos == 2 || word_pos == 22) { - desc[2] = 'n'; desc[3] = 'd'; - } else - if (word_pos == 3 || word_pos == 23) { - desc[2] = 'r'; desc[3] = 'd'; - } - current_word_display[0] = 0x01; - for (j = 0; current_word[j]; j++) { - current_word_display[j + 1] = current_word[j] + 'A' - 'a'; - } - current_word_display[j + 1] = 0; - if (storage.mnemonic[i] == 0) { // last word - if (pass == 1) { - layoutDialogSwipe(&bmp_icon_info, NULL, _("Finish"), NULL, _("Please check the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); - } else { - layoutDialogSwipe(&bmp_icon_info, NULL, _("Again"), NULL, _("Write down the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); - } - } else { - if (pass == 1) { - layoutDialogSwipe(&bmp_icon_info, NULL, _("Next"), NULL, _("Please check the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); - } else { - layoutDialogSwipe(&bmp_icon_info, NULL, _("Next"), NULL, _("Write down the seed"), NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL); - } - } + layoutResetWord(current_word, pass, word_pos, storage.mnemonic[i] == 0); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { storage_reset(); diff --git a/oled.c b/oled.c index de834b2ca5..52116f20ef 100644 --- a/oled.c +++ b/oled.c @@ -281,14 +281,9 @@ int oledStringWidth(const char *text) { return l; } -void oledDrawString(int x, int y, const char* text) +void oledDrawStringSize(int x, int y, const char* text, int size) { if (!text) return; - int size = 1; - if (*text == 0x01) { // double size - text++; - size = 2; - } int l = 0; for (; *text; text++) { char c = oledConvertChar(*text); diff --git a/oled.h b/oled.h index 8bf37f79ad..f5e711e1ea 100644 --- a/oled.h +++ b/oled.h @@ -42,7 +42,10 @@ void oledClearPixel(int x, int y); void oledInvertPixel(int x, int y); void oledDrawChar(int x, int y, char c, int zoom); int oledStringWidth(const char *text); -void oledDrawString(int x, int y, const char* text); + +#define oledDrawString(x, y, text) oledDrawStringSize((x), (y), (text), 1) +#define oledDrawStringDouble(x, y, text) oledDrawStringSize((x), (y), (text), 2) +void oledDrawStringSize(int x, int y, const char* text, int size); void oledDrawStringCenter(int y, const char* text); void oledDrawStringRight(int x, int y, const char* text); void oledDrawBitmap(int x, int y, const BITMAP *bmp); From 5cc299facdae4d6884776f0ddacaebff134da9a5 Mon Sep 17 00:00:00 2001 From: Jason Zavaglia Date: Thu, 28 Sep 2017 21:10:32 +1000 Subject: [PATCH 0573/1154] Generate the protobuf files at build time (#219) Improve the build reliability by ensuring protobuf files are generated at build time. --- .gitmodules | 3 +++ Dockerfile | 3 ++- build-firmware.sh | 2 ++ firmware/protob/Makefile | 2 +- vendor/nanopb | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) create mode 160000 vendor/nanopb diff --git a/.gitmodules b/.gitmodules index 4fe0f75397..920894a059 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "libopencm3"] path = vendor/libopencm3 url = https://github.com/libopencm3/libopencm3.git +[submodule "vendor/nanopb"] + path = vendor/nanopb + url = https://github.com/nanopb/nanopb.git diff --git a/Dockerfile b/Dockerfile index ad05037a6d..00cd4a039f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,5 @@ RUN apt-get update # install build tools and dependencies -RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi +RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi protobuf-compiler \ + libprotobuf-dev python-protobuf python3-protobuf diff --git a/build-firmware.sh b/build-firmware.sh index a045e7cb8d..6543b7fc59 100755 --- a/build-firmware.sh +++ b/build-firmware.sh @@ -13,6 +13,8 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ git checkout $TAG && \ git submodule update --init && \ make -C vendor/libopencm3 && \ + make -C vendor/nanopb/generator/proto && \ + make -C firmware/protob && \ make && \ make -C firmware sign && \ cp firmware/trezor.bin /$BINFILE && \ diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 38486526cd..6897debd11 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,7 +1,7 @@ all: messages.pb.c storage.pb.c types.pb.c messages_map.h %.pb.c: %.pb %.options - nanopb_generator.py $< -L '#include "%s"' -T + ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T %.pb: %.proto protoc -I/usr/include -I. $< -o $@ diff --git a/vendor/nanopb b/vendor/nanopb new file mode 160000 index 0000000000..54c34a9fda --- /dev/null +++ b/vendor/nanopb @@ -0,0 +1 @@ +Subproject commit 54c34a9fda152937d4cd0c7fd85c067fca23af75 From 6f5aeee18fe60885c38422229fda30d2438bc5d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Sep 2017 13:12:28 +0200 Subject: [PATCH 0574/1154] build: split deps in dockerfile into two lines --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 00cd4a039f..9b98775d9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,5 +8,5 @@ RUN apt-get update # install build tools and dependencies -RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi protobuf-compiler \ - libprotobuf-dev python-protobuf python3-protobuf +RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi +RUN apt-get install protobuf-compiler libprotobuf-dev python-protobuf python3-protobuf From 1f1c3bf35fe8d3777943de1e6fb959357c2015e4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Sep 2017 13:16:15 +0200 Subject: [PATCH 0575/1154] firmware/protob: remove generated stuff --- firmware/protob/messages.pb.c | 450 ------------ firmware/protob/messages.pb.h | 1227 ------------------------------ firmware/protob/messages_map.h | 90 --- firmware/protob/pb.h | 520 +------------ firmware/protob/pb_decode.c | 1268 +------------------------------- firmware/protob/pb_decode.h | 150 +--- firmware/protob/pb_encode.c | 668 +---------------- firmware/protob/pb_encode.h | 155 +--- firmware/protob/storage.pb.c | 42 -- firmware/protob/storage.pb.h | 79 -- firmware/protob/types.pb.c | 213 ------ firmware/protob/types.pb.h | 422 ----------- 12 files changed, 5 insertions(+), 5279 deletions(-) delete mode 100644 firmware/protob/messages.pb.c delete mode 100644 firmware/protob/messages.pb.h delete mode 100644 firmware/protob/messages_map.h mode change 100644 => 120000 firmware/protob/pb.h mode change 100644 => 120000 firmware/protob/pb_decode.c mode change 100644 => 120000 firmware/protob/pb_decode.h mode change 100644 => 120000 firmware/protob/pb_encode.c mode change 100644 => 120000 firmware/protob/pb_encode.h delete mode 100644 firmware/protob/storage.pb.c delete mode 100644 firmware/protob/storage.pb.h delete mode 100644 firmware/protob/types.pb.c delete mode 100644 firmware/protob/types.pb.h diff --git a/firmware/protob/messages.pb.c b/firmware/protob/messages.pb.c deleted file mode 100644 index 54de2aaa1e..0000000000 --- a/firmware/protob/messages.pb.c +++ /dev/null @@ -1,450 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.3 */ - -#include "messages.pb.h" - -const char GetPublicKey_coin_name_default[21] = "Bitcoin"; -const char GetAddress_coin_name_default[21] = "Bitcoin"; -const InputScriptType GetAddress_script_type_default = InputScriptType_SPENDADDRESS; -const char LoadDevice_language_default[17] = "english"; -const uint32_t ResetDevice_strength_default = 256u; -const char ResetDevice_language_default[17] = "english"; -const char RecoveryDevice_language_default[17] = "english"; -const char SignMessage_coin_name_default[21] = "Bitcoin"; -const InputScriptType SignMessage_script_type_default = InputScriptType_SPENDADDRESS; -const char VerifyMessage_coin_name_default[21] = "Bitcoin"; -const char SignTx_coin_name_default[21] = "Bitcoin"; -const uint32_t SignTx_version_default = 1u; -const uint32_t SignTx_lock_time_default = 0u; - - -const pb_field_t Initialize_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t GetFeatures_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t Features_fields[21] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Features, vendor, vendor, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, Features, major_version, vendor, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, Features, minor_version, major_version, 0), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, Features, patch_version, minor_version, 0), - PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, Features, bootloader_mode, patch_version, 0), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Features, device_id, bootloader_mode, 0), - PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_protection, device_id, 0), - PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_protection, pin_protection, 0), - PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, Features, language, passphrase_protection, 0), - PB_FIELD2( 10, STRING , OPTIONAL, STATIC , OTHER, Features, label, language, 0), - PB_FIELD2( 11, MESSAGE , REPEATED, STATIC , OTHER, Features, coins, label, &CoinType_fields), - PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Features, initialized, coins, 0), - PB_FIELD2( 13, BYTES , OPTIONAL, STATIC , OTHER, Features, revision, initialized, 0), - PB_FIELD2( 14, BYTES , OPTIONAL, STATIC , OTHER, Features, bootloader_hash, revision, 0), - PB_FIELD2( 15, BOOL , OPTIONAL, STATIC , OTHER, Features, imported, bootloader_hash, 0), - PB_FIELD2( 16, BOOL , OPTIONAL, STATIC , OTHER, Features, pin_cached, imported, 0), - PB_FIELD2( 17, BOOL , OPTIONAL, STATIC , OTHER, Features, passphrase_cached, pin_cached, 0), - PB_FIELD2( 18, BOOL , OPTIONAL, STATIC , OTHER, Features, firmware_present, passphrase_cached, 0), - PB_FIELD2( 19, BOOL , OPTIONAL, STATIC , OTHER, Features, needs_backup, firmware_present, 0), - PB_FIELD2( 20, UINT32 , OPTIONAL, STATIC , OTHER, Features, flags, needs_backup, 0), - PB_LAST_FIELD -}; - -const pb_field_t ClearSession_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t ApplySettings_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, ApplySettings, language, language, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ApplySettings, label, language, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ApplySettings, use_passphrase, label, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, ApplySettings, homescreen, use_passphrase, 0), - PB_LAST_FIELD -}; - -const pb_field_t ApplyFlags_fields[2] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, ApplyFlags, flags, flags, 0), - PB_LAST_FIELD -}; - -const pb_field_t ChangePin_fields[2] = { - PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ChangePin, remove, remove, 0), - PB_LAST_FIELD -}; - -const pb_field_t Ping_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Ping, message, message, 0), - PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, Ping, button_protection, message, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, Ping, pin_protection, button_protection, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Ping, passphrase_protection, pin_protection, 0), - PB_LAST_FIELD -}; - -const pb_field_t Success_fields[2] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, Success, message, message, 0), - PB_LAST_FIELD -}; - -const pb_field_t Failure_fields[3] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, Failure, code, code, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, Failure, message, code, 0), - PB_LAST_FIELD -}; - -const pb_field_t ButtonRequest_fields[3] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, ButtonRequest, code, code, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, ButtonRequest, data, code, 0), - PB_LAST_FIELD -}; - -const pb_field_t ButtonAck_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t PinMatrixRequest_fields[2] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, PinMatrixRequest, type, type, 0), - PB_LAST_FIELD -}; - -const pb_field_t PinMatrixAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PinMatrixAck, pin, pin, 0), - PB_LAST_FIELD -}; - -const pb_field_t Cancel_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t PassphraseRequest_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t PassphraseAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, PassphraseAck, passphrase, passphrase, 0), - PB_LAST_FIELD -}; - -const pb_field_t GetEntropy_fields[2] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, GetEntropy, size, size, 0), - PB_LAST_FIELD -}; - -const pb_field_t Entropy_fields[2] = { - PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, Entropy, entropy, entropy, 0), - PB_LAST_FIELD -}; - -const pb_field_t GetPublicKey_fields[5] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetPublicKey, show_display, ecdsa_curve_name, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, coin_name, show_display, &GetPublicKey_coin_name_default), - PB_LAST_FIELD -}; - -const pb_field_t PublicKey_fields[3] = { - PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, PublicKey, node, node, &HDNodeType_fields), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, PublicKey, xpub, node, 0), - PB_LAST_FIELD -}; - -const pb_field_t GetAddress_fields[6] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetAddress, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetAddress, coin_name, address_n, &GetAddress_coin_name_default), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetAddress, show_display, coin_name, 0), - PB_FIELD2( 4, MESSAGE , OPTIONAL, STATIC , OTHER, GetAddress, multisig, show_display, &MultisigRedeemScriptType_fields), - PB_FIELD2( 5, ENUM , OPTIONAL, STATIC , OTHER, GetAddress, script_type, multisig, &GetAddress_script_type_default), - PB_LAST_FIELD -}; - -const pb_field_t EthereumGetAddress_fields[3] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumGetAddress, address_n, address_n, 0), - PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, EthereumGetAddress, show_display, address_n, 0), - PB_LAST_FIELD -}; - -const pb_field_t Address_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, Address, address, address, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumAddress_fields[2] = { - PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, EthereumAddress, address, address, 0), - PB_LAST_FIELD -}; - -const pb_field_t WipeDevice_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t LoadDevice_fields[9] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, LoadDevice, mnemonic, mnemonic, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, LoadDevice, node, mnemonic, &HDNodeType_fields), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, pin, node, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, passphrase_protection, pin, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, language, passphrase_protection, &LoadDevice_language_default), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, LoadDevice, label, language, 0), - PB_FIELD2( 7, BOOL , OPTIONAL, STATIC , OTHER, LoadDevice, skip_checksum, label, 0), - PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, LoadDevice, u2f_counter, skip_checksum, 0), - PB_LAST_FIELD -}; - -const pb_field_t ResetDevice_fields[9] = { - PB_FIELD2( 1, BOOL , OPTIONAL, STATIC , FIRST, ResetDevice, display_random, display_random, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, strength, display_random, &ResetDevice_strength_default), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, passphrase_protection, strength, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, pin_protection, passphrase_protection, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, language, pin_protection, &ResetDevice_language_default), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, ResetDevice, label, language, 0), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, ResetDevice, u2f_counter, label, 0), - PB_FIELD2( 8, BOOL , OPTIONAL, STATIC , OTHER, ResetDevice, skip_backup, u2f_counter, 0), - PB_LAST_FIELD -}; - -const pb_field_t BackupDevice_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t EntropyRequest_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t EntropyAck_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EntropyAck, entropy, entropy, 0), - PB_LAST_FIELD -}; - -const pb_field_t RecoveryDevice_fields[10] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, RecoveryDevice, word_count, word_count, 0), - PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, passphrase_protection, word_count, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, pin_protection, passphrase_protection, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, language, pin_protection, &RecoveryDevice_language_default), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, RecoveryDevice, label, language, 0), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, enforce_wordlist, label, 0), - PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, type, enforce_wordlist, 0), - PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, RecoveryDevice, u2f_counter, type, 0), - PB_FIELD2( 10, BOOL , OPTIONAL, STATIC , OTHER, RecoveryDevice, dry_run, u2f_counter, 0), - PB_LAST_FIELD -}; - -const pb_field_t WordRequest_fields[2] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, WordRequest, type, type, 0), - PB_LAST_FIELD -}; - -const pb_field_t WordAck_fields[2] = { - PB_FIELD2( 1, STRING , REQUIRED, STATIC , FIRST, WordAck, word, word, 0), - PB_LAST_FIELD -}; - -const pb_field_t SignMessage_fields[5] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, SignMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, SignMessage, message, address_n, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignMessage, coin_name, message, &SignMessage_coin_name_default), - PB_FIELD2( 4, ENUM , OPTIONAL, STATIC , OTHER, SignMessage, script_type, coin_name, &SignMessage_script_type_default), - PB_LAST_FIELD -}; - -const pb_field_t VerifyMessage_fields[5] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, VerifyMessage, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, signature, address, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, VerifyMessage, message, signature, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, VerifyMessage, coin_name, message, &VerifyMessage_coin_name_default), - PB_LAST_FIELD -}; - -const pb_field_t MessageSignature_fields[3] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, MessageSignature, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, MessageSignature, signature, address, 0), - PB_LAST_FIELD -}; - -const pb_field_t CipherKeyValue_fields[8] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, CipherKeyValue, address_n, address_n, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CipherKeyValue, key, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, value, key, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, encrypt, value, 0), - PB_FIELD2( 5, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_encrypt, encrypt, 0), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, CipherKeyValue, ask_on_decrypt, ask_on_encrypt, 0), - PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, CipherKeyValue, iv, ask_on_decrypt, 0), - PB_LAST_FIELD -}; - -const pb_field_t CipheredKeyValue_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, CipheredKeyValue, value, value, 0), - PB_LAST_FIELD -}; - -const pb_field_t SignTx_fields[6] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, version, coin_name, &SignTx_version_default), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, lock_time, version, &SignTx_lock_time_default), - PB_LAST_FIELD -}; - -const pb_field_t TxRequest_fields[4] = { - PB_FIELD2( 1, ENUM , OPTIONAL, STATIC , FIRST, TxRequest, request_type, request_type, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, details, request_type, &TxRequestDetailsType_fields), - PB_FIELD2( 3, MESSAGE , OPTIONAL, STATIC , OTHER, TxRequest, serialized, details, &TxRequestSerializedType_fields), - PB_LAST_FIELD -}; - -const pb_field_t TxAck_fields[2] = { - PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, TxAck, tx, tx, &TransactionType_fields), - PB_LAST_FIELD -}; - -const pb_field_t EthereumSignTx_fields[10] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_limit, gas_price, 0), - PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, to, gas_limit, 0), - PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, value, to, 0), - PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0), - PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0), - PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumTxRequest_fields[5] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, EthereumTxRequest, data_length, data_length, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_v, data_length, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_r, signature_v, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_s, signature_r, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumTxAck_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumTxAck, data_chunk, data_chunk, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumSignMessage_fields[3] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignMessage, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, EthereumSignMessage, message, address_n, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumVerifyMessage_fields[4] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumVerifyMessage, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumVerifyMessage, signature, address, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumVerifyMessage, message, signature, 0), - PB_LAST_FIELD -}; - -const pb_field_t EthereumMessageSignature_fields[3] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumMessageSignature, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumMessageSignature, signature, address, 0), - PB_LAST_FIELD -}; - -const pb_field_t SignIdentity_fields[5] = { - PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, SignIdentity, identity, identity, &IdentityType_fields), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_hidden, identity, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignIdentity, challenge_visual, challenge_hidden, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SignIdentity, ecdsa_curve_name, challenge_visual, 0), - PB_LAST_FIELD -}; - -const pb_field_t SignedIdentity_fields[4] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, SignedIdentity, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, SignedIdentity, public_key, address, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, SignedIdentity, signature, public_key, 0), - PB_LAST_FIELD -}; - -const pb_field_t GetECDHSessionKey_fields[4] = { - PB_FIELD2( 1, MESSAGE , OPTIONAL, STATIC , FIRST, GetECDHSessionKey, identity, identity, &IdentityType_fields), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, GetECDHSessionKey, peer_public_key, identity, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, GetECDHSessionKey, ecdsa_curve_name, peer_public_key, 0), - PB_LAST_FIELD -}; - -const pb_field_t ECDHSessionKey_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, ECDHSessionKey, session_key, session_key, 0), - PB_LAST_FIELD -}; - -const pb_field_t SetU2FCounter_fields[2] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, SetU2FCounter, u2f_counter, u2f_counter, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkDecision_fields[2] = { - PB_FIELD2( 1, BOOL , REQUIRED, STATIC , FIRST, DebugLinkDecision, yes_no, yes_no, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkGetState_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkState_fields[11] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkState, layout, layout, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, pin, layout, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, matrix, pin, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, mnemonic, matrix, 0), - PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, DebugLinkState, node, mnemonic, &HDNodeType_fields), - PB_FIELD2( 6, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkState, passphrase_protection, node, 0), - PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_word, passphrase_protection, 0), - PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkState, reset_entropy, reset_word, 0), - PB_FIELD2( 9, STRING , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_fake_word, reset_entropy, 0), - PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkState, recovery_word_pos, recovery_fake_word, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkStop_fields[1] = { - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkLog_fields[4] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkLog, level, level, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, bucket, level, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, DebugLinkLog, text, bucket, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkMemoryRead_fields[3] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryRead, address, address, 0), - PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkMemoryRead, length, address, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkMemory_fields[2] = { - PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkMemory, memory, memory, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkMemoryWrite_fields[4] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryWrite, address, address, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, memory, address, 0), - PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, flash, memory, 0), - PB_LAST_FIELD -}; - -const pb_field_t DebugLinkFlashErase_fields[2] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkFlashErase, sector, sector, 0), - PB_LAST_FIELD -}; - - -/* Check that field information fits in pb_field_t */ -#if !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_32BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in 8 or 16 bit - * field descriptors. - */ -STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ApplyFlags_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_BackupDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_CipherKeyValue_CipheredKeyValue_SignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_EthereumSignMessage_EthereumVerifyMessage_EthereumMessageSignature_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_SetU2FCounter_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase) -#endif - -#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for ApplySettings.homescreen is too large. Define PB_FIELD_16BIT to fix this. -#endif - - diff --git a/firmware/protob/messages.pb.h b/firmware/protob/messages.pb.h deleted file mode 100644 index 9ac45f06e0..0000000000 --- a/firmware/protob/messages.pb.h +++ /dev/null @@ -1,1227 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.3 */ - -#ifndef _PB_MESSAGES_PB_H_ -#define _PB_MESSAGES_PB_H_ -#include "pb.h" -#include "types.pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Enum definitions */ -typedef enum _MessageType { - MessageType_MessageType_Initialize = 0, - MessageType_MessageType_Ping = 1, - MessageType_MessageType_Success = 2, - MessageType_MessageType_Failure = 3, - MessageType_MessageType_ChangePin = 4, - MessageType_MessageType_WipeDevice = 5, - MessageType_MessageType_FirmwareErase = 6, - MessageType_MessageType_FirmwareUpload = 7, - MessageType_MessageType_FirmwareRequest = 8, - MessageType_MessageType_GetEntropy = 9, - MessageType_MessageType_Entropy = 10, - MessageType_MessageType_GetPublicKey = 11, - MessageType_MessageType_PublicKey = 12, - MessageType_MessageType_LoadDevice = 13, - MessageType_MessageType_ResetDevice = 14, - MessageType_MessageType_SignTx = 15, - MessageType_MessageType_SimpleSignTx = 16, - MessageType_MessageType_Features = 17, - MessageType_MessageType_PinMatrixRequest = 18, - MessageType_MessageType_PinMatrixAck = 19, - MessageType_MessageType_Cancel = 20, - MessageType_MessageType_TxRequest = 21, - MessageType_MessageType_TxAck = 22, - MessageType_MessageType_CipherKeyValue = 23, - MessageType_MessageType_ClearSession = 24, - MessageType_MessageType_ApplySettings = 25, - MessageType_MessageType_ButtonRequest = 26, - MessageType_MessageType_ButtonAck = 27, - MessageType_MessageType_ApplyFlags = 28, - MessageType_MessageType_GetAddress = 29, - MessageType_MessageType_Address = 30, - MessageType_MessageType_SelfTest = 32, - MessageType_MessageType_BackupDevice = 34, - MessageType_MessageType_EntropyRequest = 35, - MessageType_MessageType_EntropyAck = 36, - MessageType_MessageType_SignMessage = 38, - MessageType_MessageType_VerifyMessage = 39, - MessageType_MessageType_MessageSignature = 40, - MessageType_MessageType_PassphraseRequest = 41, - MessageType_MessageType_PassphraseAck = 42, - MessageType_MessageType_EstimateTxSize = 43, - MessageType_MessageType_TxSize = 44, - MessageType_MessageType_RecoveryDevice = 45, - MessageType_MessageType_WordRequest = 46, - MessageType_MessageType_WordAck = 47, - MessageType_MessageType_CipheredKeyValue = 48, - MessageType_MessageType_EncryptMessage = 49, - MessageType_MessageType_EncryptedMessage = 50, - MessageType_MessageType_DecryptMessage = 51, - MessageType_MessageType_DecryptedMessage = 52, - MessageType_MessageType_SignIdentity = 53, - MessageType_MessageType_SignedIdentity = 54, - MessageType_MessageType_GetFeatures = 55, - MessageType_MessageType_EthereumGetAddress = 56, - MessageType_MessageType_EthereumAddress = 57, - MessageType_MessageType_EthereumSignTx = 58, - MessageType_MessageType_EthereumTxRequest = 59, - MessageType_MessageType_EthereumTxAck = 60, - MessageType_MessageType_GetECDHSessionKey = 61, - MessageType_MessageType_ECDHSessionKey = 62, - MessageType_MessageType_SetU2FCounter = 63, - MessageType_MessageType_EthereumSignMessage = 64, - MessageType_MessageType_EthereumVerifyMessage = 65, - MessageType_MessageType_EthereumMessageSignature = 66, - MessageType_MessageType_DebugLinkDecision = 100, - MessageType_MessageType_DebugLinkGetState = 101, - MessageType_MessageType_DebugLinkState = 102, - MessageType_MessageType_DebugLinkStop = 103, - MessageType_MessageType_DebugLinkLog = 104, - MessageType_MessageType_DebugLinkMemoryRead = 110, - MessageType_MessageType_DebugLinkMemory = 111, - MessageType_MessageType_DebugLinkMemoryWrite = 112, - MessageType_MessageType_DebugLinkFlashErase = 113 -} MessageType; - -/* Struct definitions */ -typedef struct _BackupDevice { - uint8_t dummy_field; -} BackupDevice; - -typedef struct _ButtonAck { - uint8_t dummy_field; -} ButtonAck; - -typedef struct _Cancel { - uint8_t dummy_field; -} Cancel; - -typedef struct _ClearSession { - uint8_t dummy_field; -} ClearSession; - -typedef struct _DebugLinkGetState { - uint8_t dummy_field; -} DebugLinkGetState; - -typedef struct _DebugLinkStop { - uint8_t dummy_field; -} DebugLinkStop; - -typedef struct _EntropyRequest { - uint8_t dummy_field; -} EntropyRequest; - -typedef struct _GetFeatures { - uint8_t dummy_field; -} GetFeatures; - -typedef struct _Initialize { - uint8_t dummy_field; -} Initialize; - -typedef struct _PassphraseRequest { - uint8_t dummy_field; -} PassphraseRequest; - -typedef struct _WipeDevice { - uint8_t dummy_field; -} WipeDevice; - -typedef struct _Address { - char address[60]; -} Address; - -typedef struct _ApplyFlags { - bool has_flags; - uint32_t flags; -} ApplyFlags; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} ApplySettings_homescreen_t; - -typedef struct _ApplySettings { - bool has_language; - char language[17]; - bool has_label; - char label[33]; - bool has_use_passphrase; - bool use_passphrase; - bool has_homescreen; - ApplySettings_homescreen_t homescreen; -} ApplySettings; - -typedef struct _ButtonRequest { - bool has_code; - ButtonRequestType code; - bool has_data; - char data[256]; -} ButtonRequest; - -typedef struct _ChangePin { - bool has_remove; - bool remove; -} ChangePin; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} CipherKeyValue_value_t; - -typedef struct { - size_t size; - uint8_t bytes[16]; -} CipherKeyValue_iv_t; - -typedef struct _CipherKeyValue { - size_t address_n_count; - uint32_t address_n[8]; - bool has_key; - char key[256]; - bool has_value; - CipherKeyValue_value_t value; - bool has_encrypt; - bool encrypt; - bool has_ask_on_encrypt; - bool ask_on_encrypt; - bool has_ask_on_decrypt; - bool ask_on_decrypt; - bool has_iv; - CipherKeyValue_iv_t iv; -} CipherKeyValue; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} CipheredKeyValue_value_t; - -typedef struct _CipheredKeyValue { - bool has_value; - CipheredKeyValue_value_t value; -} CipheredKeyValue; - -typedef struct _DebugLinkDecision { - bool yes_no; -} DebugLinkDecision; - -typedef struct _DebugLinkFlashErase { - bool has_sector; - uint32_t sector; -} DebugLinkFlashErase; - -typedef struct _DebugLinkLog { - bool has_level; - uint32_t level; - bool has_bucket; - char bucket[33]; - bool has_text; - char text[256]; -} DebugLinkLog; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DebugLinkMemory_memory_t; - -typedef struct _DebugLinkMemory { - bool has_memory; - DebugLinkMemory_memory_t memory; -} DebugLinkMemory; - -typedef struct _DebugLinkMemoryRead { - bool has_address; - uint32_t address; - bool has_length; - uint32_t length; -} DebugLinkMemoryRead; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DebugLinkMemoryWrite_memory_t; - -typedef struct _DebugLinkMemoryWrite { - bool has_address; - uint32_t address; - bool has_memory; - DebugLinkMemoryWrite_memory_t memory; - bool has_flash; - bool flash; -} DebugLinkMemoryWrite; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} DebugLinkState_layout_t; - -typedef struct { - size_t size; - uint8_t bytes[128]; -} DebugLinkState_reset_entropy_t; - -typedef struct _DebugLinkState { - bool has_layout; - DebugLinkState_layout_t layout; - bool has_pin; - char pin[10]; - bool has_matrix; - char matrix[10]; - bool has_mnemonic; - char mnemonic[241]; - bool has_node; - HDNodeType node; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_reset_word; - char reset_word[12]; - bool has_reset_entropy; - DebugLinkState_reset_entropy_t reset_entropy; - bool has_recovery_fake_word; - char recovery_fake_word[12]; - bool has_recovery_word_pos; - uint32_t recovery_word_pos; -} DebugLinkState; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} ECDHSessionKey_session_key_t; - -typedef struct _ECDHSessionKey { - bool has_session_key; - ECDHSessionKey_session_key_t session_key; -} ECDHSessionKey; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} Entropy_entropy_t; - -typedef struct _Entropy { - Entropy_entropy_t entropy; -} Entropy; - -typedef struct { - size_t size; - uint8_t bytes[128]; -} EntropyAck_entropy_t; - -typedef struct _EntropyAck { - bool has_entropy; - EntropyAck_entropy_t entropy; -} EntropyAck; - -typedef struct { - size_t size; - uint8_t bytes[20]; -} EthereumAddress_address_t; - -typedef struct _EthereumAddress { - EthereumAddress_address_t address; -} EthereumAddress; - -typedef struct _EthereumGetAddress { - size_t address_n_count; - uint32_t address_n[8]; - bool has_show_display; - bool show_display; -} EthereumGetAddress; - -typedef struct { - size_t size; - uint8_t bytes[20]; -} EthereumMessageSignature_address_t; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} EthereumMessageSignature_signature_t; - -typedef struct _EthereumMessageSignature { - bool has_address; - EthereumMessageSignature_address_t address; - bool has_signature; - EthereumMessageSignature_signature_t signature; -} EthereumMessageSignature; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EthereumSignMessage_message_t; - -typedef struct _EthereumSignMessage { - size_t address_n_count; - uint32_t address_n[8]; - EthereumSignMessage_message_t message; -} EthereumSignMessage; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumSignTx_nonce_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumSignTx_gas_price_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumSignTx_gas_limit_t; - -typedef struct { - size_t size; - uint8_t bytes[20]; -} EthereumSignTx_to_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumSignTx_value_t; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EthereumSignTx_data_initial_chunk_t; - -typedef struct _EthereumSignTx { - size_t address_n_count; - uint32_t address_n[8]; - bool has_nonce; - EthereumSignTx_nonce_t nonce; - bool has_gas_price; - EthereumSignTx_gas_price_t gas_price; - bool has_gas_limit; - EthereumSignTx_gas_limit_t gas_limit; - bool has_to; - EthereumSignTx_to_t to; - bool has_value; - EthereumSignTx_value_t value; - bool has_data_initial_chunk; - EthereumSignTx_data_initial_chunk_t data_initial_chunk; - bool has_data_length; - uint32_t data_length; - bool has_chain_id; - uint32_t chain_id; -} EthereumSignTx; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EthereumTxAck_data_chunk_t; - -typedef struct _EthereumTxAck { - bool has_data_chunk; - EthereumTxAck_data_chunk_t data_chunk; -} EthereumTxAck; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumTxRequest_signature_r_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} EthereumTxRequest_signature_s_t; - -typedef struct _EthereumTxRequest { - bool has_data_length; - uint32_t data_length; - bool has_signature_v; - uint32_t signature_v; - bool has_signature_r; - EthereumTxRequest_signature_r_t signature_r; - bool has_signature_s; - EthereumTxRequest_signature_s_t signature_s; -} EthereumTxRequest; - -typedef struct { - size_t size; - uint8_t bytes[20]; -} EthereumVerifyMessage_address_t; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} EthereumVerifyMessage_signature_t; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} EthereumVerifyMessage_message_t; - -typedef struct _EthereumVerifyMessage { - bool has_address; - EthereumVerifyMessage_address_t address; - bool has_signature; - EthereumVerifyMessage_signature_t signature; - bool has_message; - EthereumVerifyMessage_message_t message; -} EthereumVerifyMessage; - -typedef struct _Failure { - bool has_code; - FailureType code; - bool has_message; - char message[256]; -} Failure; - -typedef struct { - size_t size; - uint8_t bytes[20]; -} Features_revision_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} Features_bootloader_hash_t; - -typedef struct _Features { - bool has_vendor; - char vendor[33]; - bool has_major_version; - uint32_t major_version; - bool has_minor_version; - uint32_t minor_version; - bool has_patch_version; - uint32_t patch_version; - bool has_bootloader_mode; - bool bootloader_mode; - bool has_device_id; - char device_id[25]; - bool has_pin_protection; - bool pin_protection; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_language; - char language[17]; - bool has_label; - char label[33]; - size_t coins_count; - CoinType coins[10]; - bool has_initialized; - bool initialized; - bool has_revision; - Features_revision_t revision; - bool has_bootloader_hash; - Features_bootloader_hash_t bootloader_hash; - bool has_imported; - bool imported; - bool has_pin_cached; - bool pin_cached; - bool has_passphrase_cached; - bool passphrase_cached; - bool has_firmware_present; - bool firmware_present; - bool has_needs_backup; - bool needs_backup; - bool has_flags; - uint32_t flags; -} Features; - -typedef struct _GetAddress { - size_t address_n_count; - uint32_t address_n[8]; - bool has_coin_name; - char coin_name[21]; - bool has_show_display; - bool show_display; - bool has_multisig; - MultisigRedeemScriptType multisig; - bool has_script_type; - InputScriptType script_type; -} GetAddress; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} GetECDHSessionKey_peer_public_key_t; - -typedef struct _GetECDHSessionKey { - bool has_identity; - IdentityType identity; - bool has_peer_public_key; - GetECDHSessionKey_peer_public_key_t peer_public_key; - bool has_ecdsa_curve_name; - char ecdsa_curve_name[32]; -} GetECDHSessionKey; - -typedef struct _GetEntropy { - uint32_t size; -} GetEntropy; - -typedef struct _GetPublicKey { - size_t address_n_count; - uint32_t address_n[8]; - bool has_ecdsa_curve_name; - char ecdsa_curve_name[32]; - bool has_show_display; - bool show_display; - bool has_coin_name; - char coin_name[21]; -} GetPublicKey; - -typedef struct _LoadDevice { - bool has_mnemonic; - char mnemonic[241]; - bool has_node; - HDNodeType node; - bool has_pin; - char pin[10]; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_language; - char language[17]; - bool has_label; - char label[33]; - bool has_skip_checksum; - bool skip_checksum; - bool has_u2f_counter; - uint32_t u2f_counter; -} LoadDevice; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} MessageSignature_signature_t; - -typedef struct _MessageSignature { - bool has_address; - char address[60]; - bool has_signature; - MessageSignature_signature_t signature; -} MessageSignature; - -typedef struct _PassphraseAck { - char passphrase[51]; -} PassphraseAck; - -typedef struct _PinMatrixAck { - char pin[10]; -} PinMatrixAck; - -typedef struct _PinMatrixRequest { - bool has_type; - PinMatrixRequestType type; -} PinMatrixRequest; - -typedef struct _Ping { - bool has_message; - char message[256]; - bool has_button_protection; - bool button_protection; - bool has_pin_protection; - bool pin_protection; - bool has_passphrase_protection; - bool passphrase_protection; -} Ping; - -typedef struct _PublicKey { - HDNodeType node; - bool has_xpub; - char xpub[113]; -} PublicKey; - -typedef struct _RecoveryDevice { - bool has_word_count; - uint32_t word_count; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_pin_protection; - bool pin_protection; - bool has_language; - char language[17]; - bool has_label; - char label[33]; - bool has_enforce_wordlist; - bool enforce_wordlist; - bool has_type; - uint32_t type; - bool has_u2f_counter; - uint32_t u2f_counter; - bool has_dry_run; - bool dry_run; -} RecoveryDevice; - -typedef struct _ResetDevice { - bool has_display_random; - bool display_random; - bool has_strength; - uint32_t strength; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_pin_protection; - bool pin_protection; - bool has_language; - char language[17]; - bool has_label; - char label[33]; - bool has_u2f_counter; - uint32_t u2f_counter; - bool has_skip_backup; - bool skip_backup; -} ResetDevice; - -typedef struct _SetU2FCounter { - bool has_u2f_counter; - uint32_t u2f_counter; -} SetU2FCounter; - -typedef struct { - size_t size; - uint8_t bytes[256]; -} SignIdentity_challenge_hidden_t; - -typedef struct _SignIdentity { - bool has_identity; - IdentityType identity; - bool has_challenge_hidden; - SignIdentity_challenge_hidden_t challenge_hidden; - bool has_challenge_visual; - char challenge_visual[256]; - bool has_ecdsa_curve_name; - char ecdsa_curve_name[32]; -} SignIdentity; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} SignMessage_message_t; - -typedef struct _SignMessage { - size_t address_n_count; - uint32_t address_n[8]; - SignMessage_message_t message; - bool has_coin_name; - char coin_name[21]; - bool has_script_type; - InputScriptType script_type; -} SignMessage; - -typedef struct _SignTx { - uint32_t outputs_count; - uint32_t inputs_count; - bool has_coin_name; - char coin_name[21]; - bool has_version; - uint32_t version; - bool has_lock_time; - uint32_t lock_time; -} SignTx; - -typedef struct { - size_t size; - uint8_t bytes[33]; -} SignedIdentity_public_key_t; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} SignedIdentity_signature_t; - -typedef struct _SignedIdentity { - bool has_address; - char address[60]; - bool has_public_key; - SignedIdentity_public_key_t public_key; - bool has_signature; - SignedIdentity_signature_t signature; -} SignedIdentity; - -typedef struct _Success { - bool has_message; - char message[256]; -} Success; - -typedef struct _TxAck { - bool has_tx; - TransactionType tx; -} TxAck; - -typedef struct _TxRequest { - bool has_request_type; - RequestType request_type; - bool has_details; - TxRequestDetailsType details; - bool has_serialized; - TxRequestSerializedType serialized; -} TxRequest; - -typedef struct { - size_t size; - uint8_t bytes[65]; -} VerifyMessage_signature_t; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} VerifyMessage_message_t; - -typedef struct _VerifyMessage { - bool has_address; - char address[60]; - bool has_signature; - VerifyMessage_signature_t signature; - bool has_message; - VerifyMessage_message_t message; - bool has_coin_name; - char coin_name[21]; -} VerifyMessage; - -typedef struct _WordAck { - char word[12]; -} WordAck; - -typedef struct _WordRequest { - bool has_type; - WordRequestType type; -} WordRequest; - -/* Default values for struct fields */ -extern const char GetPublicKey_coin_name_default[21]; -extern const char GetAddress_coin_name_default[21]; -extern const InputScriptType GetAddress_script_type_default; -extern const char LoadDevice_language_default[17]; -extern const uint32_t ResetDevice_strength_default; -extern const char ResetDevice_language_default[17]; -extern const char RecoveryDevice_language_default[17]; -extern const char SignMessage_coin_name_default[21]; -extern const InputScriptType SignMessage_script_type_default; -extern const char VerifyMessage_coin_name_default[21]; -extern const char SignTx_coin_name_default[21]; -extern const uint32_t SignTx_version_default; -extern const uint32_t SignTx_lock_time_default; - -/* Initializer values for message structs */ -#define Initialize_init_default {0} -#define GetFeatures_init_default {0} -#define Features_init_default {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default, CoinType_init_default}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define ClearSession_init_default {0} -#define ApplySettings_init_default {false, "", false, "", false, 0, false, {0, {0}}} -#define ApplyFlags_init_default {false, 0} -#define ChangePin_init_default {false, 0} -#define Ping_init_default {false, "", false, 0, false, 0, false, 0} -#define Success_init_default {false, ""} -#define Failure_init_default {false, (FailureType)0, false, ""} -#define ButtonRequest_init_default {false, (ButtonRequestType)0, false, ""} -#define ButtonAck_init_default {0} -#define PinMatrixRequest_init_default {false, (PinMatrixRequestType)0} -#define PinMatrixAck_init_default {""} -#define Cancel_init_default {0} -#define PassphraseRequest_init_default {0} -#define PassphraseAck_init_default {""} -#define GetEntropy_init_default {0} -#define Entropy_init_default {{0, {0}}} -#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, "Bitcoin"} -#define PublicKey_init_default {HDNodeType_init_default, false, ""} -#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default, false, InputScriptType_SPENDADDRESS} -#define EthereumGetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} -#define Address_init_default {""} -#define EthereumAddress_init_default {{0, {0}}} -#define WipeDevice_init_default {0} -#define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0, false, 0} -#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, "", false, 0, false, 0} -#define BackupDevice_init_default {0} -#define EntropyRequest_init_default {0} -#define EntropyAck_init_default {false, {0, {0}}} -#define RecoveryDevice_init_default {false, 0, false, 0, false, 0, false, "english", false, "", false, 0, false, 0, false, 0, false, 0} -#define WordRequest_init_default {false, (WordRequestType)0} -#define WordAck_init_default {""} -#define SignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "Bitcoin", false, InputScriptType_SPENDADDRESS} -#define VerifyMessage_init_default {false, "", false, {0, {0}}, false, {0, {0}}, false, "Bitcoin"} -#define MessageSignature_init_default {false, "", false, {0, {0}}} -#define CipherKeyValue_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} -#define CipheredKeyValue_init_default {false, {0, {0}}} -#define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u} -#define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default} -#define TxAck_init_default {false, TransactionType_init_default} -#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} -#define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} -#define EthereumTxAck_init_default {false, {0, {0}}} -#define EthereumSignMessage_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}} -#define EthereumVerifyMessage_init_default {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define EthereumMessageSignature_init_default {false, {0, {0}}, false, {0, {0}}} -#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} -#define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}} -#define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""} -#define ECDHSessionKey_init_default {false, {0, {0}}} -#define SetU2FCounter_init_default {false, 0} -#define DebugLinkDecision_init_default {0} -#define DebugLinkGetState_init_default {0} -#define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0} -#define DebugLinkStop_init_default {0} -#define DebugLinkLog_init_default {false, 0, false, "", false, ""} -#define DebugLinkMemoryRead_init_default {false, 0, false, 0} -#define DebugLinkMemory_init_default {false, {0, {0}}} -#define DebugLinkMemoryWrite_init_default {false, 0, false, {0, {0}}, false, 0} -#define DebugLinkFlashErase_init_default {false, 0} -#define Initialize_init_zero {0} -#define GetFeatures_init_zero {0} -#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} -#define ClearSession_init_zero {0} -#define ApplySettings_init_zero {false, "", false, "", false, 0, false, {0, {0}}} -#define ApplyFlags_init_zero {false, 0} -#define ChangePin_init_zero {false, 0} -#define Ping_init_zero {false, "", false, 0, false, 0, false, 0} -#define Success_init_zero {false, ""} -#define Failure_init_zero {false, (FailureType)0, false, ""} -#define ButtonRequest_init_zero {false, (ButtonRequestType)0, false, ""} -#define ButtonAck_init_zero {0} -#define PinMatrixRequest_init_zero {false, (PinMatrixRequestType)0} -#define PinMatrixAck_init_zero {""} -#define Cancel_init_zero {0} -#define PassphraseRequest_init_zero {0} -#define PassphraseAck_init_zero {""} -#define GetEntropy_init_zero {0} -#define Entropy_init_zero {{0, {0}}} -#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, ""} -#define PublicKey_init_zero {HDNodeType_init_zero, false, ""} -#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero, false, (InputScriptType)0} -#define EthereumGetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0} -#define Address_init_zero {""} -#define EthereumAddress_init_zero {{0, {0}}} -#define WipeDevice_init_zero {0} -#define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0, false, 0} -#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0} -#define BackupDevice_init_zero {0} -#define EntropyRequest_init_zero {0} -#define EntropyAck_init_zero {false, {0, {0}}} -#define RecoveryDevice_init_zero {false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0, false, 0, false, 0} -#define WordRequest_init_zero {false, (WordRequestType)0} -#define WordAck_init_zero {""} -#define SignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, false, "", false, (InputScriptType)0} -#define VerifyMessage_init_zero {false, "", false, {0, {0}}, false, {0, {0}}, false, ""} -#define MessageSignature_init_zero {false, "", false, {0, {0}}} -#define CipherKeyValue_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, {0, {0}}, false, 0, false, 0, false, 0, false, {0, {0}}} -#define CipheredKeyValue_init_zero {false, {0, {0}}} -#define SignTx_init_zero {0, 0, false, "", false, 0, false, 0} -#define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero} -#define TxAck_init_zero {false, TransactionType_init_zero} -#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0} -#define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}} -#define EthereumTxAck_init_zero {false, {0, {0}}} -#define EthereumSignMessage_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}} -#define EthereumVerifyMessage_init_zero {false, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define EthereumMessageSignature_init_zero {false, {0, {0}}, false, {0, {0}}} -#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} -#define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}} -#define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""} -#define ECDHSessionKey_init_zero {false, {0, {0}}} -#define SetU2FCounter_init_zero {false, 0} -#define DebugLinkDecision_init_zero {0} -#define DebugLinkGetState_init_zero {0} -#define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0} -#define DebugLinkStop_init_zero {0} -#define DebugLinkLog_init_zero {false, 0, false, "", false, ""} -#define DebugLinkMemoryRead_init_zero {false, 0, false, 0} -#define DebugLinkMemory_init_zero {false, {0, {0}}} -#define DebugLinkMemoryWrite_init_zero {false, 0, false, {0, {0}}, false, 0} -#define DebugLinkFlashErase_init_zero {false, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define Address_address_tag 1 -#define ApplyFlags_flags_tag 1 -#define ApplySettings_language_tag 1 -#define ApplySettings_label_tag 2 -#define ApplySettings_use_passphrase_tag 3 -#define ApplySettings_homescreen_tag 4 -#define ButtonRequest_code_tag 1 -#define ButtonRequest_data_tag 2 -#define ChangePin_remove_tag 1 -#define CipherKeyValue_address_n_tag 1 -#define CipherKeyValue_key_tag 2 -#define CipherKeyValue_value_tag 3 -#define CipherKeyValue_encrypt_tag 4 -#define CipherKeyValue_ask_on_encrypt_tag 5 -#define CipherKeyValue_ask_on_decrypt_tag 6 -#define CipherKeyValue_iv_tag 7 -#define CipheredKeyValue_value_tag 1 -#define DebugLinkDecision_yes_no_tag 1 -#define DebugLinkFlashErase_sector_tag 1 -#define DebugLinkLog_level_tag 1 -#define DebugLinkLog_bucket_tag 2 -#define DebugLinkLog_text_tag 3 -#define DebugLinkMemory_memory_tag 1 -#define DebugLinkMemoryRead_address_tag 1 -#define DebugLinkMemoryRead_length_tag 2 -#define DebugLinkMemoryWrite_address_tag 1 -#define DebugLinkMemoryWrite_memory_tag 2 -#define DebugLinkMemoryWrite_flash_tag 3 -#define DebugLinkState_layout_tag 1 -#define DebugLinkState_pin_tag 2 -#define DebugLinkState_matrix_tag 3 -#define DebugLinkState_mnemonic_tag 4 -#define DebugLinkState_node_tag 5 -#define DebugLinkState_passphrase_protection_tag 6 -#define DebugLinkState_reset_word_tag 7 -#define DebugLinkState_reset_entropy_tag 8 -#define DebugLinkState_recovery_fake_word_tag 9 -#define DebugLinkState_recovery_word_pos_tag 10 -#define ECDHSessionKey_session_key_tag 1 -#define Entropy_entropy_tag 1 -#define EntropyAck_entropy_tag 1 -#define EthereumAddress_address_tag 1 -#define EthereumGetAddress_address_n_tag 1 -#define EthereumGetAddress_show_display_tag 2 -#define EthereumMessageSignature_address_tag 1 -#define EthereumMessageSignature_signature_tag 2 -#define EthereumSignMessage_address_n_tag 1 -#define EthereumSignMessage_message_tag 2 -#define EthereumSignTx_address_n_tag 1 -#define EthereumSignTx_nonce_tag 2 -#define EthereumSignTx_gas_price_tag 3 -#define EthereumSignTx_gas_limit_tag 4 -#define EthereumSignTx_to_tag 5 -#define EthereumSignTx_value_tag 6 -#define EthereumSignTx_data_initial_chunk_tag 7 -#define EthereumSignTx_data_length_tag 8 -#define EthereumSignTx_chain_id_tag 9 -#define EthereumTxAck_data_chunk_tag 1 -#define EthereumTxRequest_data_length_tag 1 -#define EthereumTxRequest_signature_v_tag 2 -#define EthereumTxRequest_signature_r_tag 3 -#define EthereumTxRequest_signature_s_tag 4 -#define EthereumVerifyMessage_address_tag 1 -#define EthereumVerifyMessage_signature_tag 2 -#define EthereumVerifyMessage_message_tag 3 -#define Failure_code_tag 1 -#define Failure_message_tag 2 -#define Features_vendor_tag 1 -#define Features_major_version_tag 2 -#define Features_minor_version_tag 3 -#define Features_patch_version_tag 4 -#define Features_bootloader_mode_tag 5 -#define Features_device_id_tag 6 -#define Features_pin_protection_tag 7 -#define Features_passphrase_protection_tag 8 -#define Features_language_tag 9 -#define Features_label_tag 10 -#define Features_coins_tag 11 -#define Features_initialized_tag 12 -#define Features_revision_tag 13 -#define Features_bootloader_hash_tag 14 -#define Features_imported_tag 15 -#define Features_pin_cached_tag 16 -#define Features_passphrase_cached_tag 17 -#define Features_firmware_present_tag 18 -#define Features_needs_backup_tag 19 -#define Features_flags_tag 20 -#define GetAddress_address_n_tag 1 -#define GetAddress_coin_name_tag 2 -#define GetAddress_show_display_tag 3 -#define GetAddress_multisig_tag 4 -#define GetAddress_script_type_tag 5 -#define GetECDHSessionKey_identity_tag 1 -#define GetECDHSessionKey_peer_public_key_tag 2 -#define GetECDHSessionKey_ecdsa_curve_name_tag 3 -#define GetEntropy_size_tag 1 -#define GetPublicKey_address_n_tag 1 -#define GetPublicKey_ecdsa_curve_name_tag 2 -#define GetPublicKey_show_display_tag 3 -#define GetPublicKey_coin_name_tag 4 -#define LoadDevice_mnemonic_tag 1 -#define LoadDevice_node_tag 2 -#define LoadDevice_pin_tag 3 -#define LoadDevice_passphrase_protection_tag 4 -#define LoadDevice_language_tag 5 -#define LoadDevice_label_tag 6 -#define LoadDevice_skip_checksum_tag 7 -#define LoadDevice_u2f_counter_tag 8 -#define MessageSignature_address_tag 1 -#define MessageSignature_signature_tag 2 -#define PassphraseAck_passphrase_tag 1 -#define PinMatrixAck_pin_tag 1 -#define PinMatrixRequest_type_tag 1 -#define Ping_message_tag 1 -#define Ping_button_protection_tag 2 -#define Ping_pin_protection_tag 3 -#define Ping_passphrase_protection_tag 4 -#define PublicKey_node_tag 1 -#define PublicKey_xpub_tag 2 -#define RecoveryDevice_word_count_tag 1 -#define RecoveryDevice_passphrase_protection_tag 2 -#define RecoveryDevice_pin_protection_tag 3 -#define RecoveryDevice_language_tag 4 -#define RecoveryDevice_label_tag 5 -#define RecoveryDevice_enforce_wordlist_tag 6 -#define RecoveryDevice_type_tag 8 -#define RecoveryDevice_u2f_counter_tag 9 -#define RecoveryDevice_dry_run_tag 10 -#define ResetDevice_display_random_tag 1 -#define ResetDevice_strength_tag 2 -#define ResetDevice_passphrase_protection_tag 3 -#define ResetDevice_pin_protection_tag 4 -#define ResetDevice_language_tag 5 -#define ResetDevice_label_tag 6 -#define ResetDevice_u2f_counter_tag 7 -#define ResetDevice_skip_backup_tag 8 -#define SetU2FCounter_u2f_counter_tag 1 -#define SignIdentity_identity_tag 1 -#define SignIdentity_challenge_hidden_tag 2 -#define SignIdentity_challenge_visual_tag 3 -#define SignIdentity_ecdsa_curve_name_tag 4 -#define SignMessage_address_n_tag 1 -#define SignMessage_message_tag 2 -#define SignMessage_coin_name_tag 3 -#define SignMessage_script_type_tag 4 -#define SignTx_outputs_count_tag 1 -#define SignTx_inputs_count_tag 2 -#define SignTx_coin_name_tag 3 -#define SignTx_version_tag 4 -#define SignTx_lock_time_tag 5 -#define SignedIdentity_address_tag 1 -#define SignedIdentity_public_key_tag 2 -#define SignedIdentity_signature_tag 3 -#define Success_message_tag 1 -#define TxAck_tx_tag 1 -#define TxRequest_request_type_tag 1 -#define TxRequest_details_tag 2 -#define TxRequest_serialized_tag 3 -#define VerifyMessage_address_tag 1 -#define VerifyMessage_signature_tag 2 -#define VerifyMessage_message_tag 3 -#define VerifyMessage_coin_name_tag 4 -#define WordAck_word_tag 1 -#define WordRequest_type_tag 1 - -/* Struct field encoding specification for nanopb */ -extern const pb_field_t Initialize_fields[1]; -extern const pb_field_t GetFeatures_fields[1]; -extern const pb_field_t Features_fields[21]; -extern const pb_field_t ClearSession_fields[1]; -extern const pb_field_t ApplySettings_fields[5]; -extern const pb_field_t ApplyFlags_fields[2]; -extern const pb_field_t ChangePin_fields[2]; -extern const pb_field_t Ping_fields[5]; -extern const pb_field_t Success_fields[2]; -extern const pb_field_t Failure_fields[3]; -extern const pb_field_t ButtonRequest_fields[3]; -extern const pb_field_t ButtonAck_fields[1]; -extern const pb_field_t PinMatrixRequest_fields[2]; -extern const pb_field_t PinMatrixAck_fields[2]; -extern const pb_field_t Cancel_fields[1]; -extern const pb_field_t PassphraseRequest_fields[1]; -extern const pb_field_t PassphraseAck_fields[2]; -extern const pb_field_t GetEntropy_fields[2]; -extern const pb_field_t Entropy_fields[2]; -extern const pb_field_t GetPublicKey_fields[5]; -extern const pb_field_t PublicKey_fields[3]; -extern const pb_field_t GetAddress_fields[6]; -extern const pb_field_t EthereumGetAddress_fields[3]; -extern const pb_field_t Address_fields[2]; -extern const pb_field_t EthereumAddress_fields[2]; -extern const pb_field_t WipeDevice_fields[1]; -extern const pb_field_t LoadDevice_fields[9]; -extern const pb_field_t ResetDevice_fields[9]; -extern const pb_field_t BackupDevice_fields[1]; -extern const pb_field_t EntropyRequest_fields[1]; -extern const pb_field_t EntropyAck_fields[2]; -extern const pb_field_t RecoveryDevice_fields[10]; -extern const pb_field_t WordRequest_fields[2]; -extern const pb_field_t WordAck_fields[2]; -extern const pb_field_t SignMessage_fields[5]; -extern const pb_field_t VerifyMessage_fields[5]; -extern const pb_field_t MessageSignature_fields[3]; -extern const pb_field_t CipherKeyValue_fields[8]; -extern const pb_field_t CipheredKeyValue_fields[2]; -extern const pb_field_t SignTx_fields[6]; -extern const pb_field_t TxRequest_fields[4]; -extern const pb_field_t TxAck_fields[2]; -extern const pb_field_t EthereumSignTx_fields[10]; -extern const pb_field_t EthereumTxRequest_fields[5]; -extern const pb_field_t EthereumTxAck_fields[2]; -extern const pb_field_t EthereumSignMessage_fields[3]; -extern const pb_field_t EthereumVerifyMessage_fields[4]; -extern const pb_field_t EthereumMessageSignature_fields[3]; -extern const pb_field_t SignIdentity_fields[5]; -extern const pb_field_t SignedIdentity_fields[4]; -extern const pb_field_t GetECDHSessionKey_fields[4]; -extern const pb_field_t ECDHSessionKey_fields[2]; -extern const pb_field_t SetU2FCounter_fields[2]; -extern const pb_field_t DebugLinkDecision_fields[2]; -extern const pb_field_t DebugLinkGetState_fields[1]; -extern const pb_field_t DebugLinkState_fields[11]; -extern const pb_field_t DebugLinkStop_fields[1]; -extern const pb_field_t DebugLinkLog_fields[4]; -extern const pb_field_t DebugLinkMemoryRead_fields[3]; -extern const pb_field_t DebugLinkMemory_fields[2]; -extern const pb_field_t DebugLinkMemoryWrite_fields[4]; -extern const pb_field_t DebugLinkFlashErase_fields[2]; - -/* Maximum encoded size of messages (where known) */ -#define Initialize_size 0 -#define GetFeatures_size 0 -#define Features_size (279 + 10*CoinType_size) -#define ClearSession_size 0 -#define ApplySettings_size 1083 -#define ApplyFlags_size 6 -#define ChangePin_size 2 -#define Ping_size 265 -#define Success_size 259 -#define Failure_size 265 -#define ButtonRequest_size 265 -#define ButtonAck_size 0 -#define PinMatrixRequest_size 6 -#define PinMatrixAck_size 12 -#define Cancel_size 0 -#define PassphraseRequest_size 0 -#define PassphraseAck_size 53 -#define GetEntropy_size 6 -#define Entropy_size 1027 -#define GetPublicKey_size 107 -#define PublicKey_size (121 + HDNodeType_size) -#define GetAddress_size (85 + MultisigRedeemScriptType_size) -#define EthereumGetAddress_size 50 -#define Address_size 62 -#define EthereumAddress_size 22 -#define WipeDevice_size 0 -#define LoadDevice_size (326 + HDNodeType_size) -#define ResetDevice_size 74 -#define BackupDevice_size 0 -#define EntropyRequest_size 0 -#define EntropyAck_size 131 -#define RecoveryDevice_size 80 -#define WordRequest_size 6 -#define WordAck_size 14 -#define SignMessage_size 1104 -#define VerifyMessage_size 1179 -#define MessageSignature_size 129 -#define CipherKeyValue_size 1358 -#define CipheredKeyValue_size 1027 -#define SignTx_size 47 -#define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) -#define TxAck_size (6 + TransactionType_size) -#define EthereumSignTx_size 1245 -#define EthereumTxRequest_size 80 -#define EthereumTxAck_size 1027 -#define EthereumSignMessage_size 1075 -#define EthereumVerifyMessage_size 1116 -#define EthereumMessageSignature_size 89 -#define SignIdentity_size (558 + IdentityType_size) -#define SignedIdentity_size 164 -#define GetECDHSessionKey_size (107 + IdentityType_size) -#define ECDHSessionKey_size 67 -#define SetU2FCounter_size 6 -#define DebugLinkDecision_size 2 -#define DebugLinkGetState_size 0 -#define DebugLinkState_size (1468 + HDNodeType_size) -#define DebugLinkStop_size 0 -#define DebugLinkLog_size 300 -#define DebugLinkMemoryRead_size 12 -#define DebugLinkMemory_size 1027 -#define DebugLinkMemoryWrite_size 1035 -#define DebugLinkFlashErase_size 6 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/firmware/protob/messages_map.h b/firmware/protob/messages_map.h deleted file mode 100644 index 958dfef57b..0000000000 --- a/firmware/protob/messages_map.h +++ /dev/null @@ -1,90 +0,0 @@ - // This file is automatically generated by messages_map.py -- DO NOT EDIT! - - // in messages - - { 'n', 'i', MessageType_MessageType_Initialize, Initialize_fields, (void (*)(void *)) fsm_msgInitialize }, - { 'n', 'i', MessageType_MessageType_Ping, Ping_fields, (void (*)(void *)) fsm_msgPing }, - { 'n', 'i', MessageType_MessageType_ChangePin, ChangePin_fields, (void (*)(void *)) fsm_msgChangePin }, - { 'n', 'i', MessageType_MessageType_WipeDevice, WipeDevice_fields, (void (*)(void *)) fsm_msgWipeDevice }, - // Message FirmwareErase is used in bootloader mode only - // Message FirmwareUpload is used in bootloader mode only - { 'n', 'i', MessageType_MessageType_GetEntropy, GetEntropy_fields, (void (*)(void *)) fsm_msgGetEntropy }, - { 'n', 'i', MessageType_MessageType_GetPublicKey, GetPublicKey_fields, (void (*)(void *)) fsm_msgGetPublicKey }, - { 'n', 'i', MessageType_MessageType_LoadDevice, LoadDevice_fields, (void (*)(void *)) fsm_msgLoadDevice }, - { 'n', 'i', MessageType_MessageType_ResetDevice, ResetDevice_fields, (void (*)(void *)) fsm_msgResetDevice }, - { 'n', 'i', MessageType_MessageType_SignTx, SignTx_fields, (void (*)(void *)) fsm_msgSignTx }, - // Message SimpleSignTx is deprecated - // Message PinMatrixAck is used in tiny mode - { 'n', 'i', MessageType_MessageType_Cancel, Cancel_fields, (void (*)(void *)) fsm_msgCancel }, - { 'n', 'i', MessageType_MessageType_TxAck, TxAck_fields, (void (*)(void *)) fsm_msgTxAck }, - { 'n', 'i', MessageType_MessageType_CipherKeyValue, CipherKeyValue_fields, (void (*)(void *)) fsm_msgCipherKeyValue }, - { 'n', 'i', MessageType_MessageType_ClearSession, ClearSession_fields, (void (*)(void *)) fsm_msgClearSession }, - { 'n', 'i', MessageType_MessageType_ApplySettings, ApplySettings_fields, (void (*)(void *)) fsm_msgApplySettings }, - // Message ButtonAck is used in tiny mode - { 'n', 'i', MessageType_MessageType_ApplyFlags, ApplyFlags_fields, (void (*)(void *)) fsm_msgApplyFlags }, - { 'n', 'i', MessageType_MessageType_GetAddress, GetAddress_fields, (void (*)(void *)) fsm_msgGetAddress }, - // Message SelfTest is used in bootloader mode only - { 'n', 'i', MessageType_MessageType_BackupDevice, BackupDevice_fields, (void (*)(void *)) fsm_msgBackupDevice }, - { 'n', 'i', MessageType_MessageType_EntropyAck, EntropyAck_fields, (void (*)(void *)) fsm_msgEntropyAck }, - { 'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *)) fsm_msgSignMessage }, - { 'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *)) fsm_msgVerifyMessage }, - // Message PassphraseAck is used in tiny mode - // Message EstimateTxSize is deprecated - { 'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *)) fsm_msgRecoveryDevice }, - { 'n', 'i', MessageType_MessageType_WordAck, WordAck_fields, (void (*)(void *)) fsm_msgWordAck }, - // Message EncryptMessage is deprecated - // Message DecryptMessage is deprecated - { 'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *)) fsm_msgSignIdentity }, - { 'n', 'i', MessageType_MessageType_GetFeatures, GetFeatures_fields, (void (*)(void *)) fsm_msgGetFeatures }, - { 'n', 'i', MessageType_MessageType_EthereumGetAddress, EthereumGetAddress_fields, (void (*)(void *)) fsm_msgEthereumGetAddress }, - { 'n', 'i', MessageType_MessageType_EthereumSignTx, EthereumSignTx_fields, (void (*)(void *)) fsm_msgEthereumSignTx }, - { 'n', 'i', MessageType_MessageType_EthereumTxAck, EthereumTxAck_fields, (void (*)(void *)) fsm_msgEthereumTxAck }, - { 'n', 'i', MessageType_MessageType_GetECDHSessionKey, GetECDHSessionKey_fields, (void (*)(void *)) fsm_msgGetECDHSessionKey }, - { 'n', 'i', MessageType_MessageType_SetU2FCounter, SetU2FCounter_fields, (void (*)(void *)) fsm_msgSetU2FCounter }, - { 'n', 'i', MessageType_MessageType_EthereumSignMessage, EthereumSignMessage_fields, (void (*)(void *)) fsm_msgEthereumSignMessage }, - { 'n', 'i', MessageType_MessageType_EthereumVerifyMessage, EthereumVerifyMessage_fields, (void (*)(void *)) fsm_msgEthereumVerifyMessage }, - - // out messages - - { 'n', 'o', MessageType_MessageType_Success, Success_fields, 0 }, - { 'n', 'o', MessageType_MessageType_Failure, Failure_fields, 0 }, - // Message FirmwareRequest is used in bootloader mode only - { 'n', 'o', MessageType_MessageType_Entropy, Entropy_fields, 0 }, - { 'n', 'o', MessageType_MessageType_PublicKey, PublicKey_fields, 0 }, - { 'n', 'o', MessageType_MessageType_Features, Features_fields, 0 }, - { 'n', 'o', MessageType_MessageType_PinMatrixRequest, PinMatrixRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_TxRequest, TxRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_ButtonRequest, ButtonRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_Address, Address_fields, 0 }, - { 'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0 }, - { 'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0 }, - // Message TxSize is deprecated - { 'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_CipheredKeyValue, CipheredKeyValue_fields, 0 }, - // Message EncryptedMessage is deprecated - // Message DecryptedMessage is deprecated - { 'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0 }, - { 'n', 'o', MessageType_MessageType_EthereumAddress, EthereumAddress_fields, 0 }, - { 'n', 'o', MessageType_MessageType_EthereumTxRequest, EthereumTxRequest_fields, 0 }, - { 'n', 'o', MessageType_MessageType_ECDHSessionKey, ECDHSessionKey_fields, 0 }, - { 'n', 'o', MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature_fields, 0 }, - -#if DEBUG_LINK - - // debug in messages - - // Message DebugLinkDecision is used in tiny mode - { 'd', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *)) fsm_msgDebugLinkGetState }, - { 'd', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *)) fsm_msgDebugLinkStop }, - { 'd', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryRead }, - { 'd', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *)) fsm_msgDebugLinkMemoryWrite }, - { 'd', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *)) fsm_msgDebugLinkFlashErase }, - - // debug out messages - - { 'd', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0 }, - { 'd', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0 }, - { 'd', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0 }, - -#endif diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h deleted file mode 100644 index dedcfe46af..0000000000 --- a/firmware/protob/pb.h +++ /dev/null @@ -1,519 +0,0 @@ -/* Common parts of the nanopb library. Most of these are quite low-level - * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. - */ - -#ifndef _PB_H_ -#define _PB_H_ - -/***************************************************************** - * Nanopb compilation time options. You can change these here by * - * uncommenting the lines, or on the compiler command line. * - *****************************************************************/ - -/* Enable support for dynamically allocated fields */ -/* #define PB_ENABLE_MALLOC 1 */ - -/* Define this if your CPU architecture is big endian, i.e. it - * stores the most-significant byte first. */ -/* #define __BIG_ENDIAN__ 1 */ - -/* Increase the number of required fields that are tracked. - * A compiler warning will tell if you need this. */ -/* #define PB_MAX_REQUIRED_FIELDS 256 */ - -/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ -/* #define PB_FIELD_16BIT 1 */ - -/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ -/* #define PB_FIELD_32BIT 1 */ - -/* Disable support for error messages in order to save some code space. */ -/* #define PB_NO_ERRMSG 1 */ - -/* Disable support for custom streams (support only memory buffers). */ -/* #define PB_BUFFER_ONLY 1 */ - -/* Switch back to the old-style callback function signature. - * This was the default until nanopb-0.2.1. */ -/* #define PB_OLD_CALLBACK_STYLE */ - - -/****************************************************************** - * You usually don't need to change anything below this line. * - * Feel free to look around and use the defined macros, though. * - ******************************************************************/ - - -/* Version of the nanopb library. Just in case you want to check it in - * your own program. */ -#define NANOPB_VERSION nanopb-0.2.9.3 - -/* Include all the system headers needed by nanopb. You will need the - * definitions of the following: - * - strlen, memcpy, memset functions - * - [u]int8_t, [u]int16_t, [u]int32_t, [u]int64_t - * - size_t - * - bool - * - * If you don't have the standard header files, you can instead provide - * a custom header that defines or includes all this. In that case, - * define PB_SYSTEM_HEADER to the path of this file. - */ -#ifdef PB_SYSTEM_HEADER -#include PB_SYSTEM_HEADER -#else -#include -#include -#include -#include - -#ifdef PB_ENABLE_MALLOC -#include -#endif -#endif - -/* Macro for defining packed structures (compiler dependent). - * This just reduces memory requirements, but is not required. - */ -#if defined(__GNUC__) || defined(__clang__) - /* For GCC and clang */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed __attribute__((packed)) -#elif defined(__ICCARM__) || defined(__CC_ARM) - /* For IAR ARM and Keil MDK-ARM compilers */ -# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") -# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") -# define pb_packed -#elif defined(_MSC_VER) && (_MSC_VER >= 1500) - /* For Microsoft Visual C++ */ -# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) -# define PB_PACKED_STRUCT_END __pragma(pack(pop)) -# define pb_packed -#else - /* Unknown compiler */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed -#endif - -/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ -#ifndef UNUSED -#define UNUSED(x) (void)(x) -#endif - -/* Compile-time assertion, used for checking compatible compilation options. - * If this does not work properly on your compiler, use #define STATIC_ASSERT - * to disable it. - * - * But before doing that, check carefully the error message / place where it - * comes from to see if the error has a real cause. Unfortunately the error - * message is not always very clear to read, but you can see the reason better - * in the place where the STATIC_ASSERT macro was called. - */ -#ifndef STATIC_ASSERT -#define STATIC_ASSERT(COND,MSG) typedef char STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; -#define STATIC_ASSERT_MSG(MSG, LINE, COUNTER) STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) -#define STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) static_assertion_##MSG##LINE##COUNTER -#endif - -/* Number of required fields to keep track of. */ -#ifndef PB_MAX_REQUIRED_FIELDS -#define PB_MAX_REQUIRED_FIELDS 64 -#endif - -#if PB_MAX_REQUIRED_FIELDS < 64 -#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). -#endif - -/* List of possible field types. These are used in the autogenerated code. - * Least-significant 4 bits tell the scalar type - * Most-significant 4 bits specify repeated/required/packed etc. - */ - -typedef uint8_t pb_type_t; - -/**** Field data types ****/ - -/* Numeric types */ -#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */ -#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */ -#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */ -#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */ -#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */ - -/* Marker for last packable field type. */ -#define PB_LTYPE_LAST_PACKABLE 0x04 - -/* Byte array with pre-allocated buffer. - * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ -#define PB_LTYPE_BYTES 0x05 - -/* String with pre-allocated buffer. - * data_size is the maximum length. */ -#define PB_LTYPE_STRING 0x06 - -/* Submessage - * submsg_fields is pointer to field descriptions */ -#define PB_LTYPE_SUBMESSAGE 0x07 - -/* Extension pseudo-field - * The field contains a pointer to pb_extension_t */ -#define PB_LTYPE_EXTENSION 0x08 - -/* Number of declared LTYPES */ -#define PB_LTYPES_COUNT 9 -#define PB_LTYPE_MASK 0x0F - -/**** Field repetition rules ****/ - -#define PB_HTYPE_REQUIRED 0x00 -#define PB_HTYPE_OPTIONAL 0x10 -#define PB_HTYPE_REPEATED 0x20 -#define PB_HTYPE_MASK 0x30 - -/**** Field allocation types ****/ - -#define PB_ATYPE_STATIC 0x00 -#define PB_ATYPE_POINTER 0x80 -#define PB_ATYPE_CALLBACK 0x40 -#define PB_ATYPE_MASK 0xC0 - -#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) -#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) -#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) - -/* Data type used for storing sizes of struct fields - * and array counts. - */ -#if defined(PB_FIELD_32BIT) - typedef uint32_t pb_size_t; - typedef int32_t pb_ssize_t; -#elif defined(PB_FIELD_16BIT) - typedef uint16_t pb_size_t; - typedef int16_t pb_ssize_t; -#else - typedef uint8_t pb_size_t; - typedef int8_t pb_ssize_t; -#endif - -/* This structure is used in auto-generated constants - * to specify struct fields. - * You can change field sizes if you need structures - * larger than 256 bytes or field tags larger than 256. - * The compiler should complain if your .proto has such - * structures. Fix that by defining PB_FIELD_16BIT or - * PB_FIELD_32BIT. - */ -PB_PACKED_STRUCT_START -typedef struct _pb_field_t pb_field_t; -struct _pb_field_t { - pb_size_t tag; - pb_type_t type; - pb_size_t data_offset; /* Offset of field data, relative to previous field. */ - pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ - pb_size_t data_size; /* Data size in bytes for a single item */ - pb_size_t array_size; /* Maximum number of entries in array */ - - /* Field definitions for submessage - * OR default value for all other non-array, non-callback types - * If null, then field will zeroed. */ - const void *ptr; -} pb_packed; -PB_PACKED_STRUCT_END - -/* Make sure that the standard integer types are of the expected sizes. - * All kinds of things may break otherwise.. atleast all fixed* types. - * - * If you get errors here, it probably means that your stdint.h is not - * correct for your platform. - */ -STATIC_ASSERT(sizeof(int8_t) == 1, INT8_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint8_t) == 1, UINT8_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int16_t) == 2, INT16_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint16_t) == 2, UINT16_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int32_t) == 4, INT32_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint32_t) == 4, UINT32_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(int64_t) == 8, INT64_T_WRONG_SIZE) -STATIC_ASSERT(sizeof(uint64_t) == 8, UINT64_T_WRONG_SIZE) - -/* This structure is used for 'bytes' arrays. - * It has the number of bytes in the beginning, and after that an array. - * Note that actual structs used will have a different length of bytes array. - */ -#define PB_BYTES_ARRAY_T(n) struct { size_t size; uint8_t bytes[n]; } -#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) - -struct _pb_bytes_array_t { - size_t size; - uint8_t bytes[1]; -}; -typedef struct _pb_bytes_array_t pb_bytes_array_t; - -/* This structure is used for giving the callback function. - * It is stored in the message structure and filled in by the method that - * calls pb_decode. - * - * The decoding callback will be given a limited-length stream - * If the wire type was string, the length is the length of the string. - * If the wire type was a varint/fixed32/fixed64, the length is the length - * of the actual value. - * The function may be called multiple times (especially for repeated types, - * but also otherwise if the message happens to contain the field multiple - * times.) - * - * The encoding callback will receive the actual output stream. - * It should write all the data in one call, including the field tag and - * wire type. It can write multiple fields. - * - * The callback can be null if you want to skip a field. - */ -typedef struct _pb_istream_t pb_istream_t; -typedef struct _pb_ostream_t pb_ostream_t; -typedef struct _pb_callback_t pb_callback_t; -struct _pb_callback_t { -#ifdef PB_OLD_CALLBACK_STYLE - /* Deprecated since nanopb-0.2.1 */ - union { - bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); - bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); - } funcs; -#else - /* New function signature, which allows modifying arg contents in callback. */ - union { - bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); - bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); - } funcs; -#endif - - /* Free arg for use by callback */ - void *arg; -}; - -/* Wire types. Library user needs these only in encoder callbacks. */ -typedef enum { - PB_WT_VARINT = 0, - PB_WT_64BIT = 1, - PB_WT_STRING = 2, - PB_WT_32BIT = 5 -} pb_wire_type_t; - -/* Structure for defining the handling of unknown/extension fields. - * Usually the pb_extension_type_t structure is automatically generated, - * while the pb_extension_t structure is created by the user. However, - * if you want to catch all unknown fields, you can also create a custom - * pb_extension_type_t with your own callback. - */ -typedef struct _pb_extension_type_t pb_extension_type_t; -typedef struct _pb_extension_t pb_extension_t; -struct _pb_extension_type_t { - /* Called for each unknown field in the message. - * If you handle the field, read off all of its data and return true. - * If you do not handle the field, do not read anything and return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, - uint32_t tag, pb_wire_type_t wire_type); - - /* Called once after all regular fields have been encoded. - * If you have something to write, do so and return true. - * If you do not have anything to write, just return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); - - /* Free field for use by the callback. */ - const void *arg; -}; - -struct _pb_extension_t { - /* Type describing the extension field. Usually you'll initialize - * this to a pointer to the automatically generated structure. */ - const pb_extension_type_t *type; - - /* Destination for the decoded data. This must match the datatype - * of the extension field. */ - void *dest; - - /* Pointer to the next extension handler, or NULL. - * If this extension does not match a field, the next handler is - * automatically called. */ - pb_extension_t *next; - - /* The decoder sets this to true if the extension was found. - * Ignored for encoding. */ - bool found; -}; - -/* Memory allocation functions to use. You can define pb_realloc and - * pb_free to custom functions if you want. */ -#ifdef PB_ENABLE_MALLOC -# ifndef pb_realloc -# define pb_realloc(ptr, size) realloc(ptr, size) -# endif -# ifndef pb_free -# define pb_free(ptr) free(ptr) -# endif -#endif - -/* These macros are used to declare pb_field_t's in the constant array. */ -/* Size of a structure member, in bytes. */ -#define pb_membersize(st, m) (sizeof ((st*)0)->m) -/* Number of entries in an array. */ -#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) -/* Delta from start of one member to the start of another member. */ -#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) -/* Marks the end of the field list */ -#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} - -/* Macros for filling in the data_offset field */ -/* data_offset for first field in a message */ -#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) -/* data_offset for subsequent fields */ -#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) -/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ -#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ - ? PB_DATAOFFSET_FIRST(st, m1, m2) \ - : PB_DATAOFFSET_OTHER(st, m1, m2)) - -/* Required fields are the simplest. They just have delta (padding) from - * previous field end, and the size of the field. Pointer is used for - * submessages and default values. - */ -#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -/* Optional fields add the delta to the has_ variable. */ -#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ - fd, \ - pb_delta(st, has_ ## m, m), \ - pb_membersize(st, m), 0, ptr} - -/* Repeated fields have a _count field and also the maximum number of entries. */ -#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ - fd, \ - pb_delta(st, m ## _count, m), \ - pb_membersize(st, m[0]), \ - pb_arraysize(st, m), ptr} - -/* Allocated fields carry the size of the actual data, not the pointer */ -#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m[0]), 0, ptr} - -/* Optional fields don't need a has_ variable, as information would be redundant */ -#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m[0]), 0, ptr} - -/* Repeated fields have a _count field and a pointer to array of pointers */ -#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ - fd, pb_delta(st, m ## _count, m), \ - pb_membersize(st, m[0]), 0, ptr} - -/* Callbacks are much like required fields except with special datatype. */ -#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ - fd, 0, pb_membersize(st, m), 0, ptr} - -/* Optional extensions don't have the has_ field, as that would be redundant. */ -#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ - 0, \ - 0, \ - pb_membersize(st, m), 0, ptr} - -#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ - {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ - 0, 0, pb_membersize(st, m), 0, ptr} - -/* The mapping from protobuf types to LTYPEs is done using these macros. */ -#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT -#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES -#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT -#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE -#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING -#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION - -/* This is the actual macro used in field descriptions. - * It takes these arguments: - * - Field tag number - * - Field type: BOOL, BYTES, DOUBLE, ENUM, FIXED32, FIXED64, - * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 - * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION - * - Field rules: REQUIRED, OPTIONAL or REPEATED - * - Allocation: STATIC or CALLBACK - * - Message name - * - Field name - * - Previous field name (or field name again for first field) - * - Pointer to default value or submsg fields. - */ - -#define PB_FIELD(tag, type, rules, allocation, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ - PB_DATAOFFSET_CHOOSE(message, field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) - -/* This is a new version of the macro used by nanopb generator from - * version 0.2.3 onwards. It avoids the use of a ternary expression in - * the initialization, which confused some compilers. - * - * - Placement: FIRST or OTHER, depending on if this is the first field in structure. - * - */ -#define PB_FIELD2(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ - PB_ ## rules ## _ ## allocation(tag, message, field, \ - PB_DATAOFFSET_ ## placement(message, field, prevfield), \ - PB_LTYPE_MAP_ ## type, ptr) - - -/* These macros are used for giving out error messages. - * They are mostly a debugging aid; the main error information - * is the true/false return value from functions. - * Some code space can be saved by disabling the error - * messages if not used. - */ -#ifdef PB_NO_ERRMSG -#define PB_RETURN_ERROR(stream,msg) \ - do {\ - UNUSED(stream); \ - return false; \ - } while(0) -#define PB_GET_ERROR(stream) "(errmsg disabled)" -#else -#define PB_RETURN_ERROR(stream,msg) \ - do {\ - if ((stream)->errmsg == NULL) \ - (stream)->errmsg = (msg); \ - return false; \ - } while(0) -#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") -#endif - -#endif diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h new file mode 120000 index 0000000000..835188c421 --- /dev/null +++ b/firmware/protob/pb.h @@ -0,0 +1 @@ +../../vendor/nanopb/pb.h \ No newline at end of file diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c deleted file mode 100644 index 307bbc4597..0000000000 --- a/firmware/protob/pb_decode.c +++ /dev/null @@ -1,1267 +0,0 @@ -/* pb_decode.c -- decode a protobuf using minimal resources - * - * 2011 Petteri Aimonen - */ - -/* Use the GCC warn_unused_result attribute to check that all return values - * are propagated correctly. On other compilers and gcc before 3.4.0 just - * ignore the annotation. - */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn -#else - #define checkreturn __attribute__((warn_unused_result)) -#endif - -#include "pb.h" -#include "pb_decode.h" - -/************************************** - * Declarations internal to this file * - **************************************/ - -/* Iterator for pb_field_t list */ -typedef struct { - const pb_field_t *start; /* Start of the pb_field_t array */ - const pb_field_t *pos; /* Current position of the iterator */ - unsigned field_index; /* Zero-based index of the field. */ - unsigned required_field_index; /* Zero-based index that counts only the required fields */ - void *dest_struct; /* Pointer to the destination structure to decode to */ - void *pData; /* Pointer where to store current field value */ - void *pSize; /* Pointer where to store the size of current array field */ -} pb_field_iterator_t; - -typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; - -static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count); -static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size); -static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct); -static bool pb_field_next(pb_field_iterator_t *iter); -static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag); -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension); -static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter); -static bool checkreturn find_extension_field(pb_field_iterator_t *iter); -static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); -static bool checkreturn pb_skip_varint(pb_istream_t *stream); -static bool checkreturn pb_skip_string(pb_istream_t *stream); - -#ifdef PB_ENABLE_MALLOC -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); -static void pb_release_single_field(const pb_field_iterator_t *iter); -#endif - -/* --- Function pointers to field decoders --- - * Order in the array must match pb_action_t LTYPE numbering. - */ -static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { - &pb_dec_varint, - &pb_dec_uvarint, - &pb_dec_svarint, - &pb_dec_fixed32, - &pb_dec_fixed64, - - &pb_dec_bytes, - &pb_dec_string, - &pb_dec_submessage, - NULL /* extensions */ -}; - -/******************************* - * pb_istream_t implementation * - *******************************/ - -static bool checkreturn buf_read(pb_istream_t *stream, uint8_t *buf, size_t count) -{ - uint8_t *source = (uint8_t*)stream->state; - stream->state = source + count; - - if (buf != NULL) - { - while (count--) - *buf++ = *source++; - } - - return true; -} - -bool checkreturn pb_read(pb_istream_t *stream, uint8_t *buf, size_t count) -{ -#ifndef PB_BUFFER_ONLY - if (buf == NULL && stream->callback != buf_read) - { - /* Skip input bytes */ - uint8_t tmp[16]; - while (count > 16) - { - if (!pb_read(stream, tmp, 16)) - return false; - - count -= 16; - } - - return pb_read(stream, tmp, count); - } -#endif - - if (stream->bytes_left < count) - PB_RETURN_ERROR(stream, "end-of-stream"); - -#ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#else - if (!buf_read(stream, buf, count)) - return false; -#endif - - stream->bytes_left -= count; - return true; -} - -/* Read a single byte from input stream. buf may not be NULL. - * This is an optimization for the varint decoding. */ -static bool checkreturn pb_readbyte(pb_istream_t *stream, uint8_t *buf) -{ - if (stream->bytes_left == 0) - PB_RETURN_ERROR(stream, "end-of-stream"); - -#ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, 1)) - PB_RETURN_ERROR(stream, "io error"); -#else - *buf = *(uint8_t*)stream->state; - stream->state = (uint8_t*)stream->state + 1; -#endif - - stream->bytes_left--; - - return true; -} - -pb_istream_t pb_istream_from_buffer(const uint8_t *buf, size_t bufsize) -{ - pb_istream_t stream; -#ifdef PB_BUFFER_ONLY - stream.callback = NULL; -#else - stream.callback = &buf_read; -#endif - stream.state = buf; - stream.bytes_left = bufsize; -#ifndef PB_NO_ERRMSG - stream.errmsg = NULL; -#endif - return stream; -} - -/******************** - * Helper functions * - ********************/ - -static bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) -{ - uint8_t byte; - uint32_t result; - - if (!pb_readbyte(stream, &byte)) - return false; - - if ((byte & 0x80) == 0) - { - /* Quick case, 1 byte value */ - result = byte; - } - else - { - /* Multibyte case */ - uint8_t bitpos = 7; - result = byte & 0x7F; - - do - { - if (bitpos >= 32) - PB_RETURN_ERROR(stream, "varint overflow"); - - if (!pb_readbyte(stream, &byte)) - return false; - - result |= (uint32_t)(byte & 0x7F) << bitpos; - bitpos = (uint8_t)(bitpos + 7); - } while (byte & 0x80); - } - - *dest = result; - return true; -} - -bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) -{ - uint8_t byte; - uint8_t bitpos = 0; - uint64_t result = 0; - - do - { - if (bitpos >= 64) - PB_RETURN_ERROR(stream, "varint overflow"); - - if (!pb_readbyte(stream, &byte)) - return false; - - result |= (uint64_t)(byte & 0x7F) << bitpos; - bitpos = (uint8_t)(bitpos + 7); - } while (byte & 0x80); - - *dest = result; - return true; -} - -bool checkreturn pb_skip_varint(pb_istream_t *stream) -{ - uint8_t byte; - do - { - if (!pb_read(stream, &byte, 1)) - return false; - } while (byte & 0x80); - return true; -} - -bool checkreturn pb_skip_string(pb_istream_t *stream) -{ - uint32_t length; - if (!pb_decode_varint32(stream, &length)) - return false; - - return pb_read(stream, NULL, length); -} - -bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) -{ - uint32_t temp; - *eof = false; - *wire_type = (pb_wire_type_t) 0; - *tag = 0; - - if (!pb_decode_varint32(stream, &temp)) - { - if (stream->bytes_left == 0) - *eof = true; - - return false; - } - - if (temp == 0) - { - *eof = true; /* Special feature: allow 0-terminated messages. */ - return false; - } - - *tag = temp >> 3; - *wire_type = (pb_wire_type_t)(temp & 7); - return true; -} - -bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) -{ - switch (wire_type) - { - case PB_WT_VARINT: return pb_skip_varint(stream); - case PB_WT_64BIT: return pb_read(stream, NULL, 8); - case PB_WT_STRING: return pb_skip_string(stream); - case PB_WT_32BIT: return pb_read(stream, NULL, 4); - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } -} - -/* Read a raw value to buffer, for the purpose of passing it to callback as - * a substream. Size is maximum size on call, and actual size on return. - */ -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, uint8_t *buf, size_t *size) -{ - size_t max_size = *size; - switch (wire_type) - { - case PB_WT_VARINT: - *size = 0; - do - { - (*size)++; - if (*size > max_size) return false; - if (!pb_read(stream, buf, 1)) return false; - } while (*buf++ & 0x80); - return true; - - case PB_WT_64BIT: - *size = 8; - return pb_read(stream, buf, 8); - - case PB_WT_32BIT: - *size = 4; - return pb_read(stream, buf, 4); - - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } -} - -/* Decode string length from stream and return a substream with limited length. - * Remember to close the substream using pb_close_string_substream(). - */ -bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - uint32_t size; - if (!pb_decode_varint32(stream, &size)) - return false; - - *substream = *stream; - if (substream->bytes_left < size) - PB_RETURN_ERROR(stream, "parent stream too short"); - - substream->bytes_left = size; - stream->bytes_left -= size; - return true; -} - -void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - stream->state = substream->state; - -#ifndef PB_NO_ERRMSG - stream->errmsg = substream->errmsg; -#endif -} - -static void pb_field_init(pb_field_iterator_t *iter, const pb_field_t *fields, void *dest_struct) -{ - iter->start = iter->pos = fields; - iter->field_index = 0; - iter->required_field_index = 0; - iter->pData = (char*)dest_struct + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - iter->dest_struct = dest_struct; -} - -static bool pb_field_next(pb_field_iterator_t *iter) -{ - bool notwrapped = true; - size_t prev_size = iter->pos->data_size; - - if (PB_ATYPE(iter->pos->type) == PB_ATYPE_STATIC && - PB_HTYPE(iter->pos->type) == PB_HTYPE_REPEATED) - { - prev_size *= iter->pos->array_size; - } - else if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) - { - prev_size = sizeof(void*); - } - - if (iter->pos->tag == 0) - return false; /* Only happens with empty message types */ - - if (PB_HTYPE(iter->pos->type) == PB_HTYPE_REQUIRED) - iter->required_field_index++; - - iter->pos++; - iter->field_index++; - if (iter->pos->tag == 0) - { - iter->pos = iter->start; - iter->field_index = 0; - iter->required_field_index = 0; - iter->pData = iter->dest_struct; - prev_size = 0; - notwrapped = false; - } - - iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; - iter->pSize = (char*)iter->pData + iter->pos->size_offset; - return notwrapped; -} - -static bool checkreturn pb_field_find(pb_field_iterator_t *iter, uint32_t tag) -{ - unsigned start = iter->field_index; - - do { - if (iter->pos->tag == tag && - PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) - { - return true; - } - (void)pb_field_next(iter); - } while (iter->field_index != start); - - return false; -} - -/************************* - * Decode a single field * - *************************/ - -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) -{ - pb_type_t type; - pb_decoder_t func; - - type = iter->pos->type; - func = PB_DECODERS[PB_LTYPE(type)]; - - switch (PB_HTYPE(type)) - { - case PB_HTYPE_REQUIRED: - return func(stream, iter->pos, iter->pData); - - case PB_HTYPE_OPTIONAL: - *(bool*)iter->pSize = true; - return func(stream, iter->pos, iter->pData); - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array */ - bool status = true; - size_t *size = (size_t*)iter->pSize; - pb_istream_t substream; - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left > 0 && *size < iter->pos->array_size) - { - void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); - if (!func(&substream, iter->pos, pItem)) - { - status = false; - break; - } - (*size)++; - } - pb_close_string_substream(stream, &substream); - - if (substream.bytes_left != 0) - PB_RETURN_ERROR(stream, "array overflow"); - - return status; - } - else - { - /* Repeated field */ - size_t *size = (size_t*)iter->pSize; - void *pItem = (uint8_t*)iter->pData + iter->pos->data_size * (*size); - if (*size >= iter->pos->array_size) - PB_RETURN_ERROR(stream, "array overflow"); - - (*size)++; - return func(stream, iter->pos, pItem); - } - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -#ifdef PB_ENABLE_MALLOC -/* Allocate storage for the field and store the pointer at iter->pData. - * array_size is the number of entries to reserve in an array. - * Zero size is not allowed, use pb_free() for releasing. - */ -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) -{ - void *ptr = *(void**)pData; - - if (data_size == 0 || array_size == 0) - PB_RETURN_ERROR(stream, "invalid size"); - - /* Check for multiplication overflows. - * This code avoids the costly division if the sizes are small enough. - * Multiplication is safe as long as only half of bits are set - * in either multiplicand. - */ - { - const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); - if (data_size >= check_limit || array_size >= check_limit) - { - const size_t size_max = (size_t)-1; - if (size_max / array_size < data_size) - { - PB_RETURN_ERROR(stream, "size too large"); - } - } - } - - /* Allocate new or expand previous allocation */ - /* Note: on failure the old pointer will remain in the structure, - * the message must be freed by caller also on error return. */ - ptr = pb_realloc(ptr, array_size * data_size); - if (ptr == NULL) - PB_RETURN_ERROR(stream, "realloc failed"); - - *(void**)pData = ptr; - return true; -} - -/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ -static void initialize_pointer_field(void *pItem, pb_field_iterator_t *iter) -{ - if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || - PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) - { - *(void**)pItem = NULL; - } - else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) - { - pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); - } -} -#endif - -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) -{ -#ifndef PB_ENABLE_MALLOC - UNUSED(wire_type); - UNUSED(iter); - PB_RETURN_ERROR(stream, "no malloc support"); -#else - pb_type_t type; - pb_decoder_t func; - - type = iter->pos->type; - func = PB_DECODERS[PB_LTYPE(type)]; - - switch (PB_HTYPE(type)) - { - case PB_HTYPE_REQUIRED: - case PB_HTYPE_OPTIONAL: - if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && - *(void**)iter->pData != NULL) - { - /* Duplicate field, have to release the old allocation first. */ - pb_release_single_field(iter); - } - - if (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES) - { - return func(stream, iter->pos, iter->pData); - } - else - { - if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) - return false; - - initialize_pointer_field(*(void**)iter->pData, iter); - return func(stream, iter->pos, *(void**)iter->pData); - } - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array, multiple items come in at once. */ - bool status = true; - size_t *size = (size_t*)iter->pSize; - size_t allocated_size = *size; - void *pItem; - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left) - { - if (*size + 1 > allocated_size) - { - /* Allocate more storage. This tries to guess the - * number of remaining entries. Round the division - * upwards. */ - allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1; - - if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) - { - status = false; - break; - } - } - - /* Decode the array entry */ - pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size); - initialize_pointer_field(pItem, iter); - if (!func(&substream, iter->pos, pItem)) - { - status = false; - break; - } - (*size)++; - } - pb_close_string_substream(stream, &substream); - - return status; - } - else - { - /* Normal repeated field, i.e. only one item at a time. */ - size_t *size = (size_t*)iter->pSize; - void *pItem; - - (*size)++; - if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size)) - return false; - - pItem = *(uint8_t**)iter->pData + iter->pos->data_size * (*size - 1); - initialize_pointer_field(pItem, iter); - return func(stream, iter->pos, pItem); - } - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -#endif -} - -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) -{ - pb_callback_t *pCallback = (pb_callback_t*)iter->pData; - -#ifdef PB_OLD_CALLBACK_STYLE - void *arg = pCallback->arg; -#else - void **arg = &(pCallback->arg); -#endif - - if (pCallback->funcs.decode == NULL) - return pb_skip_field(stream, wire_type); - - if (wire_type == PB_WT_STRING) - { - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - do - { - if (!pCallback->funcs.decode(&substream, iter->pos, arg)) - PB_RETURN_ERROR(stream, "callback failed"); - } while (substream.bytes_left); - - pb_close_string_substream(stream, &substream); - return true; - } - else - { - /* Copy the single scalar value to stack. - * This is required so that we can limit the stream length, - * which in turn allows to use same callback for packed and - * not-packed fields. */ - pb_istream_t substream; - uint8_t buffer[10]; - size_t size = sizeof(buffer); - - if (!read_raw_value(stream, wire_type, buffer, &size)) - return false; - substream = pb_istream_from_buffer(buffer, size); - - return pCallback->funcs.decode(&substream, iter->pos, arg); - } -} - -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iterator_t *iter) -{ - switch (PB_ATYPE(iter->pos->type)) - { - case PB_ATYPE_STATIC: - return decode_static_field(stream, wire_type, iter); - - case PB_ATYPE_POINTER: - return decode_pointer_field(stream, wire_type, iter); - - case PB_ATYPE_CALLBACK: - return decode_callback_field(stream, wire_type, iter); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -static void iter_from_extension(pb_field_iterator_t *iter, pb_extension_t *extension) -{ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - - iter->start = field; - iter->pos = field; - iter->field_index = 0; - iter->required_field_index = 0; - iter->dest_struct = extension->dest; - iter->pData = extension->dest; - iter->pSize = &extension->found; -} - -/* Default handler for extension fields. Expects a pb_field_t structure - * in extension->type->arg. */ -static bool checkreturn default_extension_decoder(pb_istream_t *stream, - pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) -{ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - pb_field_iterator_t iter; - - if (field->tag != tag) - return true; - - iter_from_extension(&iter, extension); - return decode_field(stream, wire_type, &iter); -} - -/* Try to decode an unknown field as an extension field. Tries each extension - * decoder in turn, until one of them handles the field or loop ends. */ -static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_field_iterator_t *iter) -{ - pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; - size_t pos = stream->bytes_left; - - while (extension != NULL && pos == stream->bytes_left) - { - bool status; - if (extension->type->decode) - status = extension->type->decode(stream, extension, tag, wire_type); - else - status = default_extension_decoder(stream, extension, tag, wire_type); - - if (!status) - return false; - - extension = extension->next; - } - - return true; -} - -/* Step through the iterator until an extension field is found or until all - * entries have been checked. There can be only one extension field per - * message. Returns false if no extension field is found. */ -static bool checkreturn find_extension_field(pb_field_iterator_t *iter) -{ - unsigned start = iter->field_index; - - do { - if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) - return true; - (void)pb_field_next(iter); - } while (iter->field_index != start); - - return false; -} - -/* Initialize message fields to default values, recursively */ -static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) -{ - pb_field_iterator_t iter; - pb_field_init(&iter, fields, dest_struct); - - do - { - pb_type_t type; - type = iter.pos->type; - - /* Avoid crash on empty message types (zero fields) */ - if (iter.pos->tag == 0) - continue; - - if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL) - { - /* Set has_field to false. Still initialize the optional field - * itself also. */ - *(bool*)iter.pSize = false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* Set array count to 0, no need to initialize contents. */ - *(size_t*)iter.pSize = 0; - continue; - } - - if (PB_LTYPE(iter.pos->type) == PB_LTYPE_SUBMESSAGE) - { - /* Initialize submessage to defaults */ - pb_message_set_to_defaults((const pb_field_t *) iter.pos->ptr, iter.pData); - } - else if (iter.pos->ptr != NULL) - { - /* Initialize to default value */ - memcpy(iter.pData, iter.pos->ptr, iter.pos->data_size); - } - else - { - /* Initialize to zeros */ - memset(iter.pData, 0, iter.pos->data_size); - } - } - else if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - /* Initialize the pointer to NULL. */ - *(void**)iter.pData = NULL; - - /* Initialize array count to 0. */ - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - *(size_t*)iter.pSize = 0; - } - } - else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) - { - /* Don't overwrite callback */ - } - } while (pb_field_next(&iter)); -} - -/********************* - * Decode all fields * - *********************/ - -bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - uint8_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 7) / 8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t extension_range_start = 0; - pb_field_iterator_t iter; - - pb_field_init(&iter, fields, dest_struct); - - while (stream->bytes_left) - { - uint32_t tag; - pb_wire_type_t wire_type; - bool eof; - - if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) - { - if (eof) - break; - else - return false; - } - - if (!pb_field_find(&iter, tag)) - { - /* No match found, check if it matches an extension. */ - if (tag >= extension_range_start) - { - if (!find_extension_field(&iter)) - extension_range_start = (uint32_t)-1; - else - extension_range_start = iter.pos->tag; - - if (tag >= extension_range_start) - { - size_t pos = stream->bytes_left; - - if (!decode_extension(stream, tag, wire_type, &iter)) - return false; - - if (pos != stream->bytes_left) - { - /* The field was handled */ - continue; - } - } - } - - /* No match found, skip data */ - if (!pb_skip_field(stream, wire_type)) - return false; - continue; - } - - if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED - && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) - { - fields_seen[iter.required_field_index >> 3] |= (uint8_t)(1 << (iter.required_field_index & 7)); - } - - if (!decode_field(stream, wire_type, &iter)) - return false; - } - - /* Check that all required fields were present. */ - { - /* First figure out the number of required fields by - * seeking to the end of the field array. Usually we - * are already close to end after decoding. - */ - unsigned req_field_count; - pb_type_t last_type; - unsigned i; - do { - req_field_count = iter.required_field_index; - last_type = iter.pos->type; - } while (pb_field_next(&iter)); - - /* Fixup if last field was also required. */ - if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) - req_field_count++; - - /* Check the whole bytes */ - for (i = 0; i < (req_field_count >> 3); i++) - { - if (fields_seen[i] != 0xFF) - PB_RETURN_ERROR(stream, "missing required field"); - } - - /* Check the remaining bits */ - if (fields_seen[req_field_count >> 3] != (0xFF >> (8 - (req_field_count & 7)))) - PB_RETURN_ERROR(stream, "missing required field"); - } - - return true; -} - -bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - bool status; - pb_message_set_to_defaults(fields, dest_struct); - status = pb_decode_noinit(stream, fields, dest_struct); - -#ifdef PB_ENABLE_MALLOC - if (!status) - pb_release(fields, dest_struct); -#endif - - return status; -} - -bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) -{ - pb_istream_t substream; - bool status; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - status = pb_decode(&substream, fields, dest_struct); - pb_close_string_substream(stream, &substream); - return status; -} - -#ifdef PB_ENABLE_MALLOC -static void pb_release_single_field(const pb_field_iterator_t *iter) -{ - pb_type_t type; - type = iter->pos->type; - - /* Release anything contained inside an extension or submsg. - * This has to be done even if the submsg itself is statically - * allocated. */ - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - /* Release fields from all extensions in the linked list */ - pb_extension_t *ext = *(pb_extension_t**)iter->pData; - while (ext != NULL) - { - pb_field_iterator_t ext_iter; - iter_from_extension(&ext_iter, ext); - pb_release_single_field(&ext_iter); - ext = ext->next; - } - } - else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) - { - /* Release fields in submessage or submsg array */ - void *pItem = iter->pData; - pb_size_t count = 1; - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - pItem = *(void**)iter->pData; - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - count = *(pb_size_t*)iter->pSize; - - if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) - { - /* Protect against corrupted _count fields */ - count = iter->pos->array_size; - } - } - - if (pItem) - { - while (count--) - { - pb_release((const pb_field_t*)iter->pos->ptr, pItem); - pItem = (uint8_t*)pItem + iter->pos->data_size; - } - } - } - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - if (PB_HTYPE(type) == PB_HTYPE_REPEATED && - (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES)) - { - /* Release entries in repeated string or bytes array */ - void **pItem = *(void***)iter->pData; - pb_size_t count = *(pb_size_t*)iter->pSize; - while (count--) - { - pb_free(*pItem); - *pItem++ = NULL; - } - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* We are going to release the array, so set the size to 0 */ - *(pb_size_t*)iter->pSize = 0; - } - - /* Release main item */ - pb_free(*(void**)iter->pData); - *(void**)iter->pData = NULL; - } -} - -void pb_release(const pb_field_t fields[], void *dest_struct) -{ - pb_field_iterator_t iter; - pb_field_init(&iter, fields, dest_struct); - - if (iter.pos->tag == 0) - return; /* Empty message type */ - - do - { - pb_release_single_field(&iter); - } while (pb_field_next(&iter)); -} -#endif - -/* Field decoders */ - -bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest) -{ - uint64_t value; - if (!pb_decode_varint(stream, &value)) - return false; - - if (value & 1) - *dest = (int64_t)(~(value >> 1)); - else - *dest = (int64_t)(value >> 1); - - return true; -} - -bool pb_decode_fixed32(pb_istream_t *stream, void *dest) -{ - #ifdef __BIG_ENDIAN__ - uint8_t *bytes = (uint8_t*)dest; - uint8_t lebytes[4]; - - if (!pb_read(stream, lebytes, 4)) - return false; - - bytes[0] = lebytes[3]; - bytes[1] = lebytes[2]; - bytes[2] = lebytes[1]; - bytes[3] = lebytes[0]; - return true; - #else - return pb_read(stream, (uint8_t*)dest, 4); - #endif -} - -bool pb_decode_fixed64(pb_istream_t *stream, void *dest) -{ - #ifdef __BIG_ENDIAN__ - uint8_t *bytes = (uint8_t*)dest; - uint8_t lebytes[8]; - - if (!pb_read(stream, lebytes, 8)) - return false; - - bytes[0] = lebytes[7]; - bytes[1] = lebytes[6]; - bytes[2] = lebytes[5]; - bytes[3] = lebytes[4]; - bytes[4] = lebytes[3]; - bytes[5] = lebytes[2]; - bytes[6] = lebytes[1]; - bytes[7] = lebytes[0]; - return true; - #else - return pb_read(stream, (uint8_t*)dest, 8); - #endif -} - -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint64_t value; - if (!pb_decode_varint(stream, &value)) - return false; - - switch (field->data_size) - { - case 1: *(int8_t*)dest = (int8_t)value; break; - case 2: *(int16_t*)dest = (int16_t)value; break; - case 4: *(int32_t*)dest = (int32_t)value; break; - case 8: *(int64_t*)dest = (int64_t)value; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return true; -} - -static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint64_t value; - if (!pb_decode_varint(stream, &value)) - return false; - - switch (field->data_size) - { - case 4: *(uint32_t*)dest = (uint32_t)value; break; - case 8: *(uint64_t*)dest = value; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return true; -} - -static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - int64_t value; - if (!pb_decode_svarint(stream, &value)) - return false; - - switch (field->data_size) - { - case 4: *(int32_t*)dest = (int32_t)value; break; - case 8: *(int64_t*)dest = value; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return true; -} - -static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - UNUSED(field); - return pb_decode_fixed32(stream, dest); -} - -static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - UNUSED(field); - return pb_decode_fixed64(stream, dest); -} - -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t size; - size_t alloc_size; - pb_bytes_array_t *bdest; - - if (!pb_decode_varint32(stream, &size)) - return false; - - alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); - if (size > alloc_size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { -#ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); -#else - if (!allocate_field(stream, dest, alloc_size, 1)) - return false; - bdest = *(pb_bytes_array_t**)dest; -#endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "bytes overflow"); - bdest = (pb_bytes_array_t*)dest; - } - - bdest->size = size; - - return pb_read(stream, bdest->bytes, size); -} - -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - uint32_t size; - size_t alloc_size; - bool status; - if (!pb_decode_varint32(stream, &size)) - return false; - - /* Space for null terminator */ - alloc_size = size + 1; - - if (alloc_size < size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { -#ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); -#else - if (!allocate_field(stream, dest, alloc_size, 1)) - return false; - dest = *(void**)dest; -#endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "string overflow"); - } - - status = pb_read(stream, (uint8_t*)dest, size); - *((uint8_t*)dest + size) = 0; - return status; -} - -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) -{ - bool status; - pb_istream_t substream; - const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - if (field->ptr == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - /* New array entries need to be initialized, while required and optional - * submessages have already been initialized in the top-level pb_decode. */ - if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) - status = pb_decode(&substream, submsg_fields, dest); - else - status = pb_decode_noinit(&substream, submsg_fields, dest); - - pb_close_string_substream(stream, &substream); - return status; -} diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c new file mode 120000 index 0000000000..1114e7da0b --- /dev/null +++ b/firmware/protob/pb_decode.c @@ -0,0 +1 @@ +../../vendor/nanopb/pb_decode.c \ No newline at end of file diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h deleted file mode 100644 index 45c0675fc0..0000000000 --- a/firmware/protob/pb_decode.h +++ /dev/null @@ -1,149 +0,0 @@ -/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. - * The main function is pb_decode. You also need an input stream, and the - * field descriptions created by nanopb_generator.py. - */ - -#ifndef _PB_DECODE_H_ -#define _PB_DECODE_H_ - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure for defining custom input streams. You will need to provide - * a callback function to read the bytes from your storage, which can be - * for example a file or a network socket. - * - * The callback must conform to these rules: - * - * 1) Return false on IO errors. This will cause decoding to abort. - * 2) You can use state to store your own data (e.g. buffer pointer), - * and rely on pb_read to verify that no-body reads past bytes_left. - * 3) Your callback may be used with substreams, in which case bytes_left - * is different than from the main stream. Don't use bytes_left to compute - * any pointers. - */ -struct _pb_istream_t -{ -#ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - */ - int *callback; -#else - bool (*callback)(pb_istream_t *stream, uint8_t *buf, size_t count); -#endif - - const void *state; /* Free field for use by callback implementation */ - size_t bytes_left; - -#ifndef PB_NO_ERRMSG - const char *errmsg; -#endif -}; - -/*************************** - * Main decoding functions * - ***************************/ - -/* Decode a single protocol buffers message from input stream into a C structure. - * Returns true on success, false on any failure. - * The actual struct pointed to by dest must match the description in fields. - * Callback fields of the destination structure must be initialized by caller. - * All other fields will be initialized by this function. - * - * Example usage: - * MyMessage msg = {}; - * uint8_t buffer[64]; - * pb_istream_t stream; - * - * // ... read some data into buffer ... - * - * stream = pb_istream_from_buffer(buffer, count); - * pb_decode(&stream, MyMessage_fields, &msg); - */ -bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); - -/* Same as pb_decode, except does not initialize the destination structure - * to default values. This is slightly faster if you need no default values - * and just do memset(struct, 0, sizeof(struct)) yourself. - * - * This can also be used for 'merging' two messages, i.e. update only the - * fields that exist in the new message. - * - * Note: If this function returns with an error, it will not release any - * dynamically allocated fields. You will need to call pb_release() yourself. - */ -bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); - -/* Same as pb_decode, except expects the stream to start with the message size - * encoded as varint. Corresponds to parseDelimitedFrom() in Google's - * protobuf API. - */ -bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); - -#ifdef PB_ENABLE_MALLOC -/* Release any allocated pointer fields. If you use dynamic allocation, you should - * call this for any successfully decoded message when you are done with it. If - * pb_decode() returns with an error, the message is already released. - */ -void pb_release(const pb_field_t fields[], void *dest_struct); -#endif - - -/************************************** - * Functions for manipulating streams * - **************************************/ - -/* Create an input stream for reading from a memory buffer. - * - * Alternatively, you can use a custom stream that reads directly from e.g. - * a file or a network socket. - */ -pb_istream_t pb_istream_from_buffer(const uint8_t *buf, size_t bufsize); - -/* Function to read from a pb_istream_t. You can use this if you need to - * read some custom header data, or to read data in field callbacks. - */ -bool pb_read(pb_istream_t *stream, uint8_t *buf, size_t count); - - -/************************************************ - * Helper functions for writing field callbacks * - ************************************************/ - -/* Decode the tag for the next field in the stream. Gives the wire type and - * field tag. At end of the message, returns false and sets eof to true. */ -bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); - -/* Skip the field payload data, given the wire type. */ -bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); - -/* Decode an integer in the varint format. This works for bool, enum, int32, - * int64, uint32 and uint64 field types. */ -bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); - -/* Decode an integer in the zig-zagged svarint format. This works for sint32 - * and sint64. */ -bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); - -/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to - * a 4-byte wide C variable. */ -bool pb_decode_fixed32(pb_istream_t *stream, void *dest); - -/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to - * a 8-byte wide C variable. */ -bool pb_decode_fixed64(pb_istream_t *stream, void *dest); - -/* Make a limited-length substream for reading a PB_WT_STRING field. */ -bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); -void pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h new file mode 120000 index 0000000000..d25f0ac14e --- /dev/null +++ b/firmware/protob/pb_decode.h @@ -0,0 +1 @@ +../../vendor/nanopb/pb_decode.h \ No newline at end of file diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c deleted file mode 100644 index dc5a273493..0000000000 --- a/firmware/protob/pb_encode.c +++ /dev/null @@ -1,667 +0,0 @@ -/* pb_encode.c -- encode a protobuf using minimal resources - * - * 2011 Petteri Aimonen - */ - -#include "pb.h" -#include "pb_encode.h" - -/* Use the GCC warn_unused_result attribute to check that all return values - * are propagated correctly. On other compilers and gcc before 3.4.0 just - * ignore the annotation. - */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn -#else - #define checkreturn __attribute__((warn_unused_result)) -#endif - -/************************************** - * Declarations internal to this file * - **************************************/ -typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; - -static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); -static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); -static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); - -/* --- Function pointers to field encoders --- - * Order in the array must match pb_action_t LTYPE numbering. - */ -static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { - &pb_enc_varint, - &pb_enc_uvarint, - &pb_enc_svarint, - &pb_enc_fixed32, - &pb_enc_fixed64, - - &pb_enc_bytes, - &pb_enc_string, - &pb_enc_submessage, - NULL /* extensions */ -}; - -/******************************* - * pb_ostream_t implementation * - *******************************/ - -static bool checkreturn buf_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - uint8_t *dest = (uint8_t*)stream->state; - stream->state = dest + count; - - while (count--) - *dest++ = *buf++; - - return true; -} - -pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize) -{ - pb_ostream_t stream; -#ifdef PB_BUFFER_ONLY - stream.callback = (void*)1; /* Just a marker value */ -#else - stream.callback = &buf_write; -#endif - stream.state = buf; - stream.max_size = bufsize; - stream.bytes_written = 0; -#ifndef PB_NO_ERRMSG - stream.errmsg = NULL; -#endif - return stream; -} - -bool checkreturn pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - if (stream->callback != NULL) - { - if (stream->bytes_written + count > stream->max_size) - PB_RETURN_ERROR(stream, "stream full"); - -#ifdef PB_BUFFER_ONLY - if (!buf_write(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#else - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#endif - } - - stream->bytes_written += count; - return true; -} - -/************************* - * Encode a single field * - *************************/ - -/* Encode a static array. Handles the size calculations and possible packing. */ -static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, - const void *pData, size_t count, pb_encoder_t func) -{ - size_t i; - const void *p; - size_t size; - - if (count == 0) - return true; - - if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) - PB_RETURN_ERROR(stream, "array max size exceeded"); - - /* We always pack arrays if the datatype allows it. */ - if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) - { - if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) - return false; - - /* Determine the total size of packed array. */ - if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) - { - size = 4 * count; - } - else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - size = 8 * count; - } - else - { - pb_ostream_t sizestream = PB_OSTREAM_SIZING; - p = pData; - for (i = 0; i < count; i++) - { - if (!func(&sizestream, field, p)) - return false; - p = (const char*)p + field->data_size; - } - size = sizestream.bytes_written; - } - - if (!pb_encode_varint(stream, (uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing.. */ - - /* Write the data */ - p = pData; - for (i = 0; i < count; i++) - { - if (!func(stream, field, p)) - return false; - p = (const char*)p + field->data_size; - } - } - else - { - p = pData; - for (i = 0; i < count; i++) - { - if (!pb_encode_tag_for_field(stream, field)) - return false; - - /* Normally the data is stored directly in the array entries, but - * for pointer-type string and bytes fields, the array entries are - * actually pointers themselves also. So we have to dereference once - * more to get to the actual data. */ - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && - (PB_LTYPE(field->type) == PB_LTYPE_STRING || - PB_LTYPE(field->type) == PB_LTYPE_BYTES)) - { - if (!func(stream, field, *(const void* const*)p)) - return false; - } - else - { - if (!func(stream, field, p)) - return false; - } - p = (const char*)p + field->data_size; - } - } - - return true; -} - -/* Encode a field with static or pointer allocation, i.e. one whose data - * is available to the encoder directly. */ -static bool checkreturn encode_basic_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - pb_encoder_t func; - const void *pSize; - bool implicit_has = true; - - func = PB_ENCODERS[PB_LTYPE(field->type)]; - - if (field->size_offset) - pSize = (const char*)pData + field->size_offset; - else - pSize = &implicit_has; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - /* pData is a pointer to the field, which contains pointer to - * the data. If the 2nd pointer is NULL, it is interpreted as if - * the has_field was false. - */ - - pData = *(const void* const*)pData; - implicit_has = (pData != NULL); - } - - switch (PB_HTYPE(field->type)) - { - case PB_HTYPE_REQUIRED: - if (!pData) - PB_RETURN_ERROR(stream, "missing required field"); - if (!pb_encode_tag_for_field(stream, field)) - return false; - if (!func(stream, field, pData)) - return false; - break; - - case PB_HTYPE_OPTIONAL: - if (*(const bool*)pSize) - { - if (!pb_encode_tag_for_field(stream, field)) - return false; - - if (!func(stream, field, pData)) - return false; - } - break; - - case PB_HTYPE_REPEATED: - if (!encode_array(stream, field, pData, *(const size_t*)pSize, func)) - return false; - break; - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } - - return true; -} - -/* Encode a field with callback semantics. This means that a user function is - * called to provide and encode the actual data. */ -static bool checkreturn encode_callback_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - const pb_callback_t *callback = (const pb_callback_t*)pData; - -#ifdef PB_OLD_CALLBACK_STYLE - const void *arg = callback->arg; -#else - void * const *arg = &(callback->arg); -#endif - - if (callback->funcs.encode != NULL) - { - if (!callback->funcs.encode(stream, field, arg)) - PB_RETURN_ERROR(stream, "callback error"); - } - return true; -} - -/* Encode a single field of any callback or static type. */ -static bool checkreturn encode_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - switch (PB_ATYPE(field->type)) - { - case PB_ATYPE_STATIC: - case PB_ATYPE_POINTER: - return encode_basic_field(stream, field, pData); - - case PB_ATYPE_CALLBACK: - return encode_callback_field(stream, field, pData); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -/* Default handler for extension fields. Expects to have a pb_field_t - * pointer in the extension->type->arg field. */ -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, - const pb_extension_t *extension) -{ - const pb_field_t *field = (const pb_field_t*)extension->type->arg; - return encode_field(stream, field, extension->dest); -} - -/* Walk through all the registered extensions and give them a chance - * to encode themselves. */ -static bool checkreturn encode_extension_field(pb_ostream_t *stream, - const pb_field_t *field, const void *pData) -{ - const pb_extension_t *extension = *(const pb_extension_t* const *)pData; - UNUSED(field); - - while (extension) - { - bool status; - if (extension->type->encode) - status = extension->type->encode(stream, extension); - else - status = default_extension_encoder(stream, extension); - - if (!status) - return false; - - extension = extension->next; - } - - return true; -} - -/********************* - * Encode all fields * - *********************/ - -bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - const pb_field_t *field = fields; - const void *pData = src_struct; - size_t prev_size = 0; - - while (field->tag != 0) - { - pData = (const char*)pData + prev_size + field->data_offset; - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - prev_size = sizeof(const void*); - else - prev_size = field->data_size; - - /* Special case for static arrays */ - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_HTYPE(field->type) == PB_HTYPE_REPEATED) - { - prev_size *= field->array_size; - } - - if (PB_LTYPE(field->type) == PB_LTYPE_EXTENSION) - { - /* Special case for the extension field placeholder */ - if (!encode_extension_field(stream, field, pData)) - return false; - } - else - { - /* Regular field */ - if (!encode_field(stream, field, pData)) - return false; - } - - field++; - } - - return true; -} - -bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - return pb_encode_submessage(stream, fields, src_struct); -} - -bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) -{ - pb_ostream_t stream = PB_OSTREAM_SIZING; - - if (!pb_encode(&stream, fields, src_struct)) - return false; - - *size = stream.bytes_written; - return true; -} - -/******************** - * Helper functions * - ********************/ -bool checkreturn pb_encode_varint(pb_ostream_t *stream, uint64_t value) -{ - uint8_t buffer[10]; - size_t i = 0; - - if (value == 0) - return pb_write(stream, (uint8_t*)&value, 1); - - while (value) - { - buffer[i] = (uint8_t)((value & 0x7F) | 0x80); - value >>= 7; - i++; - } - buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ - - return pb_write(stream, buffer, i); -} - -bool checkreturn pb_encode_svarint(pb_ostream_t *stream, int64_t value) -{ - uint64_t zigzagged; - if (value < 0) - zigzagged = ~((uint64_t)value << 1); - else - zigzagged = (uint64_t)value << 1; - - return pb_encode_varint(stream, zigzagged); -} - -bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) -{ - #ifdef __BIG_ENDIAN__ - const uint8_t *bytes = value; - uint8_t lebytes[4]; - lebytes[0] = bytes[3]; - lebytes[1] = bytes[2]; - lebytes[2] = bytes[1]; - lebytes[3] = bytes[0]; - return pb_write(stream, lebytes, 4); - #else - return pb_write(stream, (const uint8_t*)value, 4); - #endif -} - -bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) -{ - #ifdef __BIG_ENDIAN__ - const uint8_t *bytes = value; - uint8_t lebytes[8]; - lebytes[0] = bytes[7]; - lebytes[1] = bytes[6]; - lebytes[2] = bytes[5]; - lebytes[3] = bytes[4]; - lebytes[4] = bytes[3]; - lebytes[5] = bytes[2]; - lebytes[6] = bytes[1]; - lebytes[7] = bytes[0]; - return pb_write(stream, lebytes, 8); - #else - return pb_write(stream, (const uint8_t*)value, 8); - #endif -} - -bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) -{ - uint64_t tag = ((uint64_t)field_number << 3) | wiretype; - return pb_encode_varint(stream, tag); -} - -bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) -{ - pb_wire_type_t wiretype; - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - wiretype = PB_WT_VARINT; - break; - - case PB_LTYPE_FIXED32: - wiretype = PB_WT_32BIT; - break; - - case PB_LTYPE_FIXED64: - wiretype = PB_WT_64BIT; - break; - - case PB_LTYPE_BYTES: - case PB_LTYPE_STRING: - case PB_LTYPE_SUBMESSAGE: - wiretype = PB_WT_STRING; - break; - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } - - return pb_encode_tag(stream, wiretype, field->tag); -} - -bool checkreturn pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size) -{ - if (!pb_encode_varint(stream, (uint64_t)size)) - return false; - - return pb_write(stream, buffer, size); -} - -bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) -{ - /* First calculate the message size using a non-writing substream. */ - pb_ostream_t substream = PB_OSTREAM_SIZING; - size_t size; - bool status; - - if (!pb_encode(&substream, fields, src_struct)) - { -#ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; -#endif - return false; - } - - size = substream.bytes_written; - - if (!pb_encode_varint(stream, (uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing */ - - if (stream->bytes_written + size > stream->max_size) - PB_RETURN_ERROR(stream, "stream full"); - - /* Use a substream to verify that a callback doesn't write more than - * what it did the first time. */ - substream.callback = stream->callback; - substream.state = stream->state; - substream.max_size = size; - substream.bytes_written = 0; -#ifndef PB_NO_ERRMSG - substream.errmsg = NULL; -#endif - - status = pb_encode(&substream, fields, src_struct); - - stream->bytes_written += substream.bytes_written; - stream->state = substream.state; -#ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; -#endif - - if (substream.bytes_written != size) - PB_RETURN_ERROR(stream, "submsg size changed"); - - return status; -} - -/* Field encoders */ - -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - int64_t value = 0; - - /* Cases 1 and 2 are for compilers that have smaller types for bool - * or enums. */ - switch (field->data_size) - { - case 1: value = *(const int8_t*)src; break; - case 2: value = *(const int16_t*)src; break; - case 4: value = *(const int32_t*)src; break; - case 8: value = *(const int64_t*)src; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return pb_encode_varint(stream, (uint64_t)value); -} - -static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - uint64_t value = 0; - - switch (field->data_size) - { - case 4: value = *(const uint32_t*)src; break; - case 8: value = *(const uint64_t*)src; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return pb_encode_varint(stream, value); -} - -static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - int64_t value = 0; - - switch (field->data_size) - { - case 4: value = *(const int32_t*)src; break; - case 8: value = *(const int64_t*)src; break; - default: PB_RETURN_ERROR(stream, "invalid data_size"); - } - - return pb_encode_svarint(stream, value); -} - -static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - UNUSED(field); - return pb_encode_fixed64(stream, src); -} - -static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - UNUSED(field); - return pb_encode_fixed32(stream, src); -} - -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)src; - - if (src == NULL) - { - /* Threat null pointer as an empty bytes field */ - return pb_encode_string(stream, NULL, 0); - } - - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size) - { - PB_RETURN_ERROR(stream, "bytes size exceeded"); - } - - return pb_encode_string(stream, bytes->bytes, bytes->size); -} - -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - /* strnlen() is not always available, so just use a loop */ - size_t size = 0; - size_t max_size = field->data_size; - const char *p = (const char*)src; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - max_size = (size_t)-1; - - if (src == NULL) - { - size = 0; /* Threat null pointer as an empty string */ - } - else - { - while (size < max_size && *p != '\0') - { - size++; - p++; - } - } - - return pb_encode_string(stream, (const uint8_t*)src, size); -} - -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) -{ - if (field->ptr == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); -} - diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c new file mode 120000 index 0000000000..aebfbfda3a --- /dev/null +++ b/firmware/protob/pb_encode.c @@ -0,0 +1 @@ +../../vendor/nanopb/pb_encode.c \ No newline at end of file diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h deleted file mode 100644 index f82bac8f86..0000000000 --- a/firmware/protob/pb_encode.h +++ /dev/null @@ -1,154 +0,0 @@ -/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. - * The main function is pb_encode. You also need an output stream, and the - * field descriptions created by nanopb_generator.py. - */ - -#ifndef _PB_ENCODE_H_ -#define _PB_ENCODE_H_ - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure for defining custom output streams. You will need to provide - * a callback function to write the bytes to your storage, which can be - * for example a file or a network socket. - * - * The callback must conform to these rules: - * - * 1) Return false on IO errors. This will cause encoding to abort. - * 2) You can use state to store your own data (e.g. buffer pointer). - * 3) pb_write will update bytes_written after your callback runs. - * 4) Substreams will modify max_size and bytes_written. Don't use them - * to calculate any pointers. - */ -struct _pb_ostream_t -{ -#ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - * Also, NULL pointer marks a 'sizing stream' that does not - * write anything. - */ - int *callback; -#else - bool (*callback)(pb_ostream_t *stream, const uint8_t *buf, size_t count); -#endif - void *state; /* Free field for use by callback implementation. */ - size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ - size_t bytes_written; /* Number of bytes written so far. */ - -#ifndef PB_NO_ERRMSG - const char *errmsg; -#endif -}; - -/*************************** - * Main encoding functions * - ***************************/ - -/* Encode a single protocol buffers message from C structure into a stream. - * Returns true on success, false on any failure. - * The actual struct pointed to by src_struct must match the description in fields. - * All required fields in the struct are assumed to have been filled in. - * - * Example usage: - * MyMessage msg = {}; - * uint8_t buffer[64]; - * pb_ostream_t stream; - * - * msg.field1 = 42; - * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - * pb_encode(&stream, MyMessage_fields, &msg); - */ -bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); - -/* Same as pb_encode, but prepends the length of the message as a varint. - * Corresponds to writeDelimitedTo() in Google's protobuf API. - */ -bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); - -/* Encode the message to get the size of the encoded data, but do not store - * the data. */ -bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); - -/************************************** - * Functions for manipulating streams * - **************************************/ - -/* Create an output stream for writing into a memory buffer. - * The number of bytes written can be found in stream.bytes_written after - * encoding the message. - * - * Alternatively, you can use a custom stream that writes directly to e.g. - * a file or a network socket. - */ -pb_ostream_t pb_ostream_from_buffer(uint8_t *buf, size_t bufsize); - -/* Pseudo-stream for measuring the size of a message without actually storing - * the encoded data. - * - * Example usage: - * MyMessage msg = {}; - * pb_ostream_t stream = PB_OSTREAM_SIZING; - * pb_encode(&stream, MyMessage_fields, &msg); - * printf("Message size is %d\n", stream.bytes_written); - */ -#ifndef PB_NO_ERRMSG -#define PB_OSTREAM_SIZING {0,0,0,0,0} -#else -#define PB_OSTREAM_SIZING {0,0,0,0} -#endif - -/* Function to write into a pb_ostream_t stream. You can use this if you need - * to append or prepend some custom headers to the message. - */ -bool pb_write(pb_ostream_t *stream, const uint8_t *buf, size_t count); - - -/************************************************ - * Helper functions for writing field callbacks * - ************************************************/ - -/* Encode field header based on type and field number defined in the field - * structure. Call this from the callback before writing out field contents. */ -bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); - -/* Encode field header by manually specifing wire type. You need to use this - * if you want to write out packed arrays from a callback field. */ -bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); - -/* Encode an integer in the varint format. - * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ -bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); - -/* Encode an integer in the zig-zagged svarint format. - * This works for sint32 and sint64. */ -bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); - -/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ -bool pb_encode_string(pb_ostream_t *stream, const uint8_t *buffer, size_t size); - -/* Encode a fixed32, sfixed32 or float value. - * You need to pass a pointer to a 4-byte wide C variable. */ -bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); - -/* Encode a fixed64, sfixed64 or double value. - * You need to pass a pointer to a 8-byte wide C variable. */ -bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); - -/* Encode a submessage field. - * You need to pass the pb_field_t array and pointer to struct, just like - * with pb_encode(). This internally encodes the submessage twice, first to - * calculate message size and then to actually write it out. - */ -bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h new file mode 120000 index 0000000000..04b7546e4a --- /dev/null +++ b/firmware/protob/pb_encode.h @@ -0,0 +1 @@ +../../vendor/nanopb/pb_encode.h \ No newline at end of file diff --git a/firmware/protob/storage.pb.c b/firmware/protob/storage.pb.c deleted file mode 100644 index 42e40039df..0000000000 --- a/firmware/protob/storage.pb.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.3 */ - -#include "storage.pb.h" - - - -const pb_field_t Storage_fields[14] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, Storage, version, version, 0), - PB_FIELD2( 2, MESSAGE , OPTIONAL, STATIC , OTHER, Storage, node, version, &HDNodeType_fields), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, Storage, mnemonic, node, 0), - PB_FIELD2( 4, BOOL , OPTIONAL, STATIC , OTHER, Storage, passphrase_protection, mnemonic, 0), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, Storage, pin_failed_attempts, passphrase_protection, 0), - PB_FIELD2( 6, STRING , OPTIONAL, STATIC , OTHER, Storage, pin, pin_failed_attempts, 0), - PB_FIELD2( 7, STRING , OPTIONAL, STATIC , OTHER, Storage, language, pin, 0), - PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, Storage, label, language, 0), - PB_FIELD2( 9, BOOL , OPTIONAL, STATIC , OTHER, Storage, imported, label, 0), - PB_FIELD2( 10, BYTES , OPTIONAL, STATIC , OTHER, Storage, homescreen, imported, 0), - PB_FIELD2( 11, UINT32 , OPTIONAL, STATIC , OTHER, Storage, u2f_counter, homescreen, 0), - PB_FIELD2( 12, BOOL , OPTIONAL, STATIC , OTHER, Storage, needs_backup, u2f_counter, 0), - PB_FIELD2( 13, UINT32 , OPTIONAL, STATIC , OTHER, Storage, flags, needs_backup, 0), - PB_LAST_FIELD -}; - - -/* Check that field information fits in pb_field_t */ -#if !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_32BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in 8 or 16 bit - * field descriptors. - */ -STATIC_ASSERT((pb_membersize(Storage, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Storage) -#endif - -#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for Storage.homescreen is too large. Define PB_FIELD_16BIT to fix this. -#endif - - diff --git a/firmware/protob/storage.pb.h b/firmware/protob/storage.pb.h deleted file mode 100644 index 0478617268..0000000000 --- a/firmware/protob/storage.pb.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.3 */ - -#ifndef _PB_STORAGE_PB_H_ -#define _PB_STORAGE_PB_H_ -#include "pb.h" -#include "types.pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Enum definitions */ -/* Struct definitions */ -typedef struct { - size_t size; - uint8_t bytes[1024]; -} Storage_homescreen_t; - -typedef struct _Storage { - uint32_t version; - bool has_node; - HDNodeType node; - bool has_mnemonic; - char mnemonic[241]; - bool has_passphrase_protection; - bool passphrase_protection; - bool has_pin_failed_attempts; - uint32_t pin_failed_attempts; - bool has_pin; - char pin[10]; - bool has_language; - char language[17]; - bool has_label; - char label[33]; - bool has_imported; - bool imported; - bool has_homescreen; - Storage_homescreen_t homescreen; - bool has_u2f_counter; - uint32_t u2f_counter; - bool has_needs_backup; - bool needs_backup; - bool has_flags; - uint32_t flags; -} Storage; - -/* Default values for struct fields */ - -/* Initializer values for message structs */ -#define Storage_init_default {0, false, HDNodeType_init_default, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0, false, 0} -#define Storage_init_zero {0, false, HDNodeType_init_zero, false, "", false, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, 0, false, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define Storage_version_tag 1 -#define Storage_node_tag 2 -#define Storage_mnemonic_tag 3 -#define Storage_passphrase_protection_tag 4 -#define Storage_pin_failed_attempts_tag 5 -#define Storage_pin_tag 6 -#define Storage_language_tag 7 -#define Storage_label_tag 8 -#define Storage_imported_tag 9 -#define Storage_homescreen_tag 10 -#define Storage_u2f_counter_tag 11 -#define Storage_needs_backup_tag 12 -#define Storage_flags_tag 13 - -/* Struct field encoding specification for nanopb */ -extern const pb_field_t Storage_fields[14]; - -/* Maximum encoded size of messages (where known) */ -#define Storage_size (1373 + HDNodeType_size) - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/firmware/protob/types.pb.c b/firmware/protob/types.pb.c deleted file mode 100644 index 7974a2811f..0000000000 --- a/firmware/protob/types.pb.c +++ /dev/null @@ -1,213 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.2.9.3 */ - -#include "types.pb.h" - -const uint32_t CoinType_address_type_default = 0u; -const uint32_t CoinType_address_type_p2sh_default = 5u; -const uint32_t CoinType_xpub_magic_default = 76067358u; -const uint32_t CoinType_xprv_magic_default = 76066276u; -const uint32_t TxInputType_sequence_default = 4294967295u; -const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; -const uint32_t IdentityType_index_default = 0u; - - -const pb_field_t HDNodeType_fields[7] = { - PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, HDNodeType, depth, depth, 0), - PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, fingerprint, depth, 0), - PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, HDNodeType, child_num, fingerprint, 0), - PB_FIELD2( 4, BYTES , REQUIRED, STATIC , OTHER, HDNodeType, chain_code, child_num, 0), - PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, private_key, chain_code, 0), - PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, HDNodeType, public_key, private_key, 0), - PB_LAST_FIELD -}; - -const pb_field_t HDNodePathType_fields[3] = { - PB_FIELD2( 1, MESSAGE , REQUIRED, STATIC , FIRST, HDNodePathType, node, node, &HDNodeType_fields), - PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, HDNodePathType, address_n, node, 0), - PB_LAST_FIELD -}; - -const pb_field_t CoinType_fields[11] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), - PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), - PB_FIELD2( 8, STRING , OPTIONAL, STATIC , OTHER, CoinType, signed_message_header, address_type_p2sh, 0), - PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xpub_magic, signed_message_header, &CoinType_xpub_magic_default), - PB_FIELD2( 10, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, xprv_magic, xpub_magic, &CoinType_xprv_magic_default), - PB_FIELD2( 11, BOOL , OPTIONAL, STATIC , OTHER, CoinType, segwit, xprv_magic, 0), - PB_FIELD2( 12, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, forkid, segwit, 0), - PB_LAST_FIELD -}; - -const pb_field_t MultisigRedeemScriptType_fields[4] = { - PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, MultisigRedeemScriptType, pubkeys, pubkeys, &HDNodePathType_fields), - PB_FIELD2( 2, BYTES , REPEATED, STATIC , OTHER, MultisigRedeemScriptType, signatures, pubkeys, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, MultisigRedeemScriptType, m, signatures, 0), - PB_LAST_FIELD -}; - -const pb_field_t TxInputType_fields[9] = { - PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, TxInputType, address_n, address_n, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxInputType, prev_hash, address_n, 0), - PB_FIELD2( 3, UINT32 , REQUIRED, STATIC , OTHER, TxInputType, prev_index, prev_hash, 0), - PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, TxInputType, script_sig, prev_index, 0), - PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, TxInputType, sequence, script_sig, &TxInputType_sequence_default), - PB_FIELD2( 6, ENUM , OPTIONAL, STATIC , OTHER, TxInputType, script_type, sequence, &TxInputType_script_type_default), - PB_FIELD2( 7, MESSAGE , OPTIONAL, STATIC , OTHER, TxInputType, multisig, script_type, &MultisigRedeemScriptType_fields), - PB_FIELD2( 8, UINT64 , OPTIONAL, STATIC , OTHER, TxInputType, amount, multisig, 0), - PB_LAST_FIELD -}; - -const pb_field_t TxOutputType_fields[7] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, TxOutputType, address, address, 0), - PB_FIELD2( 2, UINT32 , REPEATED, STATIC , OTHER, TxOutputType, address_n, address, 0), - PB_FIELD2( 3, UINT64 , REQUIRED, STATIC , OTHER, TxOutputType, amount, address_n, 0), - PB_FIELD2( 4, ENUM , REQUIRED, STATIC , OTHER, TxOutputType, script_type, amount, 0), - PB_FIELD2( 5, MESSAGE , OPTIONAL, STATIC , OTHER, TxOutputType, multisig, script_type, &MultisigRedeemScriptType_fields), - PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, TxOutputType, op_return_data, multisig, 0), - PB_LAST_FIELD -}; - -const pb_field_t TxOutputBinType_fields[3] = { - PB_FIELD2( 1, UINT64 , REQUIRED, STATIC , FIRST, TxOutputBinType, amount, amount, 0), - PB_FIELD2( 2, BYTES , REQUIRED, STATIC , OTHER, TxOutputBinType, script_pubkey, amount, 0), - PB_LAST_FIELD -}; - -const pb_field_t TransactionType_fields[10] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), - PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), - PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, lock_time, bin_outputs, 0), - PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), - PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), - PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), - PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, TransactionType, extra_data, outputs_cnt, 0), - PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, extra_data_len, extra_data, 0), - PB_LAST_FIELD -}; - -const pb_field_t TxRequestDetailsType_fields[5] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), - PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_len, tx_hash, 0), - PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_offset, extra_data_len, 0), - PB_LAST_FIELD -}; - -const pb_field_t TxRequestSerializedType_fields[4] = { - PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestSerializedType, signature_index, signature_index, 0), - PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, signature, signature_index, 0), - PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, TxRequestSerializedType, serialized_tx, signature, 0), - PB_LAST_FIELD -}; - -const pb_field_t IdentityType_fields[7] = { - PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, IdentityType, proto, proto, 0), - PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, IdentityType, user, proto, 0), - PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, IdentityType, host, user, 0), - PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, IdentityType, port, host, 0), - PB_FIELD2( 5, STRING , OPTIONAL, STATIC , OTHER, IdentityType, path, port, 0), - PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, IdentityType, index, path, &IdentityType_index_default), - PB_LAST_FIELD -}; - -typedef struct { - bool wire_in; -} wire_in_struct; - -static const pb_field_t wire_in_field = - PB_FIELD2(50002, BOOL , OPTEXT, STATIC , FIRST, wire_in_struct, wire_in, wire_in, 0); - -const pb_extension_type_t wire_in = { - NULL, - NULL, - &wire_in_field -}; - -typedef struct { - bool wire_out; -} wire_out_struct; - -static const pb_field_t wire_out_field = - PB_FIELD2(50003, BOOL , OPTEXT, STATIC , FIRST, wire_out_struct, wire_out, wire_out, 0); - -const pb_extension_type_t wire_out = { - NULL, - NULL, - &wire_out_field -}; - -typedef struct { - bool wire_debug_in; -} wire_debug_in_struct; - -static const pb_field_t wire_debug_in_field = - PB_FIELD2(50004, BOOL , OPTEXT, STATIC , FIRST, wire_debug_in_struct, wire_debug_in, wire_debug_in, 0); - -const pb_extension_type_t wire_debug_in = { - NULL, - NULL, - &wire_debug_in_field -}; - -typedef struct { - bool wire_debug_out; -} wire_debug_out_struct; - -static const pb_field_t wire_debug_out_field = - PB_FIELD2(50005, BOOL , OPTEXT, STATIC , FIRST, wire_debug_out_struct, wire_debug_out, wire_debug_out, 0); - -const pb_extension_type_t wire_debug_out = { - NULL, - NULL, - &wire_debug_out_field -}; - -typedef struct { - bool wire_tiny; -} wire_tiny_struct; - -static const pb_field_t wire_tiny_field = - PB_FIELD2(50006, BOOL , OPTEXT, STATIC , FIRST, wire_tiny_struct, wire_tiny, wire_tiny, 0); - -const pb_extension_type_t wire_tiny = { - NULL, - NULL, - &wire_tiny_field -}; - -typedef struct { - bool wire_bootloader; -} wire_bootloader_struct; - -static const pb_field_t wire_bootloader_field = - PB_FIELD2(50007, BOOL , OPTEXT, STATIC , FIRST, wire_bootloader_struct, wire_bootloader, wire_bootloader, 0); - -const pb_extension_type_t wire_bootloader = { - NULL, - NULL, - &wire_bootloader_field -}; - - -/* Check that field information fits in pb_field_t */ -#if !defined(PB_FIELD_32BIT) -/* If you get an error here, it means that you need to define PB_FIELD_32BIT - * compile-time option. You can do that in pb.h or on compiler command line. - * - * The reason you need to do this is that some of your messages contain tag - * numbers or field sizes that are larger than what can fit in 8 or 16 bit - * field descriptors. - */ -STATIC_ASSERT((pb_membersize(HDNodePathType, node) < 65536 && pb_membersize(MultisigRedeemScriptType, pubkeys[0]) < 65536 && pb_membersize(TxInputType, multisig) < 65536 && pb_membersize(TxOutputType, multisig) < 65536 && pb_membersize(TransactionType, inputs[0]) < 65536 && pb_membersize(TransactionType, bin_outputs[0]) < 65536 && pb_membersize(TransactionType, outputs[0]) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_HDNodeType_HDNodePathType_CoinType_MultisigRedeemScriptType_TxInputType_TxOutputType_TxOutputBinType_TransactionType_TxRequestDetailsType_TxRequestSerializedType_IdentityType) -#endif - -#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) -#error Field descriptor for TxRequestSerializedType.serialized_tx is too large. Define PB_FIELD_16BIT to fix this. -#endif - - diff --git a/firmware/protob/types.pb.h b/firmware/protob/types.pb.h deleted file mode 100644 index 9bfd3dd9df..0000000000 --- a/firmware/protob/types.pb.h +++ /dev/null @@ -1,422 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.2.9.3 */ - -#ifndef _PB_TYPES_PB_H_ -#define _PB_TYPES_PB_H_ -#include "pb.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Enum definitions */ -typedef enum _FailureType { - FailureType_Failure_UnexpectedMessage = 1, - FailureType_Failure_ButtonExpected = 2, - FailureType_Failure_DataError = 3, - FailureType_Failure_ActionCancelled = 4, - FailureType_Failure_PinExpected = 5, - FailureType_Failure_PinCancelled = 6, - FailureType_Failure_PinInvalid = 7, - FailureType_Failure_InvalidSignature = 8, - FailureType_Failure_ProcessError = 9, - FailureType_Failure_NotEnoughFunds = 10, - FailureType_Failure_NotInitialized = 11, - FailureType_Failure_FirmwareError = 99 -} FailureType; - -typedef enum _OutputScriptType { - OutputScriptType_PAYTOADDRESS = 0, - OutputScriptType_PAYTOSCRIPTHASH = 1, - OutputScriptType_PAYTOMULTISIG = 2, - OutputScriptType_PAYTOOPRETURN = 3, - OutputScriptType_PAYTOWITNESS = 4, - OutputScriptType_PAYTOP2SHWITNESS = 5 -} OutputScriptType; - -typedef enum _InputScriptType { - InputScriptType_SPENDADDRESS = 0, - InputScriptType_SPENDMULTISIG = 1, - InputScriptType_EXTERNAL = 2, - InputScriptType_SPENDWITNESS = 3, - InputScriptType_SPENDP2SHWITNESS = 4 -} InputScriptType; - -typedef enum _RequestType { - RequestType_TXINPUT = 0, - RequestType_TXOUTPUT = 1, - RequestType_TXMETA = 2, - RequestType_TXFINISHED = 3, - RequestType_TXEXTRADATA = 4 -} RequestType; - -typedef enum _ButtonRequestType { - ButtonRequestType_ButtonRequest_Other = 1, - ButtonRequestType_ButtonRequest_FeeOverThreshold = 2, - ButtonRequestType_ButtonRequest_ConfirmOutput = 3, - ButtonRequestType_ButtonRequest_ResetDevice = 4, - ButtonRequestType_ButtonRequest_ConfirmWord = 5, - ButtonRequestType_ButtonRequest_WipeDevice = 6, - ButtonRequestType_ButtonRequest_ProtectCall = 7, - ButtonRequestType_ButtonRequest_SignTx = 8, - ButtonRequestType_ButtonRequest_FirmwareCheck = 9, - ButtonRequestType_ButtonRequest_Address = 10, - ButtonRequestType_ButtonRequest_PublicKey = 11 -} ButtonRequestType; - -typedef enum _PinMatrixRequestType { - PinMatrixRequestType_PinMatrixRequestType_Current = 1, - PinMatrixRequestType_PinMatrixRequestType_NewFirst = 2, - PinMatrixRequestType_PinMatrixRequestType_NewSecond = 3 -} PinMatrixRequestType; - -typedef enum _RecoveryDeviceType { - RecoveryDeviceType_RecoveryDeviceType_ScrambledWords = 0, - RecoveryDeviceType_RecoveryDeviceType_Matrix = 1 -} RecoveryDeviceType; - -typedef enum _WordRequestType { - WordRequestType_WordRequestType_Plain = 0, - WordRequestType_WordRequestType_Matrix9 = 1, - WordRequestType_WordRequestType_Matrix6 = 2 -} WordRequestType; - -/* Struct definitions */ -typedef struct _CoinType { - bool has_coin_name; - char coin_name[17]; - bool has_coin_shortcut; - char coin_shortcut[9]; - bool has_address_type; - uint32_t address_type; - bool has_maxfee_kb; - uint64_t maxfee_kb; - bool has_address_type_p2sh; - uint32_t address_type_p2sh; - bool has_signed_message_header; - char signed_message_header[32]; - bool has_xpub_magic; - uint32_t xpub_magic; - bool has_xprv_magic; - uint32_t xprv_magic; - bool has_segwit; - bool segwit; - bool has_forkid; - uint32_t forkid; -} CoinType; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} HDNodeType_chain_code_t; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} HDNodeType_private_key_t; - -typedef struct { - size_t size; - uint8_t bytes[33]; -} HDNodeType_public_key_t; - -typedef struct _HDNodeType { - uint32_t depth; - uint32_t fingerprint; - uint32_t child_num; - HDNodeType_chain_code_t chain_code; - bool has_private_key; - HDNodeType_private_key_t private_key; - bool has_public_key; - HDNodeType_public_key_t public_key; -} HDNodeType; - -typedef struct _IdentityType { - bool has_proto; - char proto[9]; - bool has_user; - char user[64]; - bool has_host; - char host[64]; - bool has_port; - char port[6]; - bool has_path; - char path[256]; - bool has_index; - uint32_t index; -} IdentityType; - -typedef struct { - size_t size; - uint8_t bytes[520]; -} TxOutputBinType_script_pubkey_t; - -typedef struct _TxOutputBinType { - uint64_t amount; - TxOutputBinType_script_pubkey_t script_pubkey; -} TxOutputBinType; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} TxRequestDetailsType_tx_hash_t; - -typedef struct _TxRequestDetailsType { - bool has_request_index; - uint32_t request_index; - bool has_tx_hash; - TxRequestDetailsType_tx_hash_t tx_hash; - bool has_extra_data_len; - uint32_t extra_data_len; - bool has_extra_data_offset; - uint32_t extra_data_offset; -} TxRequestDetailsType; - -typedef struct { - size_t size; - uint8_t bytes[73]; -} TxRequestSerializedType_signature_t; - -typedef struct { - size_t size; - uint8_t bytes[2048]; -} TxRequestSerializedType_serialized_tx_t; - -typedef struct _TxRequestSerializedType { - bool has_signature_index; - uint32_t signature_index; - bool has_signature; - TxRequestSerializedType_signature_t signature; - bool has_serialized_tx; - TxRequestSerializedType_serialized_tx_t serialized_tx; -} TxRequestSerializedType; - -typedef struct _HDNodePathType { - HDNodeType node; - size_t address_n_count; - uint32_t address_n[8]; -} HDNodePathType; - -typedef struct { - size_t size; - uint8_t bytes[73]; -} MultisigRedeemScriptType_signatures_t; - -typedef struct _MultisigRedeemScriptType { - size_t pubkeys_count; - HDNodePathType pubkeys[15]; - size_t signatures_count; - MultisigRedeemScriptType_signatures_t signatures[15]; - bool has_m; - uint32_t m; -} MultisigRedeemScriptType; - -typedef struct { - size_t size; - uint8_t bytes[32]; -} TxInputType_prev_hash_t; - -typedef struct { - size_t size; - uint8_t bytes[1650]; -} TxInputType_script_sig_t; - -typedef struct _TxInputType { - size_t address_n_count; - uint32_t address_n[8]; - TxInputType_prev_hash_t prev_hash; - uint32_t prev_index; - bool has_script_sig; - TxInputType_script_sig_t script_sig; - bool has_sequence; - uint32_t sequence; - bool has_script_type; - InputScriptType script_type; - bool has_multisig; - MultisigRedeemScriptType multisig; - bool has_amount; - uint64_t amount; -} TxInputType; - -typedef struct { - size_t size; - uint8_t bytes[80]; -} TxOutputType_op_return_data_t; - -typedef struct _TxOutputType { - bool has_address; - char address[54]; - size_t address_n_count; - uint32_t address_n[8]; - uint64_t amount; - OutputScriptType script_type; - bool has_multisig; - MultisigRedeemScriptType multisig; - bool has_op_return_data; - TxOutputType_op_return_data_t op_return_data; -} TxOutputType; - -typedef struct { - size_t size; - uint8_t bytes[1024]; -} TransactionType_extra_data_t; - -typedef struct _TransactionType { - bool has_version; - uint32_t version; - size_t inputs_count; - TxInputType inputs[1]; - size_t bin_outputs_count; - TxOutputBinType bin_outputs[1]; - bool has_lock_time; - uint32_t lock_time; - size_t outputs_count; - TxOutputType outputs[1]; - bool has_inputs_cnt; - uint32_t inputs_cnt; - bool has_outputs_cnt; - uint32_t outputs_cnt; - bool has_extra_data; - TransactionType_extra_data_t extra_data; - bool has_extra_data_len; - uint32_t extra_data_len; -} TransactionType; - -/* Extensions */ -extern const pb_extension_type_t wire_in; -extern const pb_extension_type_t wire_out; -extern const pb_extension_type_t wire_debug_in; -extern const pb_extension_type_t wire_debug_out; -extern const pb_extension_type_t wire_tiny; -extern const pb_extension_type_t wire_bootloader; - -/* Default values for struct fields */ -extern const uint32_t CoinType_address_type_default; -extern const uint32_t CoinType_address_type_p2sh_default; -extern const uint32_t CoinType_xpub_magic_default; -extern const uint32_t CoinType_xprv_magic_default; -extern const uint32_t TxInputType_sequence_default; -extern const InputScriptType TxInputType_script_type_default; -extern const uint32_t IdentityType_index_default; - -/* Initializer values for message structs */ -#define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, "", false, 76067358u, false, 76066276u, false, 0, false, 0} -#define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 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}}}, false, 0} -#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} -#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} -#define TxOutputBinType_init_default {0, {0, {0}}} -#define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0, false, {0, {0}}, false, 0} -#define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}, false, 0, false, 0} -#define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} -#define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} -#define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} -#define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, 0, false, 0} -#define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 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}}}, false, 0} -#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} -#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} -#define TxOutputBinType_init_zero {0, {0, {0}}} -#define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0, false, {0, {0}}, false, 0} -#define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}, false, 0, false, 0} -#define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}} -#define IdentityType_init_zero {false, "", false, "", false, "", false, "", false, "", false, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define CoinType_coin_name_tag 1 -#define CoinType_coin_shortcut_tag 2 -#define CoinType_address_type_tag 3 -#define CoinType_maxfee_kb_tag 4 -#define CoinType_address_type_p2sh_tag 5 -#define CoinType_signed_message_header_tag 8 -#define CoinType_xpub_magic_tag 9 -#define CoinType_xprv_magic_tag 10 -#define CoinType_segwit_tag 11 -#define CoinType_forkid_tag 12 -#define HDNodeType_depth_tag 1 -#define HDNodeType_fingerprint_tag 2 -#define HDNodeType_child_num_tag 3 -#define HDNodeType_chain_code_tag 4 -#define HDNodeType_private_key_tag 5 -#define HDNodeType_public_key_tag 6 -#define IdentityType_proto_tag 1 -#define IdentityType_user_tag 2 -#define IdentityType_host_tag 3 -#define IdentityType_port_tag 4 -#define IdentityType_path_tag 5 -#define IdentityType_index_tag 6 -#define TxOutputBinType_amount_tag 1 -#define TxOutputBinType_script_pubkey_tag 2 -#define TxRequestDetailsType_request_index_tag 1 -#define TxRequestDetailsType_tx_hash_tag 2 -#define TxRequestDetailsType_extra_data_len_tag 3 -#define TxRequestDetailsType_extra_data_offset_tag 4 -#define TxRequestSerializedType_signature_index_tag 1 -#define TxRequestSerializedType_signature_tag 2 -#define TxRequestSerializedType_serialized_tx_tag 3 -#define HDNodePathType_node_tag 1 -#define HDNodePathType_address_n_tag 2 -#define MultisigRedeemScriptType_pubkeys_tag 1 -#define MultisigRedeemScriptType_signatures_tag 2 -#define MultisigRedeemScriptType_m_tag 3 -#define TxInputType_address_n_tag 1 -#define TxInputType_prev_hash_tag 2 -#define TxInputType_prev_index_tag 3 -#define TxInputType_script_sig_tag 4 -#define TxInputType_sequence_tag 5 -#define TxInputType_script_type_tag 6 -#define TxInputType_multisig_tag 7 -#define TxInputType_amount_tag 8 -#define TxOutputType_address_tag 1 -#define TxOutputType_address_n_tag 2 -#define TxOutputType_amount_tag 3 -#define TxOutputType_script_type_tag 4 -#define TxOutputType_multisig_tag 5 -#define TxOutputType_op_return_data_tag 6 -#define TransactionType_version_tag 1 -#define TransactionType_inputs_tag 2 -#define TransactionType_bin_outputs_tag 3 -#define TransactionType_outputs_tag 5 -#define TransactionType_lock_time_tag 4 -#define TransactionType_inputs_cnt_tag 6 -#define TransactionType_outputs_cnt_tag 7 -#define TransactionType_extra_data_tag 8 -#define TransactionType_extra_data_len_tag 9 -#define wire_in_tag 50002 -#define wire_out_tag 50003 -#define wire_debug_in_tag 50004 -#define wire_debug_out_tag 50005 -#define wire_tiny_tag 50006 -#define wire_bootloader_tag 50007 - -/* Struct field encoding specification for nanopb */ -extern const pb_field_t HDNodeType_fields[7]; -extern const pb_field_t HDNodePathType_fields[3]; -extern const pb_field_t CoinType_fields[11]; -extern const pb_field_t MultisigRedeemScriptType_fields[4]; -extern const pb_field_t TxInputType_fields[9]; -extern const pb_field_t TxOutputType_fields[7]; -extern const pb_field_t TxOutputBinType_fields[3]; -extern const pb_field_t TransactionType_fields[10]; -extern const pb_field_t TxRequestDetailsType_fields[5]; -extern const pb_field_t TxRequestSerializedType_fields[4]; -extern const pb_field_t IdentityType_fields[7]; - -/* Maximum encoded size of messages (where known) */ -#define HDNodeType_size 121 -#define HDNodePathType_size 171 -#define CoinType_size 107 -#define MultisigRedeemScriptType_size 3741 -#define TxInputType_size 5508 -#define TxOutputType_size 3947 -#define TxOutputBinType_size 534 -#define TransactionType_size 11055 -#define TxRequestDetailsType_size 52 -#define TxRequestSerializedType_size 2132 -#define IdentityType_size 416 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif From 1072369bc4a8df1199ef2fded2d753966def677f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Sep 2017 13:19:03 +0200 Subject: [PATCH 0576/1154] firmware: need extra cast for nanopb call in message.c --- firmware/messages.c | 3 ++- firmware/protob/.gitignore | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/messages.c b/firmware/messages.c index ad89dc688f..d5d2ba553c 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -320,7 +320,8 @@ void msg_read_tiny(const uint8_t *buf, int len) } const pb_field_t *fields = 0; - pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); + // upstream nanopb is missing const qualifier, so we have to cast :-/ + pb_istream_t stream = pb_istream_from_buffer((uint8_t *)buf + 9, msg_size); switch (msg_id) { case MessageType_MessageType_PinMatrixAck: diff --git a/firmware/protob/.gitignore b/firmware/protob/.gitignore index 8d944df5a6..969d878a10 100644 --- a/firmware/protob/.gitignore +++ b/firmware/protob/.gitignore @@ -1,3 +1,6 @@ *.pb *_pb2.py +*.pb.c +*.pb.h +messages_map.h __pycache__/ From 53f5d5c14700bcba9c19219626a2b17dc6b90d7d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Sep 2017 18:19:13 +0200 Subject: [PATCH 0577/1154] u2f: add gandi to known apps --- firmware/u2f_knownapps.h | 9 +++++++++ gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_gandi.png | Bin 0 -> 250 bytes 4 files changed, 12 insertions(+) create mode 100644 gen/bitmaps/u2f_gandi.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 2fda7630ce..3279262c55 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -94,6 +94,15 @@ static const U2FWellKnown u2f_well_known[] = { "FastMail", &bmp_u2f_fastmail }, + { + // https://account.gandi.net/api/u2f/trusted_facets.json + { 0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, + 0x12, 0x89, 0x50, 0x11, 0x39, 0x89, 0xfc, 0x45, + 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, 0x75, 0x60, + 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96 }, + "Gandi", + &bmp_u2f_gandi, + }, { // https://demo.yubico.com { 0x55, 0x67, 0x3b, 0x51, 0x38, 0xcc, 0x90, 0xd3, diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 4ee1a7e9e2..f2e69441da 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -26,6 +26,7 @@ const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_fastmail_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x4f, 0xff, 0xff, 0xf2, 0x67, 0xff, 0xff, 0xe6, 0x73, 0xff, 0xff, 0xce, 0x79, 0xff, 0xff, 0x9e, 0x7c, 0xff, 0xff, 0x3e, 0x7e, 0x7f, 0xfe, 0x7e, 0x7f, 0x3f, 0xfc, 0xfe, 0x7f, 0x9f, 0xf9, 0xfe, 0x7f, 0xcf, 0xf3, 0xfe, 0x7f, 0xe7, 0xe7, 0xfe, 0x7f, 0xf3, 0xcf, 0xfe, 0x7f, 0xf8, 0x1f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_u2f_gandi_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x01, 0x8f, 0xe1, 0x00, 0x03, 0xc7, 0xc3, 0x80, 0x03, 0xe0, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x30, 0x00, 0x00, 0xf0, 0xfc, 0x00, 0x00, 0xf1, 0xfe, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf1, 0xcf, 0x00, 0x00, 0xf0, 0x8f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; @@ -58,6 +59,7 @@ const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; const BITMAP bmp_u2f_fastmail = {32, 32, bmp_u2f_fastmail_data}; +const BITMAP bmp_u2f_gandi = {32, 32, bmp_u2f_gandi_data}; const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index e6e1b0b479..2a348e2e34 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -34,6 +34,7 @@ extern const BITMAP bmp_logo64_empty; extern const BITMAP bmp_u2f_bitbucket; extern const BITMAP bmp_u2f_dropbox; extern const BITMAP bmp_u2f_fastmail; +extern const BITMAP bmp_u2f_gandi; extern const BITMAP bmp_u2f_github; extern const BITMAP bmp_u2f_gitlab; extern const BITMAP bmp_u2f_google; diff --git a/gen/bitmaps/u2f_gandi.png b/gen/bitmaps/u2f_gandi.png new file mode 100644 index 0000000000000000000000000000000000000000..12abe0ff114a8075d60d926035e4f71b01137394 GIT binary patch literal 250 zcmVl}sKSjKh{yvs6Z-vK^GUCCruz_mSPGJnA68?>)Wgxs5+|TS>}@oPLy-~rXzC^* z(*d4Q5u8QKrfCx0AaDk8*{}1CAO=iPdJwO3(Q=LpD^#|ix=P)hV{vK>!Cy;AzF6RiKIsgCw07*qoM6N<$g8VOK A&j0`b literal 0 HcmV?d00001 From b6d53acefcdc6cbd90d1dba2d83c7ec3d3cd6d20 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Sep 2017 20:41:29 +0200 Subject: [PATCH 0578/1154] build: fix missing stuff in travis --- .travis.yml | 6 ++++++ Dockerfile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95eed0db96..b6a26d821e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,10 @@ addons: - build-essential - gcc-arm-none-eabi - libnewlib-arm-none-eabi + - protobuf-compiler + - libprotobuf-dev + - python-protobuf + - python3-protobuf env: global: @@ -20,9 +24,11 @@ env: script: - make -C vendor/libopencm3 lib/stm32/f2 + - make -C vendor/nanopb/generator/proto - make - make -C bootloader - make -C fastflash + - make -C firmware/protob - make -C firmware - make -C demo diff --git a/Dockerfile b/Dockerfile index 9b98775d9c..ae2645f359 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,4 +9,4 @@ RUN apt-get update # install build tools and dependencies RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi -RUN apt-get install protobuf-compiler libprotobuf-dev python-protobuf python3-protobuf +RUN apt-get install -y protobuf-compiler libprotobuf-dev python-protobuf python3-protobuf From 8a6dd3c764c7e6127e57cb9664db2271189b8c18 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Sep 2017 20:48:26 +0200 Subject: [PATCH 0579/1154] build: use python2 for messages_map.py --- .travis.yml | 1 - Dockerfile | 2 +- firmware/protob/.gitignore | 1 + firmware/protob/messages_map.py | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6a26d821e..1f0068b652 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,6 @@ addons: - protobuf-compiler - libprotobuf-dev - python-protobuf - - python3-protobuf env: global: diff --git a/Dockerfile b/Dockerfile index ae2645f359..08213ec00c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,4 +9,4 @@ RUN apt-get update # install build tools and dependencies RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi -RUN apt-get install -y protobuf-compiler libprotobuf-dev python-protobuf python3-protobuf +RUN apt-get install -y protobuf-compiler libprotobuf-dev python-protobuf diff --git a/firmware/protob/.gitignore b/firmware/protob/.gitignore index 969d878a10..8ea827fb73 100644 --- a/firmware/protob/.gitignore +++ b/firmware/protob/.gitignore @@ -2,5 +2,6 @@ *_pb2.py *.pb.c *.pb.h +*.pyc messages_map.h __pycache__/ diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index f727c1a70a..f8a74f0bab 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2 from collections import defaultdict from messages_pb2 import MessageType from types_pb2 import wire_in, wire_out, wire_debug_in, wire_debug_out, wire_tiny, wire_bootloader From 4b8ac90d105ee8ffeb65d7d5d30ccf6e98891f7c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Sep 2017 21:01:59 +0200 Subject: [PATCH 0580/1154] travis: fix build for old protobuf --- .travis.yml | 1 + firmware/protob/messages_map.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1f0068b652..8fc80d9b4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ script: - make - make -C bootloader - make -C fastflash + - sed -i '/, deprecated = true/d' firmware/protob/messages.proto # protobuf 2.5 compatibility :-/ - make -C firmware/protob - make -C firmware - make -C demo diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index f8a74f0bab..78c778b594 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -25,7 +25,7 @@ def handle_message(message, extension): bootloader = options.Extensions[wire_bootloader] tiny = options.Extensions[wire_tiny] and direction == "i" - if options.deprecated: + if getattr(options, 'deprecated', None): return '\t// Message %s is deprecated' % short_name if bootloader: return '\t// Message %s is used in bootloader mode only' % short_name From 4147a914ac2030ef357c30bb9d7e728bed2f378c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 29 Sep 2017 19:46:38 +0100 Subject: [PATCH 0581/1154] Dockerfile: Use multi-line instructions Minimize the number of layers and call apt-get update properly --- Dockerfile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 08213ec00c..ecca657a37 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,11 +2,8 @@ FROM debian:9 -# update repositories - -RUN apt-get update - # install build tools and dependencies -RUN apt-get install -y build-essential git python python-ecdsa gcc-arm-none-eabi -RUN apt-get install -y protobuf-compiler libprotobuf-dev python-protobuf +RUN apt-get update && apt-get install -y \ + build-essential git python python-ecdsa gcc-arm-none-eabi \ + protobuf-compiler libprotobuf-dev python-protobuf From 8983a346d9ea0f5db769cf31e7961102043b18d9 Mon Sep 17 00:00:00 2001 From: Jason Zavaglia Date: Sat, 30 Sep 2017 19:09:11 +1000 Subject: [PATCH 0582/1154] Have coins.h and coins.c generated at build time (#220) --- Makefile.include | 2 +- firmware/.gitignore | 2 ++ firmware/Makefile | 15 +++++++++++++++ firmware/coins-gen.py | 38 +++++++++++++++++++++++--------------- firmware/coins.c | 13 +------------ firmware/coins.h | 7 +------ firmware/coins.json | 1 + firmware/protob/Makefile | 2 +- 8 files changed, 45 insertions(+), 35 deletions(-) create mode 100644 firmware/.gitignore create mode 120000 firmware/coins.json diff --git a/Makefile.include b/Makefile.include index 7bbcb3d825..cd4813fe31 100644 --- a/Makefile.include +++ b/Makefile.include @@ -139,7 +139,7 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP %.small.o: %.c Makefile $(CC) $(CFLAGS) -MMD -o $@ -c $< -clean: +clean:: rm -f $(OBJS) rm -f *.a rm -f *.bin diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000000..248dabf294 --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1,2 @@ +coins_array.h +coins_count.h diff --git a/firmware/Makefile b/firmware/Makefile index 4599627d26..750838826d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -95,3 +95,18 @@ bootloader.o: ../fastflash/bootloader.bin --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_size=__bootloader_size__ \ --rename-section .data=.rodata \ $< $@ + +# ensure header files are generated prior to compiling sources +coins.c crypto.c fsm.c transaction.c: coins_count.h +coins.c: coins_array.h + +################# +# Code Generation +coins_count.h: coins-gen.py coins.json + ./$< count > $@ + +coins_array.h: coins-gen.py coins.json + ./$< array > $@ + +clean:: + rm -f coins_count.h coins_array.h diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 6d78185d17..9535466e52 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -1,10 +1,15 @@ -#!/usr/bin/env python3 -import json +#!/usr/bin/env python2 +from __future__ import print_function +import json, sys -coins_json = json.load(open('../vendor/trezor-common/coins.json', 'r')) +coins_json = json.load(open('coins.json', 'r')) coins_stable, coins_debug = [], [] +if len(sys.argv) != 2 or sys.argv[1] not in ("count", "array"): + print("usage: coins-gen.py [count|array]\n", file=sys.stderr) + sys.exit(1) + def get_fields(coin): return [ @@ -59,20 +64,23 @@ for coin in coins_json: justify_width(coins_stable) justify_width(coins_debug) -for row in coins_stable: - print('\t{' + ' '.join(row) + ' },') +print("// THIS IS A GENERATED FILE - DO NOT HAND EDIT\n\n") -print('#if DEBUG_LINK') +if sys.argv[1] == "array": + for row in coins_stable: + print('\t{' + ' '.join(row) + ' },') -for row in coins_debug: - print('\t{' + ' '.join(row) + ' },') + print('#if DEBUG_LINK') -print('#endif') + for row in coins_debug: + print('\t{' + ' '.join(row) + ' },') -print('-' * 32) + print('#endif') -print('#if DEBUG_LINK') -print('#define COINS_COUNT %d' % (len(coins_stable) + len(coins_debug))) -print('#else') -print('#define COINS_COUNT %d' % (len(coins_stable))) -print('#endif') + +if sys.argv[1] == "count": + print('#if DEBUG_LINK') + print('#define COINS_COUNT %d' % (len(coins_stable) + len(coins_debug))) + print('#else') + print('#define COINS_COUNT %d' % (len(coins_stable))) + print('#endif') diff --git a/firmware/coins.c b/firmware/coins.c index 6fe150906e..f2f69a0d18 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -26,18 +26,7 @@ // filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 // address types > 0xFF represent a two-byte prefix in big-endian order const CoinType coins[COINS_COUNT] = { - {true, "Bitcoin", true, " BTC", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, true, false, 0, }, - {true, "Testnet", true, " TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, true, false, 0, }, - {true, "Bcash", true, " BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, true, 0, }, - {true, "Namecoin", true, " NMC", true, 52, true, 10000000, true, 5, true, "\x19" "Namecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, false, false, 0, }, - {true, "Litecoin", true, " LTC", true, 48, true, 40000000, true, 50, true, "\x19" "Litecoin Signed Message:\n", true, 0x019da462, true, 0x019d9cfe, true, true, false, 0, }, - {true, "Dogecoin", true, " DOGE", true, 30, true, 1000000000, true, 22, true, "\x19" "Dogecoin Signed Message:\n", true, 0x02facafd, true, 0x02fac398, true, false, false, 0, }, - {true, "Dash", true, " DASH", true, 76, true, 100000, true, 16, true, "\x19" "DarkCoin Signed Message:\n", true, 0x02fe52cc, true, 0x02fe52f8, true, false, false, 0, }, - {true, "Zcash", true, " ZEC", true, 7352, true, 1000000, true, 7357, true, "\x16" "Zcash Signed Message:\n", true, 0x0488b21e, true, 0x0488ade4, true, false, false, 0, }, -#if DEBUG_LINK - {true, "Bcash Testnet", true, " TBCH", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, true, 0, }, - {true, "Zcash Testnet", true, " TAZ", true, 7461, true, 10000000, true, 7354, true, "\x16" "Zcash Signed Message:\n", true, 0x043587cf, true, 0x04358394, true, false, false, 0, }, -#endif +#include "coins_array.h" }; const CoinType *coinByName(const char *name) diff --git a/firmware/coins.h b/firmware/coins.h index a00709b63e..a00fa27049 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -21,13 +21,8 @@ #define __COINS_H__ #include "messages.pb.h" -#include "types.pb.h" -#if DEBUG_LINK -#define COINS_COUNT 10 -#else -#define COINS_COUNT 8 -#endif +#include "coins_count.h" _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); diff --git a/firmware/coins.json b/firmware/coins.json new file mode 120000 index 0000000000..a13f2d9c08 --- /dev/null +++ b/firmware/coins.json @@ -0,0 +1 @@ +../vendor/trezor-common/coins.json \ No newline at end of file diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 6897debd11..34a4739bb3 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -13,4 +13,4 @@ messages_map.h: messages_map.py messages_pb2.py types_pb2.py ./$< > $@ clean: - rm -f *.pb *.o *.pb.c *.pb.h *_pb2.py messages_map.h + rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From da1262cf4af87c4a1d43c7dee3161e6d4d299db0 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 29 May 2017 14:57:14 +0100 Subject: [PATCH 0583/1154] vendor: Update trezor-common --- firmware/protob/messages.options | 7 +++++++ firmware/protob/types.options | 34 ++++++++++++++++++++++++++++++++ vendor/trezor-common | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index b42e5efad6..c4c0f06675 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -142,6 +142,13 @@ GetECDHSessionKey.ecdsa_curve_name max_size:32 ECDHSessionKey.session_key max_size:65 +NEMGetAddress.address_n max_count:8 + +NEMAddress.address max_size:41 + +NEMSignedTx.data max_size:2048 +NEMSignedTx.signature max_size:64 + # deprecated SimpleSignTx skip_message:true diff --git a/firmware/protob/types.options b/firmware/protob/types.options index bd56519202..6b7afbb2d7 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -36,3 +36,37 @@ IdentityType.user max_size:64 IdentityType.host max_size:64 IdentityType.port max_size:6 IdentityType.path max_size:256 + +NEMTransactionCommon.address_n max_count:8 +NEMTransactionCommon.signer max_size:32 + +NEMTransfer.recipient max_size:41 +NEMTransfer.public_key max_size:32 +NEMTransfer.payload max_size:256 +NEMTransfer.mosaics max_count:16 + +NEMMosaic.namespace max_size:145 +NEMMosaic.mosaic max_size:33 + +NEMProvisionNamespace.namespace max_size:65 +NEMProvisionNamespace.parent max_size:81 +NEMProvisionNamespace.sink max_size:41 + +NEMMosaicCreation.sink max_size:41 + +NEMMosaicDefinition.name max_size:32 +NEMMosaicDefinition.ticker max_size:16 +NEMMosaicDefinition.namespace max_size:145 +NEMMosaicDefinition.mosaic max_size:33 +NEMMosaicDefinition.levy_address max_size:41 +NEMMosaicDefinition.levy_namespace max_size:145 +NEMMosaicDefinition.levy_mosaic max_size:33 +NEMMosaicDefinition.description max_size:513 +NEMMosaicDefinition.networks max_count:8 + +NEMMosaicSupplyChange.namespace max_size:145 +NEMMosaicSupplyChange.mosaic max_size:33 + +NEMAggregateModification.modifications max_count:16 + +NEMCosignatoryModification.public_key max_size:32 diff --git a/vendor/trezor-common b/vendor/trezor-common index 5f7a1a7a5a..c41f84e221 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 5f7a1a7a5a4311fd71ed113624dd1d0fe9e72ff5 +Subproject commit c41f84e221f0fc370fcad399541f6fff00f717b8 From c331d7e8f04a97908b64bb84bfb25dde61700cea Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 29 May 2017 15:07:13 +0100 Subject: [PATCH 0584/1154] vendor: Update trezor-crypto --- firmware/Makefile | 3 +++ vendor/trezor-crypto | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 750838826d..902ebcc4f0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -61,6 +61,8 @@ OBJS += ../vendor/trezor-crypto/aes/aeskey.o OBJS += ../vendor/trezor-crypto/aes/aestab.o OBJS += ../vendor/trezor-crypto/aes/aes_modes.o +OBJS += ../vendor/trezor-crypto/nem.o + OBJS += ../vendor/trezor-qrenc/qr_encode.o # OBJS += protob/pb_common.o @@ -88,6 +90,7 @@ CFLAGS += -DDEBUG_LINK=$(DEBUG_LINK) CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DUSE_ETHEREUM=1 +CFLAGS += -DUSE_NEM=1 bootloader.o: ../fastflash/bootloader.bin $(OBJCOPY) -I binary -O elf32-littlearm -B arm \ diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 9dfc6a4477..9c91985674 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 9dfc6a4477a7ac344ab630441e0b76d5d623a313 +Subproject commit 9c919856747a6a519e5a553cc9b67f1c408337af From 3057f788372e5bafbc34679cb23e4336f2bc0462 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 29 May 2017 17:07:55 +0100 Subject: [PATCH 0585/1154] fsm: Add NEMGetAddress --- firmware/fsm.c | 40 ++++++++++++++++++++++++++++++++++++++++ firmware/fsm.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index f460cd5956..f05e952781 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -50,6 +50,7 @@ #include "secp256k1.h" #include #include "ethereum.h" +#include "nem.h" #include "gettext.h" // message methods @@ -1104,6 +1105,45 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg) layoutHome(); } +void fsm_msgNEMGetAddress(NEMGetAddress *msg) +{ + if (!msg->has_network) { + msg->network = NEM_NETWORK_MAINNET; + } + + const char *network; + CHECK_PARAM((network = nem_network_name(msg->network)), _("Invalid NEM network")); + + CHECK_INITIALIZED + CHECK_PIN + + RESP_INIT(NEMAddress); + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + if (!hdnode_get_nem_address(node, msg->network, resp->address)) + return; + + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, network, sizeof(desc)); + strlcat(desc, ":", sizeof(desc)); + + bool qrcode = false; + for (;;) { + layoutAddress(resp->address, desc, qrcode); + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + break; + } + qrcode = !qrcode; + } + } + + msg_write(MessageType_MessageType_NEMAddress, resp); + layoutHome(); +} + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm.h b/firmware/fsm.h index cbd4712c44..e127b386dc 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -66,6 +66,8 @@ void fsm_msgEthereumTxAck(EthereumTxAck *msg); void fsm_msgEthereumSignMessage(EthereumSignMessage *msg); void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); +void fsm_msgNEMGetAddress(NEMGetAddress *msg); + // debug message functions #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); From 19033a459d60e015b9cca80f77415221ad59453d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 30 May 2017 17:41:02 +0100 Subject: [PATCH 0586/1154] fsm: Add NEMSignTx --- firmware/Makefile | 1 + firmware/fsm.c | 41 +++++++++ firmware/fsm.h | 1 + firmware/layout2.c | 98 +++++++++++++++++++++ firmware/layout2.h | 5 ++ firmware/nem2.c | 212 +++++++++++++++++++++++++++++++++++++++++++++ firmware/nem2.h | 36 ++++++++ 7 files changed, 394 insertions(+) create mode 100644 firmware/nem2.c create mode 100644 firmware/nem2.h diff --git a/firmware/Makefile b/firmware/Makefile index 902ebcc4f0..b7d7372702 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -24,6 +24,7 @@ OBJS += signing.o OBJS += crypto.o OBJS += ethereum.o OBJS += ethereum_tokens.o +OBJS += nem2.o OBJS += debug.o diff --git a/firmware/fsm.c b/firmware/fsm.c index f05e952781..15395425ed 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -51,6 +51,7 @@ #include #include "ethereum.h" #include "nem.h" +#include "nem2.h" #include "gettext.h" // message methods @@ -1144,6 +1145,46 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) layoutHome(); } +void fsm_msgNEMSignTx(NEMSignTx *msg) { + CHECK_PARAM(msg->has_transaction, _("No common provided")); + CHECK_PARAM(msg->has_transfer, _("No transaction provided")); + + const char *reason; + CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction)), reason); + CHECK_PARAM(!(reason = nem_validate_transfer(&msg->transfer, msg->transaction.network)), reason); + + CHECK_INITIALIZED + CHECK_PIN + + if (!nem_askTransfer(&msg->transaction, &msg->transfer)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + RESP_INIT(NEMSignedTx); + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); + if (!node) return; + + nem_transaction_ctx context; + nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); + + if (!nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { + layoutHome(); + return; + } + + resp->has_data = true; + resp->data.size = nem_transaction_end(&context, node->private_key, resp->signature.bytes); + + resp->has_signature = true; + resp->signature.size = sizeof(ed25519_signature); + + msg_write(MessageType_MessageType_NEMSignedTx, resp); + layoutHome(); +} + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm.h b/firmware/fsm.h index e127b386dc..3768e12996 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -67,6 +67,7 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage *msg); void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); void fsm_msgNEMGetAddress(NEMGetAddress *msg); +void fsm_msgNEMSignTx(NEMSignTx *msg); // debug message functions #if DEBUG_LINK diff --git a/firmware/layout2.c b/firmware/layout2.c index b26c3be982..ccd9eda6c0 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -30,6 +30,8 @@ #include "qr_encode.h" #include "timer.h" #include "bignum.h" +#include "nem.h" +#include "secp256k1.h" #include "gettext.h" #define BITCOIN_DIVISIBILITY (8) @@ -465,3 +467,99 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico } layoutDialog(appicon, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); } + +static inline void nemFormatAmount(bignum256 *amnt, uint64_t quantity, int divisibility, const bignum256 *mul, const char *ticker, char *str_out, size_t size) { + bn_read_uint64(quantity, amnt); + + if (mul) { + bn_multiply(mul, amnt, &secp256k1.prime); + bn_format(amnt, NULL, ticker, divisibility + NEM_XEM_DIVISIBILITY, str_out, size); + } else { + bn_format(amnt, NULL, ticker, divisibility, str_out, size); + } +} + +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee) { + char str_out[32], str_fee[32]; + bignum256 amnt; + + nemFormatAmount(&amnt, quantity, NEM_XEM_DIVISIBILITY, mul, " " NEM_XEM_TICKER, str_out, sizeof(str_out)); + + bn_read_uint64(fee, &amnt); + bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee, sizeof(str_fee)); + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + _("Confirm transfer of"), + str_out, + _("and network fee of"), + str_fee, + NULL, + NULL); +} + +void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul) { + char mosaic_name[256]; + strlcpy(mosaic_name, namespace, sizeof(mosaic_name)); + strlcat(mosaic_name, ".", sizeof(mosaic_name)); + strlcat(mosaic_name, mosaic, sizeof(mosaic_name)); + + char str_out[32]; + bignum256 amnt; + nemFormatAmount(&amnt, quantity, 0, mul, NULL, str_out, sizeof(str_out)); + + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("I take the risk"), + _("Unknown Mosaic"), + _("Confirm transfer of"), + str_out, + _("raw units of"), + mosaic_name, + NULL, + NULL); +} + +void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted) { + if (payload[0] == 0xFE) { + char encoded[(length - 1) * 2 + 1]; + data2hex(&payload[1], length - 1, encoded); + + const char **str = split_message((uint8_t *) encoded, sizeof(encoded) - 1, 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), + str[0], str[1], str[2], str[3], NULL, NULL); + } else { + const char **str = split_message(payload, length, 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + encrypted ? _("Encrypted message") : _("Unencrypted message"), + str[0], str[1], str[2], str[3], NULL, NULL); + } +} + +void layoutNEMTransferTo(const char *desc, const char *address) { + static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(first_third, address, sizeof(first_third)); + + static char second_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third)); + + const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + desc, + _("Confirm transfer to"), + first_third, + second_third, + third_third, + NULL, + NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 643aa4624b..6364e05416 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -23,6 +23,7 @@ #include "layout.h" #include "types.pb.h" #include "bitmaps.h" +#include "bignum.h" extern void *layoutLast; @@ -46,5 +47,9 @@ void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee); +void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul); +void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); +void layoutNEMTransferTo(const char *desc, const char *address); #endif diff --git a/firmware/nem2.c b/firmware/nem2.c new file mode 100644 index 0000000000..62d92549ff --- /dev/null +++ b/firmware/nem2.c @@ -0,0 +1,212 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "nem2.h" + +#include "aes.h" +#include "fsm.h" +#include "gettext.h" +#include "layout2.h" +#include "protect.h" +#include "rng.h" + +const char *nem_validate_common(NEMTransactionCommon *common) { + if (!common->has_network) { + common->has_network = true; + common->network = NEM_NETWORK_MAINNET; + } + + if (nem_network_name(common->network) == NULL) return _("Invalid NEM network"); + if (!common->has_timestamp) return _("No timestamp provided"); + if (!common->has_fee) return _("No fee provided"); + if (!common->has_deadline) return _("No deadline provided"); + + return NULL; +} + +const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { + if (!transfer->has_recipient) return _("No recipient provided"); + if (!transfer->has_amount) return _("No amount provided"); + if (transfer->has_public_key && transfer->public_key.size != 32) return _("Invalid recipient public key"); + + if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); + + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; + + if (!mosaic->has_namespace) return "No mosaic namespace provided"; + if (!mosaic->has_mosaic) return "No mosaic name provided"; + if (!mosaic->has_quantity) return "No mosaic quantity provided"; + } + + return NULL; +} + + +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer) { + const char *network = nem_network_name(common->network); + if (network == NULL) { + return false; + } + + + if (transfer->mosaics_count) { + bool done[transfer->mosaics_count]; + memset(done, 0, sizeof(done)); + + uint64_t quantity[transfer->mosaics_count]; + uint64_t *xemQuantity = NULL; + + bignum256 mul; + bn_read_uint64(transfer->amount, &mul); + + for (size_t i = 0; i < transfer->mosaics_count; i++) { + // Skip duplicate mosaics + if (done[i]) continue; + + const NEMMosaic *mosaic = &transfer->mosaics[i]; + + // XEM is treated specially + if (strcmp(mosaic->namespace, "nem") == 0 && strcmp(mosaic->mosaic, "xem") == 0) { + done[i] = true; + xemQuantity = &quantity[i]; + } + + quantity[i] = mosaic->quantity; + for (size_t j = i + 1; j < transfer->mosaics_count; j++) { + const NEMMosaic *new_mosaic = &transfer->mosaics[j]; + + if (strcmp(mosaic->namespace, new_mosaic->namespace) == 0 && strcmp(mosaic->mosaic, new_mosaic->mosaic) == 0) { + // Duplicate mosaics are merged into one + done[i] = true; + quantity[i] += transfer->mosaics[j].quantity; + } + } + } + + layoutNEMTransferXEM(network, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + for (size_t i = 0; i < transfer->mosaics_count; i++) { + // Skip special or duplicate mosaics + if (done[i]) continue; + + const NEMMosaic *mosaic = &transfer->mosaics[i]; + + layoutNEMTransferMosaic(mosaic->namespace, mosaic->mosaic, quantity[i], &mul); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + } else { + layoutNEMTransferXEM(network, transfer->amount, NULL, common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + if (transfer->has_payload) { + layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, transfer->has_public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + layoutNEMTransferTo(network, transfer->recipient); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } + + return true; +} + +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) { + static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; + + const uint8_t *payload = transfer->payload.bytes; + size_t size = transfer->payload.size; + + if (transfer->has_public_key) { + if (node == NULL) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); + return false; + } + + random_buffer(encrypted, NEM_SALT_SIZE + AES_BLOCK_SIZE); + + // hdnode_nem_encrypt mutates the IV + uint8_t iv[AES_BLOCK_SIZE]; + memcpy(iv, &encrypted[NEM_SALT_SIZE], AES_BLOCK_SIZE); + + const uint8_t *salt = encrypted; + uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE]; + + bool ret = hdnode_nem_encrypt(node, + transfer->public_key.bytes, + iv, + salt, + payload, + size, + buffer); + + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload")); + return false; + } + + payload = encrypted; + size = NEM_ENCRYPTED_PAYLOAD_SIZE(size); + } + + bool ret = nem_transaction_create_transfer(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + transfer->recipient, + transfer->amount, + payload, + size, + transfer->has_public_key, + transfer->mosaics_count); + + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); + return false; + } + + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; + + ret = nem_transaction_write_mosaic(context, + mosaic->namespace, + mosaic->mosaic, + mosaic->quantity); + + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to attach mosaics"); + return false; + } + } + + return true; +} diff --git a/firmware/nem2.h b/firmware/nem2.h new file mode 100644 index 0000000000..ed394fdab7 --- /dev/null +++ b/firmware/nem2.h @@ -0,0 +1,36 @@ +/* + * This file is part of the TREZOR project. + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __NEM2_H__ +#define __NEM2_H__ + +#include "nem.h" + +#include "messages.pb.h" +#include "types.pb.h" + +#include + +const char *nem_validate_common(NEMTransactionCommon *common); +const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); + +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); + +#endif From 563723a55ffa1c5533dd1f6f2ad8056aa815ece5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 1 Jul 2017 14:38:04 +0100 Subject: [PATCH 0587/1154] nem2: Handle multisig transactions --- firmware/fsm.c | 54 +++++++++++++++++++-- firmware/layout2.c | 45 ++++++++++++++++++ firmware/layout2.h | 3 +- firmware/nem2.c | 114 +++++++++++++++++++++++++++++++++++++-------- firmware/nem2.h | 10 +++- 5 files changed, 198 insertions(+), 28 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 15395425ed..fff56caed7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1149,14 +1149,39 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { CHECK_PARAM(msg->has_transaction, _("No common provided")); CHECK_PARAM(msg->has_transfer, _("No transaction provided")); + bool cosigning = msg->has_cosigning && msg->cosigning; + const char *reason; - CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction)), reason); + CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction, false)), reason); CHECK_PARAM(!(reason = nem_validate_transfer(&msg->transfer, msg->transaction.network)), reason); + if (msg->has_multisig) { + CHECK_PARAM(!(reason = nem_validate_common(&msg->multisig, true)), reason); + + CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); + } else { + CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); + } + CHECK_INITIALIZED CHECK_PIN - if (!nem_askTransfer(&msg->transaction, &msg->transfer)) { + const char *network = nem_network_name(msg->transaction.network); + + if (msg->has_multisig) { + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); + + if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + } + + const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + + if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; @@ -1167,12 +1192,31 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); if (!node) return; + hdnode_fill_public_key(node); + nem_transaction_ctx context; nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); - if (!nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { - layoutHome(); - return; + if (msg->has_multisig) { + uint8_t buffer[sizeof(resp->data.bytes)]; + + nem_transaction_ctx inner; + nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer)); + + if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { + layoutHome(); + return; + } + + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { + layoutHome(); + return; + } + } else { + if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/layout2.c b/firmware/layout2.c index ccd9eda6c0..d6e50c4ce8 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -479,6 +479,27 @@ static inline void nemFormatAmount(bignum256 *amnt, uint64_t quantity, int divis } } +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6) { + static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(first_third, address, sizeof(first_third)); + + static char second_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third)); + + const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; + + layoutDialogSwipe(icon, + btnNo, + btnYes, + desc, + line1, + first_third, + second_third, + third_third, + line5, + line6); +} + void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee) { char str_out[32], str_fee[32]; bignum256 amnt; @@ -499,6 +520,30 @@ void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 * NULL); } +void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2) { + char str_fee1[32], str_fee2[32]; + bignum256 amnt; + + bn_read_uint64(fee1, &amnt); + bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee1, sizeof(str_fee1)); + + if (fee2_desc) { + bn_read_uint64(fee2, &amnt); + bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee2, sizeof(str_fee2)); + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + confirm ? _("Confirm") : _("Next"), + desc, + fee1_desc, + str_fee1, + fee2_desc, + fee2_desc ? str_fee2 : NULL, + NULL, + NULL); +} + void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul) { char mosaic_name[256]; strlcpy(mosaic_name, namespace, sizeof(mosaic_name)); diff --git a/firmware/layout2.h b/firmware/layout2.h index 6364e05416..aa6675f0ad 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -47,9 +47,10 @@ void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6); void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee); +void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); -void layoutNEMTransferTo(const char *desc, const char *address); #endif diff --git a/firmware/nem2.c b/firmware/nem2.c index 62d92549ff..6d9505ac3e 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -26,16 +26,35 @@ #include "protect.h" #include "rng.h" -const char *nem_validate_common(NEMTransactionCommon *common) { +const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { if (!common->has_network) { common->has_network = true; common->network = NEM_NETWORK_MAINNET; } - if (nem_network_name(common->network) == NULL) return _("Invalid NEM network"); - if (!common->has_timestamp) return _("No timestamp provided"); - if (!common->has_fee) return _("No fee provided"); - if (!common->has_deadline) return _("No deadline provided"); + if (nem_network_name(common->network) == NULL) { + return inner ? _("Invalid NEM network in inner transaction") : _("Invalid NEM network"); + } + + if (!common->has_timestamp) { + return inner ? _("No timestamp provided in inner transaction") : _("No timestamp provided"); + } + + if (!common->has_fee) { + return inner ? _("No fee provided in inner transaction") : _("No fee provided"); + } + + if (!common->has_deadline) { + return inner ? _("No deadline provided in inner transaction") : _("No deadline provided"); + } + + if (inner != common->has_signer) { + return inner ? _("No signer provided in inner transaction") : _("Signer not allowed in outer transaction"); + } + + if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) { + return _("Invalid signer public key in inner transaction"); + } return NULL; } @@ -43,29 +62,26 @@ const char *nem_validate_common(NEMTransactionCommon *common) { const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { if (!transfer->has_recipient) return _("No recipient provided"); if (!transfer->has_amount) return _("No amount provided"); - if (transfer->has_public_key && transfer->public_key.size != 32) return _("Invalid recipient public key"); + + if (transfer->has_public_key && transfer->public_key.size != sizeof(ed25519_public_key)) { + return _("Invalid recipient public key"); + } if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); for (size_t i = 0; i < transfer->mosaics_count; i++) { const NEMMosaic *mosaic = &transfer->mosaics[i]; - if (!mosaic->has_namespace) return "No mosaic namespace provided"; - if (!mosaic->has_mosaic) return "No mosaic name provided"; - if (!mosaic->has_quantity) return "No mosaic quantity provided"; + if (!mosaic->has_namespace) return _("No mosaic namespace provided"); + if (!mosaic->has_mosaic) return _("No mosaic name provided"); + if (!mosaic->has_quantity) return _("No mosaic quantity provided"); } return NULL; } -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer) { - const char *network = nem_network_name(common->network); - if (network == NULL) { - return false; - } - - +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { bool done[transfer->mosaics_count]; memset(done, 0, sizeof(done)); @@ -100,7 +116,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran } } - layoutNEMTransferXEM(network, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee); + layoutNEMTransferXEM(desc, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -117,7 +133,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran } } } else { - layoutNEMTransferXEM(network, transfer->amount, NULL, common->fee); + layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -130,7 +146,14 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran } } - layoutNEMTransferTo(network, transfer->recipient); + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + desc, + _("Confirm transfer to"), + transfer->recipient, + NULL, + NULL); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } @@ -203,10 +226,61 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM mosaic->quantity); if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Failed to attach mosaics"); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics")); return false; } } return true; } + +bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), + address, + NULL, + NULL); + + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); + + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + return true; +} + +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { + bool ret; + if (cosigning) { + ret = nem_transaction_create_multisig_signature(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + inner); + } else { + ret = nem_transaction_create_multisig(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + inner); + } + + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); + return false; + } + + return true; +} diff --git a/firmware/nem2.h b/firmware/nem2.h index ed394fdab7..0c87fe7a18 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -27,10 +27,16 @@ #include -const char *nem_validate_common(NEMTransactionCommon *common); +const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_askTransaction(const char *desc, const NEMTransactionCommon *common, const NEMSignTx *msg); +bool nem_fsmTransaction(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMSignTx *msg); + +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); + #endif From b559e5fb6dfaccdbf55f21ac98092d23efadd431 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 16 Jul 2017 20:54:58 +0100 Subject: [PATCH 0588/1154] fsm: Add NEM_CHECK_PARAM macros --- firmware/fsm.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index fff56caed7..c98ce57ac9 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1146,17 +1146,24 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) } void fsm_msgNEMSignTx(NEMSignTx *msg) { + const char *reason; + +#define NEM_CHECK_PARAM(s) CHECK_PARAM( (reason = (s)) == NULL, reason) +#define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) + CHECK_PARAM(msg->has_transaction, _("No common provided")); - CHECK_PARAM(msg->has_transfer, _("No transaction provided")); + + // Ensure exactly one transaction is provided + unsigned int provided = msg->has_transfer; + CHECK_PARAM(provided != 0, _("No transaction provided")); + CHECK_PARAM(provided == 1, _("More than one transaction provided")); + + NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); + NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); bool cosigning = msg->has_cosigning && msg->cosigning; - - const char *reason; - CHECK_PARAM(!(reason = nem_validate_common(&msg->transaction, false)), reason); - CHECK_PARAM(!(reason = nem_validate_transfer(&msg->transfer, msg->transaction.network)), reason); - if (msg->has_multisig) { - CHECK_PARAM(!(reason = nem_validate_common(&msg->multisig, true)), reason); + NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); } else { From 4a55dd89e66ffc4e27a580aad1d3ef1919667b94 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 17 Jul 2017 20:23:20 +0100 Subject: [PATCH 0589/1154] nem2: Handle Provision Namespace transactions --- firmware/fsm.c | 19 ++++++++++++++++++- firmware/nem2.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ firmware/nem2.h | 4 ++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index c98ce57ac9..bff8740469 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1154,12 +1154,13 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { CHECK_PARAM(msg->has_transaction, _("No common provided")); // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer; + unsigned int provided = msg->has_transfer + msg->has_provision_namespace; CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided")); NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); bool cosigning = msg->has_cosigning && msg->cosigning; if (msg->has_multisig) { @@ -1194,6 +1195,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + RESP_INIT(NEMSignedTx); HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); @@ -1215,6 +1222,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&inner, &msg->multisig, &msg->provision_namespace)) { + layoutHome(); + return; + } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { layoutHome(); return; @@ -1224,6 +1236,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); return; } + + if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&context, &msg->transaction, &msg->provision_namespace)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/nem2.c b/firmware/nem2.c index 6d9505ac3e..3f7336b978 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -80,6 +80,15 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) return NULL; } +const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network) { + if (!provision_namespace->has_namespace) return _("No namespace provided"); + if (!provision_namespace->has_sink) return _("No rental sink provided"); + if (!provision_namespace->has_fee) return _("No rental sink fee provided"); + + if (!nem_validate_address(provision_namespace->sink, network)) return _("Invalid rental sink address"); + + return NULL; +} bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { @@ -234,6 +243,42 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM return true; } +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { + layoutDialog(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + _("Create namespace"), + provision_namespace->namespace, + provision_namespace->has_parent ? _("under namespace") : NULL, + provision_namespace->has_parent ? provision_namespace->parent : NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), provision_namespace->fee, _("and network fee of"), common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } + + return true; +} + +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) { + return nem_transaction_create_provision_namespace(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + provision_namespace->namespace, + provision_namespace->has_parent ? provision_namespace->parent : NULL, + provision_namespace->sink, + provision_namespace->fee); +} + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { layoutNEMDialog(&bmp_icon_question, _("Cancel"), diff --git a/firmware/nem2.h b/firmware/nem2.h index 0c87fe7a18..db73380f90 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -29,6 +29,7 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); +const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); bool nem_askTransaction(const char *desc, const NEMTransactionCommon *common, const NEMSignTx *msg); bool nem_fsmTransaction(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMSignTx *msg); @@ -36,6 +37,9 @@ bool nem_fsmTransaction(nem_transaction_ctx *context, const HDNode *node, const bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); From 8dbd6182fb25eb87d8dc8f95468779cb48a2c3fe Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 20 Jul 2017 22:58:19 +0100 Subject: [PATCH 0590/1154] nem_mosaics: Initial commit --- firmware/Makefile | 1 + firmware/layout2.c | 81 +++++++++------------ firmware/layout2.h | 8 ++- firmware/nem2.c | 147 ++++++++++++++++++++++++++++++-------- firmware/nem2.h | 9 +++ firmware/nem_mosaics.c | 16 +++++ firmware/nem_mosaics.h | 13 ++++ firmware/nem_mosaics.json | 8 +++ firmware/nem_mosaics.py | 95 ++++++++++++++++++++++++ 9 files changed, 297 insertions(+), 81 deletions(-) create mode 100644 firmware/nem_mosaics.c create mode 100644 firmware/nem_mosaics.h create mode 100644 firmware/nem_mosaics.json create mode 100755 firmware/nem_mosaics.py diff --git a/firmware/Makefile b/firmware/Makefile index b7d7372702..99422c4417 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -25,6 +25,7 @@ OBJS += crypto.o OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o +OBJS += nem_mosaics.o OBJS += debug.o diff --git a/firmware/layout2.c b/firmware/layout2.c index d6e50c4ce8..9190eb9f8b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -30,8 +30,8 @@ #include "qr_encode.h" #include "timer.h" #include "bignum.h" -#include "nem.h" #include "secp256k1.h" +#include "nem2.h" #include "gettext.h" #define BITCOIN_DIVISIBILITY (8) @@ -468,18 +468,7 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico layoutDialog(appicon, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); } -static inline void nemFormatAmount(bignum256 *amnt, uint64_t quantity, int divisibility, const bignum256 *mul, const char *ticker, char *str_out, size_t size) { - bn_read_uint64(quantity, amnt); - - if (mul) { - bn_multiply(mul, amnt, &secp256k1.prime); - bn_format(amnt, NULL, ticker, divisibility + NEM_XEM_DIVISIBILITY, str_out, size); - } else { - bn_format(amnt, NULL, ticker, divisibility, str_out, size); - } -} - -void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6) { +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address) { static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; strlcpy(first_third, address, sizeof(first_third)); @@ -496,18 +485,16 @@ void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, first_third, second_third, third_third, - line5, - line6); + NULL, + NULL); } -void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee) { +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee) { char str_out[32], str_fee[32]; - bignum256 amnt; - nemFormatAmount(&amnt, quantity, NEM_XEM_DIVISIBILITY, mul, " " NEM_XEM_TICKER, str_out, sizeof(str_out)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier, str_out, sizeof(str_out)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee, sizeof(str_fee)); - bn_read_uint64(fee, &amnt); - bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -522,14 +509,11 @@ void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 * void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2) { char str_fee1[32], str_fee2[32]; - bignum256 amnt; - bn_read_uint64(fee1, &amnt); - bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee1, sizeof(str_fee1)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee1, NULL, str_fee1, sizeof(str_fee1)); if (fee2_desc) { - bn_read_uint64(fee2, &amnt); - bn_format(&amnt, NULL, " " NEM_XEM_TICKER, NEM_XEM_DIVISIBILITY, str_fee2, sizeof(str_fee2)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2, sizeof(str_fee2)); } layoutDialogSwipe(&bmp_icon_question, @@ -544,15 +528,35 @@ void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, NULL); } -void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul) { +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier) { + char str_out[32], str_levy[32]; + + nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); + + if (definition->has_levy) { + nem_mosaicFormatLevy(definition, quantity, multiplier, str_levy, sizeof(str_levy)); + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + definition->has_name ? definition->name : _("Mosaic"), + _("Confirm transfer of"), + str_out, + definition->has_levy ? _("and levy of") : NULL, + definition->has_levy ? str_levy : NULL, + NULL, + NULL); +} + +void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier) { char mosaic_name[256]; strlcpy(mosaic_name, namespace, sizeof(mosaic_name)); strlcat(mosaic_name, ".", sizeof(mosaic_name)); strlcat(mosaic_name, mosaic, sizeof(mosaic_name)); char str_out[32]; - bignum256 amnt; - nemFormatAmount(&amnt, quantity, 0, mul, NULL, str_out, sizeof(str_out)); + nem_mosaicFormatAmount(NULL, quantity, multiplier, str_out, sizeof(str_out)); char *decimal = strchr(str_out, '.'); if (decimal != NULL) { @@ -587,24 +591,3 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encryp str[0], str[1], str[2], str[3], NULL, NULL); } } - -void layoutNEMTransferTo(const char *desc, const char *address) { - static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; - strlcpy(first_third, address, sizeof(first_third)); - - static char second_third[NEM_ADDRESS_SIZE / 3 + 1]; - strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third)); - - const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; - - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - desc, - _("Confirm transfer to"), - first_third, - second_third, - third_third, - NULL, - NULL); -} diff --git a/firmware/layout2.h b/firmware/layout2.h index aa6675f0ad..86b02ffe7b 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -47,10 +47,12 @@ void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); -void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address, const char *line5, const char *line6); -void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *mul, uint64_t fee); + +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); -void layoutNEMTransferMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *mul); +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier); +void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); #endif diff --git a/firmware/nem2.c b/firmware/nem2.c index 3f7336b978..48f8f22e4a 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -25,6 +25,9 @@ #include "layout2.h" #include "protect.h" #include "rng.h" +#include "secp256k1.h" + +static void format_amount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, const bignum256 *multiplier2, int divisor, char *str_out, size_t size); const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { if (!common->has_network) { @@ -92,51 +95,61 @@ const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provis bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { - bool done[transfer->mosaics_count]; - memset(done, 0, sizeof(done)); + struct { + bool skip; + uint64_t quantity; + const NEMMosaicDefinition *definition; + } mosaics[transfer->mosaics_count], *xem = NULL; - uint64_t quantity[transfer->mosaics_count]; - uint64_t *xemQuantity = NULL; - - bignum256 mul; - bn_read_uint64(transfer->amount, &mul); + memset(mosaics, 0, sizeof(mosaics)); for (size_t i = 0; i < transfer->mosaics_count; i++) { // Skip duplicate mosaics - if (done[i]) continue; + if (mosaics[i].skip) continue; const NEMMosaic *mosaic = &transfer->mosaics[i]; - // XEM is treated specially - if (strcmp(mosaic->namespace, "nem") == 0 && strcmp(mosaic->mosaic, "xem") == 0) { - done[i] = true; - xemQuantity = &quantity[i]; + // XEM is displayed separately + if ((mosaics[i].definition = nem_mosaicByName(mosaic->namespace, mosaic->mosaic))) { + if (mosaics[i].definition == NEM_MOSAIC_DEFINITION_XEM) { + // Do not display as a mosaic + mosaics[i].skip = true; + xem = &mosaics[i]; + } } - quantity[i] = mosaic->quantity; + mosaics[i].quantity = mosaic->quantity; for (size_t j = i + 1; j < transfer->mosaics_count; j++) { const NEMMosaic *new_mosaic = &transfer->mosaics[j]; - if (strcmp(mosaic->namespace, new_mosaic->namespace) == 0 && strcmp(mosaic->mosaic, new_mosaic->mosaic) == 0) { - // Duplicate mosaics are merged into one - done[i] = true; - quantity[i] += transfer->mosaics[j].quantity; + if (nem_mosaicMatches(mosaics[i].definition, new_mosaic->namespace, new_mosaic->mosaic)) { + // Merge duplicate mosaics + mosaics[j].skip = true; + mosaics[i].quantity += new_mosaic->quantity; } } } - layoutNEMTransferXEM(desc, xemQuantity == NULL ? 0 : *xemQuantity, &mul, common->fee); + bignum256 multiplier; + bn_read_uint64(transfer->amount, &multiplier); + + layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } for (size_t i = 0; i < transfer->mosaics_count; i++) { - // Skip special or duplicate mosaics - if (done[i]) continue; + // Skip duplicate mosaics or XEM + if (mosaics[i].skip) continue; const NEMMosaic *mosaic = &transfer->mosaics[i]; - layoutNEMTransferMosaic(mosaic->namespace, mosaic->mosaic, quantity[i], &mul); + if (mosaics[i].definition) { + layoutNEMTransferMosaic(mosaics[i].definition, mosaics[i].quantity, &multiplier); + } else { + layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaics[i].quantity, &multiplier); + } + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -160,9 +173,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran _("Confirm"), desc, _("Confirm transfer to"), - transfer->recipient, - NULL, - NULL); + transfer->recipient); if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } @@ -285,16 +296,12 @@ bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint _("Next"), desc, cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), - address, - NULL, - NULL); - + address); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -329,3 +336,85 @@ bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *c return true; } + +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic) { + for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { + const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; + + if (nem_mosaicMatches(definition, namespace, mosaic)) { + return definition; + } + } + + return NULL; +} + +void format_amount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, const bignum256 *multiplier2, int divisor, char *str_out, size_t size) { + uint32_t divisibility = definition && definition->has_divisibility ? definition->divisibility : 0; + const char *ticker = definition && definition->has_ticker ? definition->ticker : NULL; + + bignum256 amnt; + bn_read_uint64(quantity, &amnt); + + if (multiplier2) { + bn_multiply(multiplier2, &amnt, &secp256k1.prime); + } + + // Do not use prefix/suffix with bn_format, it messes with the truncation code + if (multiplier) { + bn_multiply(multiplier, &amnt, &secp256k1.prime); + divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility; + } + + // bn_format(amnt / (10 ^ divisor), divisibility) + bn_format(&amnt, NULL, NULL, divisibility + divisor, str_out, size); + + // Truncate as if we called bn_format with (divisibility) instead of (divisibility + divisor) + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + const char *terminator = strchr(str_out, '\0'); + + if (divisibility == 0) { + // Truncate as an integer + *decimal = '\0'; + } else { + char *end = decimal + divisibility + 1; + if (end < terminator) { + *end = '\0'; + } + } + } + + if (ticker) { + strlcat(str_out, " ", size); + strlcat(str_out, ticker, size); + } +} + +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { + format_amount(definition, quantity, multiplier, NULL, 0, str_out, size); +} + +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { + bignum256 multiplier2; + + if (!definition->has_levy || !definition->has_fee) { + return false; + } + + switch (definition->levy) { + case NEMMosaicLevy_MosaicLevy_Absolute: + format_amount(definition, definition->fee, NULL, NULL, 0, str_out, size); + break; + + case NEMMosaicLevy_MosaicLevy_Percentile: + bn_read_uint64(definition->fee, &multiplier2); + format_amount(definition, quantity, multiplier, &multiplier2, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); + break; + + default: + return false; + } + + return true; +} diff --git a/firmware/nem2.h b/firmware/nem2.h index db73380f90..dc3f3721d1 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -21,6 +21,7 @@ #define __NEM2_H__ #include "nem.h" +#include "nem_mosaics.h" #include "messages.pb.h" #include "types.pb.h" @@ -43,4 +44,12 @@ bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactio bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic); +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); + +static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic) { + return strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0; +} + #endif diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c new file mode 100644 index 0000000000..d9faea3a74 --- /dev/null +++ b/firmware/nem_mosaics.c @@ -0,0 +1,16 @@ +// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! + +#include "nem_mosaics.h" + +const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {{ + .has_ticker = true, + .ticker = " XEM", + .has_namespace = true, + .namespace = "nem", + .has_mosaic = true, + .mosaic = "xem", + .has_divisibility = true, + .divisibility = 6, +}}; + +const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h new file mode 100644 index 0000000000..5ce599ed6f --- /dev/null +++ b/firmware/nem_mosaics.h @@ -0,0 +1,13 @@ +// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! + +#ifndef __NEM_MOSAICS_H__ +#define __NEM_MOSAICS_H__ + +#include "types.pb.h" + +#define NEM_MOSAIC_DEFINITIONS_COUNT (1) + +extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; +extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; + +#endif diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json new file mode 100644 index 0000000000..a5432a417c --- /dev/null +++ b/firmware/nem_mosaics.json @@ -0,0 +1,8 @@ +[ + { + "ticker": " XEM", + "namespace": "nem", + "mosaic": "xem", + "divisibility": 6 + } +] diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py new file mode 100755 index 0000000000..243568958c --- /dev/null +++ b/firmware/nem_mosaics.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +import json, os +from google.protobuf import json_format +from itertools import chain +import protob.types_pb2 as types + +HEADER_TEMPLATE = """ +// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! + +#ifndef __NEM_MOSAICS_H__ +#define __NEM_MOSAICS_H__ + +#include "types.pb.h" + +#define NEM_MOSAIC_DEFINITIONS_COUNT ({count}) + +extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; +extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; + +#endif +""".lstrip() + +CODE_TEMPLATE = """ +// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! + +#include "nem_mosaics.h" + +const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {code}; + +const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; +""".lstrip() + +def format_primitive(value): + if type(value) is bool: + return ("false", "true")[value] + elif type(value) in (int, float): + return str(value) + elif type(value) is str: + return json.dumps(value) + elif type(value) is list: + return "{ " + ", ".join( + format_primitive(item) for item in value + ) + " }" + else: + raise TypeError + +def format_struct(struct): + return "{\n" + "\n".join( + "\t.{0} = {1},".format(member, value) for member, value in struct.items() + ) + "\n}" + + +def format_field(field, value): + if field.message_type is not None: + raise TypeError + elif field.enum_type: + return "{0}_{1}".format(field.enum_type.name, field.enum_type.values_by_number[value].name) + elif hasattr(value, "_values"): + return format_primitive(value._values) + else: + return format_primitive(value) + +def field_to_meta(field, value): + if hasattr(value, "_values"): + return ("{}_count".format(field.name), format_primitive(len(value._values))) + else: + return ("has_{}".format(field.name), format_primitive(True)) + +def message_to_struct(_message, proto): + message = json_format.ParseDict(_message, proto()) + return dict(chain.from_iterable( + ( + field_to_meta(field, value), + (field.name, format_field(field, value)), + ) for field, value in message.ListFields() + )) + +def format_message(message, proto): + return format_struct(message_to_struct(message, proto)) + +def format_messages(messages, proto): + return "{" + ",\n".join( + format_message(message, proto) for message in messages + ) + "}" + +if __name__ == "__main__": + os.chdir(os.path.abspath(os.path.dirname(__file__))) + + messages = json.load(open("nem_mosaics.json")) + + with open("nem_mosaics.h", "w+") as f: + f.write(HEADER_TEMPLATE.format(count=format_primitive(len(messages)))) + + with open("nem_mosaics.c", "w+") as f: + f.write(CODE_TEMPLATE.format(code=format_messages(messages, types.NEMMosaicDefinition))) From 9f41ee39ba5a11e799a290cbc2e7f3a0e44dd0c2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Thu, 20 Jul 2017 22:58:45 +0100 Subject: [PATCH 0591/1154] nem_mosaics: Add DIMCOIN --- firmware/nem_mosaics.c | 16 ++++++++++++++++ firmware/nem_mosaics.h | 2 +- firmware/nem_mosaics.json | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index d9faea3a74..1e7d5cb558 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -11,6 +11,22 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .mosaic = "xem", .has_divisibility = true, .divisibility = 6, +}, +{ + .has_name = true, + .name = "DIMCOIN", + .has_ticker = true, + .ticker = " DIM", + .has_namespace = true, + .namespace = "dim", + .has_mosaic = true, + .mosaic = "coin", + .has_divisibility = true, + .divisibility = 6, + .has_levy = true, + .levy = NEMMosaicLevy_MosaicLevy_Percentile, + .has_fee = true, + .fee = 10, }}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h index 5ce599ed6f..8a17e665da 100644 --- a/firmware/nem_mosaics.h +++ b/firmware/nem_mosaics.h @@ -5,7 +5,7 @@ #include "types.pb.h" -#define NEM_MOSAIC_DEFINITIONS_COUNT (1) +#define NEM_MOSAIC_DEFINITIONS_COUNT (2) extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index a5432a417c..b878811d96 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -4,5 +4,14 @@ "namespace": "nem", "mosaic": "xem", "divisibility": 6 + }, + { + "name": "DIMCOIN", + "ticker": " DIM", + "namespace": "dim", + "mosaic": "coin", + "divisibility": 6, + "levy": "MosaicLevy_Percentile", + "fee": 10 } ] From 3a303087ae2b6dc7d8040263de4fd66e09c8e876 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 21 Jul 2017 10:54:58 +0100 Subject: [PATCH 0592/1154] nem_mosaics: Add DIM TOKEN --- firmware/nem_mosaics.c | 12 ++++++++++++ firmware/nem_mosaics.h | 2 +- firmware/nem_mosaics.json | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index 1e7d5cb558..7e50bbee13 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -27,6 +27,18 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .levy = NEMMosaicLevy_MosaicLevy_Percentile, .has_fee = true, .fee = 10, +}, +{ + .has_name = true, + .name = "DIM TOKEN", + .has_ticker = true, + .ticker = " DIMTOK", + .has_namespace = true, + .namespace = "dim", + .has_mosaic = true, + .mosaic = "token", + .has_divisibility = true, + .divisibility = 6, }}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h index 8a17e665da..a4d0c21ecd 100644 --- a/firmware/nem_mosaics.h +++ b/firmware/nem_mosaics.h @@ -5,7 +5,7 @@ #include "types.pb.h" -#define NEM_MOSAIC_DEFINITIONS_COUNT (2) +#define NEM_MOSAIC_DEFINITIONS_COUNT (3) extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index b878811d96..16024823dc 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -13,5 +13,12 @@ "divisibility": 6, "levy": "MosaicLevy_Percentile", "fee": 10 + }, + { + "name": "DIM TOKEN", + "ticker": " DIMTOK", + "namespace": "dim", + "mosaic": "token", + "divisibility": 6 } ] From b0394622a3641dd00c0c422bb7d847376cd33214 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 21 Jul 2017 11:13:08 +0100 Subject: [PATCH 0593/1154] nem2: Warn on unknown mosaics --- firmware/nem2.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/firmware/nem2.c b/firmware/nem2.c index 48f8f22e4a..dabcb3e2e0 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -103,19 +103,23 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran memset(mosaics, 0, sizeof(mosaics)); + bool unknownMosaic = false; + for (size_t i = 0; i < transfer->mosaics_count; i++) { // Skip duplicate mosaics if (mosaics[i].skip) continue; const NEMMosaic *mosaic = &transfer->mosaics[i]; - // XEM is displayed separately if ((mosaics[i].definition = nem_mosaicByName(mosaic->namespace, mosaic->mosaic))) { + // XEM is displayed separately if (mosaics[i].definition == NEM_MOSAIC_DEFINITION_XEM) { // Do not display as a mosaic mosaics[i].skip = true; xem = &mosaics[i]; } + } else { + unknownMosaic = true; } mosaics[i].quantity = mosaic->quantity; @@ -133,6 +137,22 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran bignum256 multiplier; bn_read_uint64(transfer->amount, &multiplier); + if (unknownMosaic) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("I take the risk"), + _("Unknown Mosaics"), + _("Divisibility and levy"), + _("cannot be shown for"), + _("unknown mosaics!"), + NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; @@ -255,7 +275,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM } bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { - layoutDialog(&bmp_icon_question, + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, From 17e33d5517b0dd08c268d569b108a8c3484275de Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 22 Jul 2017 19:02:41 +0100 Subject: [PATCH 0594/1154] nem2: Handle Mosaic Definition Creation transactions --- firmware/fsm.c | 34 ++++++-- firmware/layout2.c | 68 +++++++++++++++- firmware/layout2.h | 2 + firmware/nem2.c | 158 +++++++++++++++++++++++++++++++++++++- firmware/nem2.h | 8 +- firmware/nem_mosaics.c | 6 ++ firmware/nem_mosaics.json | 5 +- 7 files changed, 264 insertions(+), 17 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index bff8740469..5cbd771ba6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1154,13 +1154,14 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { CHECK_PARAM(msg->has_transaction, _("No common provided")); // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer + msg->has_provision_namespace; + unsigned int provided = msg->has_transfer + msg->has_provision_namespace + msg->has_mosaic_creation; CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided")); NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); bool cosigning = msg->has_cosigning && msg->cosigning; if (msg->has_multisig) { @@ -1187,8 +1188,18 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { } } + RESP_INIT(NEMSignedTx); + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); + if (!node) return; + + hdnode_fill_public_key(node); + const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + char address[NEM_ADDRESS_SIZE + 1]; + hdnode_get_nem_address(node, common->network, address); + if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); @@ -1201,12 +1212,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } - RESP_INIT(NEMSignedTx); - - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); - if (!node) return; - - hdnode_fill_public_key(node); + if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } nem_transaction_ctx context; nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); @@ -1227,6 +1237,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { + layoutHome(); + return; + } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { layoutHome(); return; @@ -1241,6 +1256,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); return; } + + if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&context, &msg->transaction, &msg->mosaic_creation)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/layout2.c b/firmware/layout2.c index 9190eb9f8b..a098cf0c6e 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -550,10 +550,8 @@ void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t qua } void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier) { - char mosaic_name[256]; - strlcpy(mosaic_name, namespace, sizeof(mosaic_name)); - strlcat(mosaic_name, ".", sizeof(mosaic_name)); - strlcat(mosaic_name, mosaic, sizeof(mosaic_name)); + char mosaic_name[32]; + nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name)); char str_out[32]; nem_mosaicFormatAmount(NULL, quantity, multiplier, str_out, sizeof(str_out)); @@ -591,3 +589,65 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encryp str[0], str[1], str[2], str[3], NULL, NULL); } } + +void layoutNEMMosaicDescription(const char *description) { + const char **str = split_message((uint8_t *) description, strlen(description), 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + _("Mosaic Description"), + str[0], str[1], str[2], str[3], NULL, NULL); +} + +void layoutNEMLevy(const NEMMosaicDefinition *definition) { + const NEMMosaicDefinition *mosaic; + if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic)) { + mosaic = definition; + } else { + mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic); + } + + char mosaic_name[32]; + if (mosaic == NULL) { + nem_mosaicFormatName(definition->levy_namespace, definition->levy_mosaic, mosaic_name, sizeof(mosaic_name)); + } + + char str_out[32]; + bignum256 amnt; + + switch (definition->levy) { + case NEMMosaicLevy_MosaicLevy_Percentile: + bn_read_uint64(definition->fee, &amnt); + bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); + + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + _("Percentile Levy"), + _("Raw levy value is"), + str_out, + _("in"), + mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name) : mosaic_name, + NULL, + NULL); + break; + + case NEMMosaicLevy_MosaicLevy_Absolute: + default: + nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out)); + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + _("Absolute Levy"), + _("Levy is"), + str_out, + mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL) : _("in raw units of"), + mosaic ? NULL : mosaic_name, + NULL, + NULL); + break; + } +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 86b02ffe7b..337f635a87 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -54,5 +54,7 @@ void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); +void layoutNEMMosaicDescription(const char *description); +void layoutNEMLevy(const NEMMosaicDefinition *definition); #endif diff --git a/firmware/nem2.c b/firmware/nem2.c index dabcb3e2e0..ee92027e0b 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -93,6 +93,40 @@ const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provis return NULL; } +const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) { + if (!mosaic_creation->has_definition) return _("No mosaic definition provided"); + if (!mosaic_creation->has_sink) return _("No creation sink provided"); + if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); + + if (!nem_validate_address(mosaic_creation->sink, network)) return _("Invalid creation sink address"); + + if (mosaic_creation->definition.has_name) return _("Name not allowed in mosaic creation transactions"); + if (mosaic_creation->definition.has_ticker) return _("Ticker not allowed in mosaic creation transactions"); + + if (!mosaic_creation->definition.has_namespace) return _("No mosaic namespace provided"); + if (!mosaic_creation->definition.has_mosaic) return _("No mosaic name provided"); + + if (mosaic_creation->definition.has_levy) { + if (!mosaic_creation->definition.has_fee) return _("No levy address provided"); + if (!mosaic_creation->definition.has_levy_address) return _("No levy address provided"); + if (!mosaic_creation->definition.has_levy_namespace) return _("No levy namespace provided"); + if (!mosaic_creation->definition.has_levy_mosaic) return _("No levy mosaic name provided"); + + if (!mosaic_creation->definition.has_divisibility) return _("No divisibility provided"); + if (!mosaic_creation->definition.has_supply) return _("No supply provided"); + if (!mosaic_creation->definition.has_mutable_supply) return _("No supply mutability provided"); + if (!mosaic_creation->definition.has_transferable) return _("No mosaic transferability provided"); + if (!mosaic_creation->definition.has_description) return _("No description provided"); + + if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY) return _("Invalid divisibility provided"); + if (mosaic_creation->definition.supply > NEM_MAX_SUPPLY) return _("Invalid supply provided"); + + if (!nem_validate_address(mosaic_creation->definition.levy_address, network)) return _("Invalid levy address"); + } + + return NULL; +} + bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { struct { @@ -310,6 +344,118 @@ bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactio provision_namespace->fee); } +bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + _("Create mosaic"), + mosaic_creation->definition.mosaic, + _("under namespace"), + mosaic_creation->definition.namespace, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + layoutNEMMosaicDescription(mosaic_creation->definition.description); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + char str_out[32]; + bignum256 amnt; + + bn_read_uint64(mosaic_creation->definition.supply, &amnt); + bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); + + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } + + strlcat(str_out, ".", sizeof(str_out)); + for (size_t i = 0; i < mosaic_creation->definition.divisibility; i++) { + strlcat(str_out, "0", sizeof(str_out)); + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + _("Properties"), + mosaic_creation->definition.mutable_supply ? _("Mutable supply:") : _("Immutable supply:"), + str_out, + _("Mosaic will be"), + mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"), + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + if (mosaic_creation->definition.has_levy) { + layoutNEMLevy(&mosaic_creation->definition); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + if (strcmp(address, mosaic_creation->definition.levy_address) == 0) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + _("Levy Recipient"), + _("Levy will be paid to"), + _("yourself"), + NULL, + NULL, + NULL, + NULL); + } else { + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Next"), + _("Levy Recipient"), + _("Levy will be paid to"), + mosaic_creation->definition.levy_address); + } + + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + return true; +} + +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) { + return nem_transaction_create_mosaic_creation(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + mosaic_creation->definition.namespace, + mosaic_creation->definition.mosaic, + mosaic_creation->definition.description, + mosaic_creation->definition.divisibility, + mosaic_creation->definition.supply, + mosaic_creation->definition.mutable_supply, + mosaic_creation->definition.transferable, + mosaic_creation->definition.levy, + mosaic_creation->definition.fee, + mosaic_creation->definition.levy_address, + mosaic_creation->definition.levy_namespace, + mosaic_creation->definition.levy_mosaic, + mosaic_creation->sink, + mosaic_creation->fee); +} + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { layoutNEMDialog(&bmp_icon_question, _("Cancel"), @@ -422,14 +568,16 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti return false; } + const NEMMosaicDefinition *levy_mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic); + switch (definition->levy) { case NEMMosaicLevy_MosaicLevy_Absolute: - format_amount(definition, definition->fee, NULL, NULL, 0, str_out, size); + format_amount(levy_mosaic, definition->fee, NULL, NULL, 0, str_out, size); break; case NEMMosaicLevy_MosaicLevy_Percentile: bn_read_uint64(definition->fee, &multiplier2); - format_amount(definition, quantity, multiplier, &multiplier2, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); + format_amount(levy_mosaic, quantity, multiplier, &multiplier2, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); break; default: @@ -438,3 +586,9 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti return true; } + +void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { + strlcpy(str_out, namespace, size); + strlcat(str_out, ".", size); + strlcat(str_out, mosaic, size); +} diff --git a/firmware/nem2.h b/firmware/nem2.h index dc3f3721d1..f25f81cb62 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -31,9 +31,7 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); - -bool nem_askTransaction(const char *desc, const NEMTransactionCommon *common, const NEMSignTx *msg); -bool nem_fsmTransaction(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMSignTx *msg); +const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); @@ -41,12 +39,16 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); +bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic); void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); +void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size); static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic) { return strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0; diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index 7e50bbee13..ed50c9064c 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -3,6 +3,8 @@ #include "nem_mosaics.h" const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {{ + .has_name = true, + .name = "XEM", .has_ticker = true, .ticker = " XEM", .has_namespace = true, @@ -27,6 +29,10 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .levy = NEMMosaicLevy_MosaicLevy_Percentile, .has_fee = true, .fee = 10, + .has_levy_namespace = true, + .levy_namespace = "dim", + .has_levy_mosaic = true, + .levy_mosaic = "coin", }, { .has_name = true, diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index 16024823dc..522a2abd58 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -1,5 +1,6 @@ [ { + "name": "XEM", "ticker": " XEM", "namespace": "nem", "mosaic": "xem", @@ -12,7 +13,9 @@ "mosaic": "coin", "divisibility": 6, "levy": "MosaicLevy_Percentile", - "fee": 10 + "fee": 10, + "levy_namespace": "dim", + "levy_mosaic": "coin" }, { "name": "DIM TOKEN", From 327736ca96ee077651def8f257e3345dc2c6e023 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 22 Jul 2017 20:07:03 +0100 Subject: [PATCH 0595/1154] nem_mosaics: Whitelist networks --- firmware/layout2.c | 10 +++++----- firmware/layout2.h | 4 ++-- firmware/nem2.c | 17 +++++++++-------- firmware/nem2.h | 21 +++++++++++++++++---- firmware/nem_mosaics.c | 4 ++++ firmware/nem_mosaics.json | 6 ++++-- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index a098cf0c6e..d1df50271a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -528,13 +528,13 @@ void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, NULL); } -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier) { +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { char str_out[32], str_levy[32]; nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); if (definition->has_levy) { - nem_mosaicFormatLevy(definition, quantity, multiplier, str_levy, sizeof(str_levy)); + nem_mosaicFormatLevy(definition, quantity, multiplier, network, str_levy, sizeof(str_levy)); } layoutDialogSwipe(&bmp_icon_question, @@ -597,12 +597,12 @@ void layoutNEMMosaicDescription(const char *description) { str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutNEMLevy(const NEMMosaicDefinition *definition) { +void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { const NEMMosaicDefinition *mosaic; - if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic)) { + if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic, network)) { mosaic = definition; } else { - mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic); + mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); } char mosaic_name[32]; diff --git a/firmware/layout2.h b/firmware/layout2.h index 337f635a87..6176e61794 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -51,10 +51,10 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier); +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); void layoutNEMMosaicDescription(const char *description); -void layoutNEMLevy(const NEMMosaicDefinition *definition); +void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); #endif diff --git a/firmware/nem2.c b/firmware/nem2.c index ee92027e0b..10f9a03974 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -102,6 +102,7 @@ const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creatio if (mosaic_creation->definition.has_name) return _("Name not allowed in mosaic creation transactions"); if (mosaic_creation->definition.has_ticker) return _("Ticker not allowed in mosaic creation transactions"); + if (mosaic_creation->definition.networks_count) return _("Networks not allowed in mosaic creation transactions"); if (!mosaic_creation->definition.has_namespace) return _("No mosaic namespace provided"); if (!mosaic_creation->definition.has_mosaic) return _("No mosaic name provided"); @@ -145,7 +146,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran const NEMMosaic *mosaic = &transfer->mosaics[i]; - if ((mosaics[i].definition = nem_mosaicByName(mosaic->namespace, mosaic->mosaic))) { + if ((mosaics[i].definition = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network))) { // XEM is displayed separately if (mosaics[i].definition == NEM_MOSAIC_DEFINITION_XEM) { // Do not display as a mosaic @@ -160,7 +161,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran for (size_t j = i + 1; j < transfer->mosaics_count; j++) { const NEMMosaic *new_mosaic = &transfer->mosaics[j]; - if (nem_mosaicMatches(mosaics[i].definition, new_mosaic->namespace, new_mosaic->mosaic)) { + if (nem_mosaicMatches(mosaics[i].definition, new_mosaic->namespace, new_mosaic->mosaic, common->network)) { // Merge duplicate mosaics mosaics[j].skip = true; mosaics[i].quantity += new_mosaic->quantity; @@ -199,7 +200,7 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran const NEMMosaic *mosaic = &transfer->mosaics[i]; if (mosaics[i].definition) { - layoutNEMTransferMosaic(mosaics[i].definition, mosaics[i].quantity, &multiplier); + layoutNEMTransferMosaic(mosaics[i].definition, mosaics[i].quantity, &multiplier, common->network); } else { layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaics[i].quantity, &multiplier); } @@ -395,7 +396,7 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr } if (mosaic_creation->definition.has_levy) { - layoutNEMLevy(&mosaic_creation->definition); + layoutNEMLevy(&mosaic_creation->definition, common->network); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -503,11 +504,11 @@ bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *c return true; } -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic) { +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; - if (nem_mosaicMatches(definition, namespace, mosaic)) { + if (nem_mosaicMatches(definition, namespace, mosaic, network)) { return definition; } } @@ -561,14 +562,14 @@ void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quan format_amount(definition, quantity, multiplier, NULL, 0, str_out, size); } -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { bignum256 multiplier2; if (!definition->has_levy || !definition->has_fee) { return false; } - const NEMMosaicDefinition *levy_mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic); + const NEMMosaicDefinition *levy_mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); switch (definition->levy) { case NEMMosaicLevy_MosaicLevy_Absolute: diff --git a/firmware/nem2.h b/firmware/nem2.h index f25f81cb62..38f5f8b199 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -45,13 +45,26 @@ bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCom bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic); +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); + void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size); -static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic) { - return strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0; +static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { + if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { + if (definition->networks_count == 0) { + return true; + } + + for (size_t i = 0; i < definition->networks_count; i++) { + if (definition->networks[i] == network) { + return true; + } + } + } + + return false; } #endif diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index ed50c9064c..2305f5ebb3 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -33,6 +33,8 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .levy_namespace = "dim", .has_levy_mosaic = true, .levy_mosaic = "coin", + .networks_count = 1, + .networks = { 104 }, }, { .has_name = true, @@ -45,6 +47,8 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .mosaic = "token", .has_divisibility = true, .divisibility = 6, + .networks_count = 1, + .networks = { 104 }, }}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index 522a2abd58..31b6f51c70 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -15,13 +15,15 @@ "levy": "MosaicLevy_Percentile", "fee": 10, "levy_namespace": "dim", - "levy_mosaic": "coin" + "levy_mosaic": "coin", + "networks": [ 104 ] }, { "name": "DIM TOKEN", "ticker": " DIMTOK", "namespace": "dim", "mosaic": "token", - "divisibility": 6 + "divisibility": 6, + "networks": [ 104 ] } ] From a10e131ecd25ef3a0b39ba84dcc40b0ab4cd78c8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 23 Jul 2017 15:45:20 +0100 Subject: [PATCH 0596/1154] nem2: Handle Mosaic Supply Change transactions --- firmware/fsm.c | 19 +++++++++++++- firmware/nem2.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ firmware/nem2.h | 4 +++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 5cbd771ba6..5d6ec5a38b 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1154,7 +1154,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { CHECK_PARAM(msg->has_transaction, _("No common provided")); // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer + msg->has_provision_namespace + msg->has_mosaic_creation; + unsigned int provided = msg->has_transfer + msg->has_provision_namespace + msg->has_mosaic_creation + msg->has_supply_change; CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided")); @@ -1162,6 +1162,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); bool cosigning = msg->has_cosigning && msg->cosigning; if (msg->has_multisig) { @@ -1218,6 +1219,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + nem_transaction_ctx context; nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); @@ -1242,6 +1249,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_supply_change && !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { + layoutHome(); + return; + } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { layoutHome(); return; @@ -1261,6 +1273,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); return; } + + if (msg->has_supply_change && !nem_fsmSupplyChange(&context, &msg->transaction, &msg->supply_change)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/nem2.c b/firmware/nem2.c index 10f9a03974..f4145bcba5 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -128,6 +128,15 @@ const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creatio return NULL; } +const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change) { + if (!supply_change->has_namespace) return _("No namespace provided"); + if (!supply_change->has_mosaic) return _("No mosaic provided"); + if (!supply_change->has_type) return _("No type provided"); + if (!supply_change->has_delta) return _("No delta provided"); + + return NULL; +} + bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { struct { @@ -457,6 +466,67 @@ bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCom mosaic_creation->fee); } +bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + _("Modify supply for"), + supply_change->mosaic, + _("under namespace"), + supply_change->namespace, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + char str_out[32]; + + bignum256 amnt; + bn_read_uint64(supply_change->delta, &amnt); + bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); + + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), + str_out, + _("whole units"), + NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } + + return true; +} + +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) { + return nem_transaction_create_mosaic_supply_change(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + supply_change->namespace, + supply_change->mosaic, + supply_change->type, + supply_change->delta); +} + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { layoutNEMDialog(&bmp_icon_question, _("Cancel"), diff --git a/firmware/nem2.h b/firmware/nem2.h index 38f5f8b199..52ed41ddd3 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -32,6 +32,7 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); +const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); @@ -42,6 +43,9 @@ bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactio bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); +bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); From 2aeeb3f9785fd65c49efdc266fdfdab58197c94a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 23 Jul 2017 18:55:13 +0100 Subject: [PATCH 0597/1154] nem2: Handle Aggregate Modification transactions --- firmware/fsm.c | 23 +++++++++- firmware/nem2.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++ firmware/nem2.h | 4 ++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 5d6ec5a38b..6babd08a12 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1154,7 +1154,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { CHECK_PARAM(msg->has_transaction, _("No common provided")); // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer + msg->has_provision_namespace + msg->has_mosaic_creation + msg->has_supply_change; + unsigned int provided = msg->has_transfer + + msg->has_provision_namespace + + msg->has_mosaic_creation + + msg->has_supply_change + + msg->has_aggregate_modification; CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided")); @@ -1163,6 +1167,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); + NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); bool cosigning = msg->has_cosigning && msg->cosigning; if (msg->has_multisig) { @@ -1225,6 +1230,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + nem_transaction_ctx context; nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); @@ -1254,6 +1265,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&inner, &msg->multisig, &msg->aggregate_modification)) { + layoutHome(); + return; + } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { layoutHome(); return; @@ -1278,6 +1294,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); return; } + + if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&context, &msg->transaction, &msg->aggregate_modification)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/nem2.c b/firmware/nem2.c index f4145bcba5..d3885a8167 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -137,6 +137,26 @@ const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_chang return NULL; } +const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation) { + if (creation && aggregate_modification->modifications_count == 0) { + return _("No modifications provided"); + } + + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + + if (!modification->has_type) return _("No modification type provided"); + if (!modification->has_public_key) return _("No cosignatory public key provided"); + if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided"); + + if (creation && modification->type == NEMModificationType_CosignatoryModification_Delete) { + return _("Cannot remove cosignatory when converting account"); + } + } + + return NULL; +} + bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { struct { @@ -527,6 +547,104 @@ bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommo supply_change->delta); } +bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { + if (creation) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + _("Convert account to"), + _("multisig account?"), + NULL, + NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + char address[NEM_ADDRESS_SIZE + 1]; + + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + nem_get_address(modification->public_key.bytes, common->network, address); + + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), + address); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + int32_t relative_change = aggregate_modification->relative_change; + if (relative_change) { + char str_out[32]; + + bignum256 amnt; + bn_read_uint64(relative_change < 0 ? -relative_change : relative_change, &amnt); + bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); + + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } + + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + creation ? _("Set minimum") : (relative_change < 0 ? _("Decrease minimum") : _("Increase minimum")), + creation ? _("cosignatories to") : _("cosignatories by"), + str_out, + NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } + + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } + + return true; +} + +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) { + bool ret = nem_transaction_create_aggregate_modification(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + aggregate_modification->modifications_count, + aggregate_modification->relative_change != 0); + if (!ret) return false; + + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + + ret = nem_transaction_write_cosignatory_modification(context, + modification->type, + modification->public_key.bytes); + if (!ret) return false; + } + + if (aggregate_modification->relative_change) { + ret = nem_transaction_write_minimum_cosignatories(context, aggregate_modification->relative_change); + if (!ret) return false; + } + + return true; +} + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { layoutNEMDialog(&bmp_icon_question, _("Cancel"), diff --git a/firmware/nem2.h b/firmware/nem2.h index 52ed41ddd3..479903e783 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -33,6 +33,7 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); +const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); @@ -46,6 +47,9 @@ bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCom bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); +bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); From 1f20625bbc6c5d5fa964d898362039334e331d98 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 26 Jul 2017 19:25:46 +0100 Subject: [PATCH 0598/1154] nem2: Refactor for new bn_format --- firmware/layout2.c | 9 +--- firmware/nem2.c | 126 +++++++++++++++------------------------------ firmware/nem2.h | 7 ++- 3 files changed, 48 insertions(+), 94 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index d1df50271a..ac1e6ae860 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -611,17 +611,10 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { } char str_out[32]; - bignum256 amnt; switch (definition->levy) { case NEMMosaicLevy_MosaicLevy_Percentile: - bn_read_uint64(definition->fee, &amnt); - bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); - - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - *decimal = '\0'; - } + bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), diff --git a/firmware/nem2.c b/firmware/nem2.c index d3885a8167..5a8f51f6f1 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -27,8 +27,6 @@ #include "rng.h" #include "secp256k1.h" -static void format_amount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, const bignum256 *multiplier2, int divisor, char *str_out, size_t size); - const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { if (!common->has_network) { common->has_network = true; @@ -395,20 +393,15 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr } char str_out[32]; - bignum256 amnt; - bn_read_uint64(mosaic_creation->definition.supply, &amnt); - bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); - - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - *decimal = '\0'; - } - - strlcat(str_out, ".", sizeof(str_out)); - for (size_t i = 0; i < mosaic_creation->definition.divisibility; i++) { - strlcat(str_out, "0", sizeof(str_out)); - } + bn_format_uint64(mosaic_creation->definition.supply, + NULL, + NULL, + mosaic_creation->definition.divisibility, + mosaic_creation->definition.divisibility, + true, + str_out, + sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), @@ -502,15 +495,7 @@ bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupp } char str_out[32]; - - bignum256 amnt; - bn_read_uint64(supply_change->delta, &amnt); - bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); - - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - *decimal = '\0'; - } + bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), @@ -584,15 +569,14 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA int32_t relative_change = aggregate_modification->relative_change; if (relative_change) { char str_out[32]; - - bignum256 amnt; - bn_read_uint64(relative_change < 0 ? -relative_change : relative_change, &amnt); - bn_format(&amnt, NULL, NULL, 0, str_out, sizeof(str_out)); - - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - *decimal = '\0'; - } + bn_format_uint64(relative_change < 0 ? -relative_change : relative_change, + NULL, + NULL, + 0, + 0, + false, + str_out, + sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), @@ -704,80 +688,52 @@ const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *m return NULL; } -void format_amount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, const bignum256 *multiplier2, int divisor, char *str_out, size_t size) { - uint32_t divisibility = definition && definition->has_divisibility ? definition->divisibility : 0; - const char *ticker = definition && definition->has_ticker ? definition->ticker : NULL; +static inline size_t format_amount(const NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { + bignum256 val; + memcpy(&val, amnt, sizeof(bignum256)); - bignum256 amnt; - bn_read_uint64(quantity, &amnt); - - if (multiplier2) { - bn_multiply(multiplier2, &amnt, &secp256k1.prime); - } - - // Do not use prefix/suffix with bn_format, it messes with the truncation code if (multiplier) { - bn_multiply(multiplier, &amnt, &secp256k1.prime); + bn_multiply(multiplier, &val, &secp256k1.prime); divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility; } - // bn_format(amnt / (10 ^ divisor), divisibility) - bn_format(&amnt, NULL, NULL, divisibility + divisor, str_out, size); - - // Truncate as if we called bn_format with (divisibility) instead of (divisibility + divisor) - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - const char *terminator = strchr(str_out, '\0'); - - if (divisibility == 0) { - // Truncate as an integer - *decimal = '\0'; - } else { - char *end = decimal + divisibility + 1; - if (end < terminator) { - *end = '\0'; - } - } - } - - if (ticker) { - strlcat(str_out, " ", size); - strlcat(str_out, ticker, size); - } + return bn_format(&val, + NULL, + definition && definition->has_ticker ? definition->ticker : NULL, + definition && definition->has_divisibility ? definition->divisibility : 0, + -divisor, + false, + str_out, + size); } void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { - format_amount(definition, quantity, multiplier, NULL, 0, str_out, size); + bignum256 amnt; + bn_read_uint64(quantity, &amnt); + + format_amount(definition, &amnt, multiplier, 0, str_out, size); } bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { - bignum256 multiplier2; - if (!definition->has_levy || !definition->has_fee) { return false; } - const NEMMosaicDefinition *levy_mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); + bignum256 amnt, fee; + bn_read_uint64(quantity, &amnt); + bn_read_uint64(definition->fee, &fee); + + const NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); switch (definition->levy) { case NEMMosaicLevy_MosaicLevy_Absolute: - format_amount(levy_mosaic, definition->fee, NULL, NULL, 0, str_out, size); - break; + return format_amount(mosaic, &fee, NULL, 0, str_out, size); case NEMMosaicLevy_MosaicLevy_Percentile: - bn_read_uint64(definition->fee, &multiplier2); - format_amount(levy_mosaic, quantity, multiplier, &multiplier2, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); - break; + bn_multiply(&fee, &amnt, &secp256k1.prime); + return format_amount(mosaic, &amnt, multiplier, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); default: return false; } - - return true; -} - -void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { - strlcpy(str_out, namespace, size); - strlcat(str_out, ".", size); - strlcat(str_out, mosaic, size); } diff --git a/firmware/nem2.h b/firmware/nem2.h index 479903e783..5a36298da5 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -57,7 +57,12 @@ const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *m void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); -void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size); + +static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { + strlcpy(str_out, namespace, size); + strlcat(str_out, ".", size); + strlcat(str_out, mosaic, size); +} static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { From 1d83eee3b3b8a3fac707058322f51586873db49f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 28 Jul 2017 16:29:31 +0100 Subject: [PATCH 0599/1154] nem2: Canonicalize mosaics in transfer transactions NIS deserializes then serializes transactions in order to verify the signature. This means that transactions must be serialized canonically, otherwise the signature will not match. Due to [1], mosaics are sorted and deduplicated in transfer transactions. [1]: https://github.com/NemProject/nem.core/commit/4231550ddfd1aa554b672ae725da6c23940bc2d0 --- firmware/fsm.c | 4 ++ firmware/nem2.c | 103 +++++++++++++++++++++++++++++++----------------- firmware/nem2.h | 24 +++++++++++ 3 files changed, 95 insertions(+), 36 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 6babd08a12..4ad24b19f5 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1206,6 +1206,10 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { char address[NEM_ADDRESS_SIZE + 1]; hdnode_get_nem_address(node, common->network, address); + if (msg->has_transfer) { + msg->transfer.mosaics_count = nem_canonicalizeMosaics(msg->transfer.mosaics, msg->transfer.mosaics_count); + } + if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); diff --git a/firmware/nem2.c b/firmware/nem2.c index 5a8f51f6f1..818ff8cc43 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -157,43 +157,21 @@ const char *nem_validate_aggregate_modification(const NEMAggregateModification * bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { - struct { - bool skip; - uint64_t quantity; - const NEMMosaicDefinition *definition; - } mosaics[transfer->mosaics_count], *xem = NULL; - - memset(mosaics, 0, sizeof(mosaics)); - + const NEMMosaic *xem = NULL; bool unknownMosaic = false; - for (size_t i = 0; i < transfer->mosaics_count; i++) { - // Skip duplicate mosaics - if (mosaics[i].skip) continue; + const NEMMosaicDefinition *definitions[transfer->mosaics_count]; + for (size_t i = 0; i < transfer->mosaics_count; i++) { const NEMMosaic *mosaic = &transfer->mosaics[i]; - if ((mosaics[i].definition = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network))) { - // XEM is displayed separately - if (mosaics[i].definition == NEM_MOSAIC_DEFINITION_XEM) { - // Do not display as a mosaic - mosaics[i].skip = true; - xem = &mosaics[i]; - } - } else { + definitions[i] = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); + + if (definitions[i] == NEM_MOSAIC_DEFINITION_XEM) { + xem = mosaic; + } else if (definitions[i] == NULL) { unknownMosaic = true; } - - mosaics[i].quantity = mosaic->quantity; - for (size_t j = i + 1; j < transfer->mosaics_count; j++) { - const NEMMosaic *new_mosaic = &transfer->mosaics[j]; - - if (nem_mosaicMatches(mosaics[i].definition, new_mosaic->namespace, new_mosaic->mosaic, common->network)) { - // Merge duplicate mosaics - mosaics[j].skip = true; - mosaics[i].quantity += new_mosaic->quantity; - } - } } bignum256 multiplier; @@ -221,15 +199,16 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran } for (size_t i = 0; i < transfer->mosaics_count; i++) { - // Skip duplicate mosaics or XEM - if (mosaics[i].skip) continue; - const NEMMosaic *mosaic = &transfer->mosaics[i]; - if (mosaics[i].definition) { - layoutNEMTransferMosaic(mosaics[i].definition, mosaics[i].quantity, &multiplier, common->network); + if (mosaic == xem) { + continue; + } + + if (definitions[i]) { + layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier, common->network); } else { - layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaics[i].quantity, &multiplier); + layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaic->quantity, &multiplier); } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { @@ -707,6 +686,58 @@ static inline size_t format_amount(const NEMMosaicDefinition *definition, const size); } +size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { + if (mosaics_count <= 1) { + return mosaics_count; + } + + size_t actual_count = 0; + + bool skip[mosaics_count]; + memset(skip, 0, sizeof(skip)); + + // Merge duplicates + for (size_t i = 0; i < mosaics_count; i++) { + if (skip[i]) continue; + + NEMMosaic *mosaic = &mosaics[actual_count]; + + if (actual_count++ != i) { + memcpy(mosaic, &mosaics[i], sizeof(NEMMosaic)); + } + + for (size_t j = i + 1; j < mosaics_count; j++) { + if (skip[j]) continue; + + const NEMMosaic *new_mosaic = &mosaics[j]; + + if (nem_mosaicCompare(mosaic, new_mosaic) == 0) { + skip[j] = true; + mosaic->quantity += new_mosaic->quantity; + } + } + } + + NEMMosaic temp; + + // Sort mosaics + for (size_t i = 0; i < actual_count - 1; i++) { + NEMMosaic *a = &mosaics[i]; + + for (size_t j = i + 1; j < actual_count; j++) { + NEMMosaic *b = &mosaics[j]; + + if (nem_mosaicCompare(a, b) > 0) { + memcpy(&temp, a, sizeof(NEMMosaic)); + memcpy(a, b, sizeof(NEMMosaic)); + memcpy(b, &temp, sizeof(NEMMosaic)); + } + } + } + + return actual_count; +} + void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { bignum256 amnt; bn_read_uint64(quantity, &amnt); diff --git a/firmware/nem2.h b/firmware/nem2.h index 5a36298da5..d539947c21 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -55,6 +55,7 @@ bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *c const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); +size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); @@ -80,4 +81,27 @@ static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, cons return false; } +static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) { + size_t namespace_length = strlen(a->namespace); + + // Ensure that strlen(a->namespace) <= strlen(b->namespace) + if (namespace_length > strlen(b->namespace)) { + return -nem_mosaicCompare(b, a); + } + + int r = strncmp(a->namespace, b->namespace, namespace_length); + + if (r == 0 && b->namespace[namespace_length] != '\0') { + // The next character would be the separator + r = (':' - b->namespace[namespace_length]); + } + + if (r == 0) { + // Finally compare the mosaic + r = strcmp(a->mosaic, b->mosaic); + } + + return r; +} + #endif From d0e89db9faed583b9ef961e64289f391f3d5b30d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 2 Aug 2017 17:27:11 +0100 Subject: [PATCH 0600/1154] nem_mosaics: Add Breeze Token --- firmware/nem_mosaics.c | 14 ++++++++++++++ firmware/nem_mosaics.h | 2 +- firmware/nem_mosaics.json | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index 2305f5ebb3..c656b647a3 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -49,6 +49,20 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .divisibility = 6, .networks_count = 1, .networks = { 104 }, +}, +{ + .has_name = true, + .name = "Breeze Token", + .has_ticker = true, + .ticker = " BREEZE", + .has_namespace = true, + .namespace = "breeze", + .has_mosaic = true, + .mosaic = "breeze-token", + .has_divisibility = true, + .divisibility = 0, + .networks_count = 1, + .networks = { 104 }, }}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h index a4d0c21ecd..6cf1453b85 100644 --- a/firmware/nem_mosaics.h +++ b/firmware/nem_mosaics.h @@ -5,7 +5,7 @@ #include "types.pb.h" -#define NEM_MOSAIC_DEFINITIONS_COUNT (3) +#define NEM_MOSAIC_DEFINITIONS_COUNT (4) extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index 31b6f51c70..6b59269bca 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -25,5 +25,13 @@ "mosaic": "token", "divisibility": 6, "networks": [ 104 ] + }, + { + "name": "Breeze Token", + "ticker": " BREEZE", + "namespace": "breeze", + "mosaic": "breeze-token", + "divisibility": 0, + "networks": [ 104 ] } ] From 5b0c0b1bfd6b6d631b67a200053f9a9a2b40ff51 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 19 Sep 2017 18:20:44 +0100 Subject: [PATCH 0601/1154] nem_mosaics: Add PacNEM --- firmware/nem_mosaics.c | 36 ++++++++++++++++++++++++++++++++++++ firmware/nem_mosaics.h | 2 +- firmware/nem_mosaics.json | 20 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c index c656b647a3..7a9cecbe01 100644 --- a/firmware/nem_mosaics.c +++ b/firmware/nem_mosaics.c @@ -63,6 +63,42 @@ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = .divisibility = 0, .networks_count = 1, .networks = { 104 }, +}, +{ + .has_name = true, + .name = "PacNEM Game Credits", + .has_ticker = true, + .ticker = " PAC:HRT", + .has_namespace = true, + .namespace = "pacnem", + .has_mosaic = true, + .mosaic = "heart", + .has_divisibility = true, + .divisibility = 0, + .networks_count = 1, + .networks = { 104 }, +}, +{ + .has_name = true, + .name = "PacNEM Score Tokens", + .has_ticker = true, + .ticker = " PAC:CHS", + .has_namespace = true, + .namespace = "pacnem", + .has_mosaic = true, + .mosaic = "cheese", + .has_divisibility = true, + .divisibility = 6, + .has_levy = true, + .levy = NEMMosaicLevy_MosaicLevy_Percentile, + .has_fee = true, + .fee = 100, + .has_levy_namespace = true, + .levy_namespace = "nem", + .has_levy_mosaic = true, + .levy_mosaic = "xem", + .networks_count = 1, + .networks = { 104 }, }}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h index 6cf1453b85..ae756f4319 100644 --- a/firmware/nem_mosaics.h +++ b/firmware/nem_mosaics.h @@ -5,7 +5,7 @@ #include "types.pb.h" -#define NEM_MOSAIC_DEFINITIONS_COUNT (4) +#define NEM_MOSAIC_DEFINITIONS_COUNT (6) extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json index 6b59269bca..c547e93af1 100644 --- a/firmware/nem_mosaics.json +++ b/firmware/nem_mosaics.json @@ -33,5 +33,25 @@ "mosaic": "breeze-token", "divisibility": 0, "networks": [ 104 ] + }, + { + "name": "PacNEM Game Credits", + "ticker": " PAC:HRT", + "namespace": "pacnem", + "mosaic": "heart", + "divisibility": 0, + "networks": [ 104 ] + }, + { + "name": "PacNEM Score Tokens", + "ticker": " PAC:CHS", + "namespace": "pacnem", + "mosaic": "cheese", + "divisibility": 6, + "levy": "MosaicLevy_Percentile", + "fee": 100, + "levy_namespace": "nem", + "levy_mosaic": "xem", + "networks": [ 104 ] } ] From 83db3c098fcfcc04e0faa400bc61c1aa32326226 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Oct 2017 13:11:53 +0200 Subject: [PATCH 0602/1154] fsm: implement CoSi messages --- firmware/fsm.c | 79 +++++++++++++++++++++++++++++++- firmware/fsm.h | 3 ++ firmware/layout2.c | 19 ++++++++ firmware/layout2.h | 2 + firmware/protob/messages.options | 13 ++++++ vendor/trezor-common | 2 +- 6 files changed, 116 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4ad24b19f5..264a5d6198 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -17,6 +17,8 @@ * along with this library. If not, see . */ +#include + #include "trezor.h" #include "fsm.h" #include "messages.h" @@ -48,10 +50,10 @@ #include "ripemd160.h" #include "curves.h" #include "secp256k1.h" -#include #include "ethereum.h" #include "nem.h" #include "nem2.h" +#include "rfc6979.h" #include "gettext.h" // message methods @@ -1315,6 +1317,81 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); } +void fsm_msgCosiCommit(CosiCommit *msg) +{ + RESP_INIT(CosiCommitment); + + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_data, _("No data provided")); + + layoutCosiCommitSign(msg->data.bytes, msg->data.size, false); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); + + resp->has_commitment = true; + resp->has_pubkey = true; + resp->commitment.size = 32; + resp->pubkey.size = 32; + + ed25519_publickey(nonce, resp->commitment.bytes); + ed25519_publickey(node->private_key, resp->pubkey.bytes); + + msg_write(MessageType_MessageType_CosiCommitment, resp); + layoutHome(); +} + +void fsm_msgCosiSign(CosiSign *msg) +{ + RESP_INIT(CosiSignature); + + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_data, _("No data provided")); + CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); + CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); + + layoutCosiCommitSign(msg->data.bytes, msg->data.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); + + resp->has_signature = true; + resp->signature.size = 32; + + ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); + + msg_write(MessageType_MessageType_CosiSignature, resp); + layoutHome(); +} + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm.h b/firmware/fsm.h index 3768e12996..a738ab59cb 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -69,6 +69,9 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); void fsm_msgNEMGetAddress(NEMGetAddress *msg); void fsm_msgNEMSignTx(NEMSignTx *msg); +void fsm_msgCosiCommit(CosiCommit *msg); +void fsm_msgCosiSign(CosiSign *msg); + // debug message functions #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); diff --git a/firmware/layout2.c b/firmware/layout2.c index ac1e6ae860..0ffd7aa6d7 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -644,3 +644,22 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { break; } } + +void layoutCosiCommitSign(const uint8_t *data, uint32_t len, bool final_sign) +{ + char str[4][17]; + if (len == 32) { + data2hex(data , 8, str[0]); + data2hex(data + 8, 8, str[1]); + data2hex(data + 16, 8, str[2]); + data2hex(data + 24, 8, str[3]); + } else { + strlcpy(str[0], "Data", sizeof(str[0])); + strlcpy(str[1], "of", sizeof(str[1])); + strlcpy(str[2], "unsupported", sizeof(str[2])); + strlcpy(str[3], "length", sizeof(str[3])); + } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + final_sign ? _("CoSi sign message?") : _("CoSi commit message?"), + str[0], str[1], str[2], str[3], NULL, NULL); +} diff --git a/firmware/layout2.h b/firmware/layout2.h index 6176e61794..d87c80e418 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -57,4 +57,6 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encryp void layoutNEMMosaicDescription(const char *description); void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); +void layoutCosiCommitSign(const uint8_t *data, uint32_t len, bool final_sign); + #endif diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c4c0f06675..9964171d58 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -149,6 +149,19 @@ NEMAddress.address max_size:41 NEMSignedTx.data max_size:2048 NEMSignedTx.signature max_size:64 +CosiCommit.address_n max_count:8 +CosiCommit.data max_size:32 + +CosiCommitment.commitment max_size:32 +CosiCommitment.pubkey max_size:32 + +CosiSign.address_n max_count:8 +CosiSign.data max_size:32 +CosiSign.global_commitment max_size:32 +CosiSign.global_pubkey max_size:32 + +CosiSignature.signature max_size:32 + # deprecated SimpleSignTx skip_message:true diff --git a/vendor/trezor-common b/vendor/trezor-common index c41f84e221..c20bb1c567 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit c41f84e221f0fc370fcad399541f6fff00f717b8 +Subproject commit c20bb1c567ac0c1ddabf74354f204043eeacad10 From 12c541f87202275e310129dc77b2c7ccb09bef27 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 7 Oct 2017 22:07:56 +0100 Subject: [PATCH 0603/1154] nem2: Handle Importance Transfer transactions --- firmware/fsm.c | 20 ++++++++++++++++- firmware/nem2.c | 42 +++++++++++++++++++++++++++++++++++ firmware/nem2.h | 4 ++++ firmware/protob/types.options | 2 ++ vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 6 files changed, 69 insertions(+), 3 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 264a5d6198..564336fcc2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1160,7 +1160,8 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { msg->has_provision_namespace + msg->has_mosaic_creation + msg->has_supply_change + - msg->has_aggregate_modification; + msg->has_aggregate_modification + + msg->has_importance_transfer; CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided")); @@ -1170,6 +1171,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); + NEM_CHECK_PARAM_WHEN(msg->has_importance_transfer, nem_validate_importance_transfer(&msg->importance_transfer)); bool cosigning = msg->has_cosigning && msg->cosigning; if (msg->has_multisig) { @@ -1242,6 +1244,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + nem_transaction_ctx context; nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); @@ -1276,6 +1284,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { return; } + if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&inner, &msg->multisig, &msg->importance_transfer)) { + layoutHome(); + return; + } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { layoutHome(); return; @@ -1305,6 +1318,11 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); return; } + + if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&context, &msg->transaction, &msg->importance_transfer)) { + layoutHome(); + return; + } } resp->has_data = true; diff --git a/firmware/nem2.c b/firmware/nem2.c index 818ff8cc43..d44afba12a 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -155,6 +155,14 @@ const char *nem_validate_aggregate_modification(const NEMAggregateModification * return NULL; } +const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer) { + if (!importance_transfer->has_mode) return _("No mode provided"); + if (!importance_transfer->has_public_key) return _("No remote account provided"); + if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided"); + + return NULL; +} + bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { const NEMMosaic *xem = NULL; @@ -608,6 +616,40 @@ bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransac return true; } +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) { + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Next"), + desc, + importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), + _("harvesting?"), + NULL, + NULL, + NULL, + NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } + + return true; +} + +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) { + return nem_transaction_create_importance_transfer(context, + common->network, + common->timestamp, + NULL, + common->fee, + common->deadline, + importance_transfer->mode, + importance_transfer->public_key.bytes); +} + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { layoutNEMDialog(&bmp_icon_question, _("Cancel"), diff --git a/firmware/nem2.h b/firmware/nem2.h index d539947c21..4639bd0081 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -34,6 +34,7 @@ const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provis const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); +const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); @@ -50,6 +51,9 @@ bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommo bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); + bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 6b7afbb2d7..ce84f0961a 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -70,3 +70,5 @@ NEMMosaicSupplyChange.mosaic max_size:33 NEMAggregateModification.modifications max_count:16 NEMCosignatoryModification.public_key max_size:32 + +NEMImportanceTransfer.public_key max_size:32 diff --git a/vendor/trezor-common b/vendor/trezor-common index c20bb1c567..b9a2a9c3de 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit c20bb1c567ac0c1ddabf74354f204043eeacad10 +Subproject commit b9a2a9c3defd8a4b84d674116cbae2cf46b6080b diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 9c91985674..636320da58 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 9c919856747a6a519e5a553cc9b67f1c408337af +Subproject commit 636320da585ddb5f5c26257cfb724efd34cde50b From a90acf8b62682d880832bdf5aea8a7810956aac1 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 9 Oct 2017 17:47:56 +0100 Subject: [PATCH 0604/1154] nem_mosaics: Remove generated files --- firmware/.gitignore | 2 + firmware/nem_mosaics.c | 104 ----------------------------------------- firmware/nem_mosaics.h | 13 ------ 3 files changed, 2 insertions(+), 117 deletions(-) delete mode 100644 firmware/nem_mosaics.c delete mode 100644 firmware/nem_mosaics.h diff --git a/firmware/.gitignore b/firmware/.gitignore index 248dabf294..be84b50dd3 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,2 +1,4 @@ coins_array.h coins_count.h + +nem_mosaics.[ch] diff --git a/firmware/nem_mosaics.c b/firmware/nem_mosaics.c deleted file mode 100644 index 7a9cecbe01..0000000000 --- a/firmware/nem_mosaics.c +++ /dev/null @@ -1,104 +0,0 @@ -// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! - -#include "nem_mosaics.h" - -const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {{ - .has_name = true, - .name = "XEM", - .has_ticker = true, - .ticker = " XEM", - .has_namespace = true, - .namespace = "nem", - .has_mosaic = true, - .mosaic = "xem", - .has_divisibility = true, - .divisibility = 6, -}, -{ - .has_name = true, - .name = "DIMCOIN", - .has_ticker = true, - .ticker = " DIM", - .has_namespace = true, - .namespace = "dim", - .has_mosaic = true, - .mosaic = "coin", - .has_divisibility = true, - .divisibility = 6, - .has_levy = true, - .levy = NEMMosaicLevy_MosaicLevy_Percentile, - .has_fee = true, - .fee = 10, - .has_levy_namespace = true, - .levy_namespace = "dim", - .has_levy_mosaic = true, - .levy_mosaic = "coin", - .networks_count = 1, - .networks = { 104 }, -}, -{ - .has_name = true, - .name = "DIM TOKEN", - .has_ticker = true, - .ticker = " DIMTOK", - .has_namespace = true, - .namespace = "dim", - .has_mosaic = true, - .mosaic = "token", - .has_divisibility = true, - .divisibility = 6, - .networks_count = 1, - .networks = { 104 }, -}, -{ - .has_name = true, - .name = "Breeze Token", - .has_ticker = true, - .ticker = " BREEZE", - .has_namespace = true, - .namespace = "breeze", - .has_mosaic = true, - .mosaic = "breeze-token", - .has_divisibility = true, - .divisibility = 0, - .networks_count = 1, - .networks = { 104 }, -}, -{ - .has_name = true, - .name = "PacNEM Game Credits", - .has_ticker = true, - .ticker = " PAC:HRT", - .has_namespace = true, - .namespace = "pacnem", - .has_mosaic = true, - .mosaic = "heart", - .has_divisibility = true, - .divisibility = 0, - .networks_count = 1, - .networks = { 104 }, -}, -{ - .has_name = true, - .name = "PacNEM Score Tokens", - .has_ticker = true, - .ticker = " PAC:CHS", - .has_namespace = true, - .namespace = "pacnem", - .has_mosaic = true, - .mosaic = "cheese", - .has_divisibility = true, - .divisibility = 6, - .has_levy = true, - .levy = NEMMosaicLevy_MosaicLevy_Percentile, - .has_fee = true, - .fee = 100, - .has_levy_namespace = true, - .levy_namespace = "nem", - .has_levy_mosaic = true, - .levy_mosaic = "xem", - .networks_count = 1, - .networks = { 104 }, -}}; - -const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h b/firmware/nem_mosaics.h deleted file mode 100644 index ae756f4319..0000000000 --- a/firmware/nem_mosaics.h +++ /dev/null @@ -1,13 +0,0 @@ -// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! - -#ifndef __NEM_MOSAICS_H__ -#define __NEM_MOSAICS_H__ - -#include "types.pb.h" - -#define NEM_MOSAIC_DEFINITIONS_COUNT (6) - -extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; -extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; - -#endif From c87c16adc9746263c8556645ea19c35753887bc3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 9 Oct 2017 17:48:30 +0100 Subject: [PATCH 0605/1154] firmware: Generate nem_mosaics.[ch] at build time --- firmware/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/Makefile b/firmware/Makefile index 99422c4417..29e617a65d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -105,6 +105,8 @@ bootloader.o: ../fastflash/bootloader.bin coins.c crypto.c fsm.c transaction.c: coins_count.h coins.c: coins_array.h +nem2.c layout2.c: nem_mosaics.h + ################# # Code Generation coins_count.h: coins-gen.py coins.json @@ -113,5 +115,9 @@ coins_count.h: coins-gen.py coins.json coins_array.h: coins-gen.py coins.json ./$< array > $@ +nem_mosaics.c nem_mosaics.h: nem_mosaics.py nem_mosaics.json + ./$< + clean:: rm -f coins_count.h coins_array.h + rm -f nem_mosaics.c nem_mosaics.h From 128742d113dad2a5889093864f7f4a8ca5762f68 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 9 Oct 2017 17:49:13 +0100 Subject: [PATCH 0606/1154] nem2: Update copyright header for consistency --- firmware/nem2.c | 2 +- firmware/nem2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/nem2.c b/firmware/nem2.c index d44afba12a..67c0089ece 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -1,7 +1,7 @@ /* * This file is part of the TREZOR project. * - * Copyright (C) 2017 Saleem Rashid + * Copyright (C) 2017 Saleem Rashid * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by diff --git a/firmware/nem2.h b/firmware/nem2.h index 4639bd0081..34d1afeea1 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -1,7 +1,7 @@ /* * This file is part of the TREZOR project. * - * Copyright (C) 2017 Saleem Rashid + * Copyright (C) 2017 Saleem Rashid * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by From 296c1205281fd41762e7c362091078e9fe7141c1 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 9 Oct 2017 18:06:02 +0100 Subject: [PATCH 0607/1154] nem_mosaics: Refactor and use Python 2 --- firmware/nem_mosaics.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index 243568958c..cb652067ba 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -1,8 +1,13 @@ -#!/usr/bin/env python3 -import json, os +#!/usr/bin/env python2 +import json, os, sys + +import collections, numbers + from google.protobuf import json_format from itertools import chain -import protob.types_pb2 as types + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "protob")) +import types_pb2 as types HEADER_TEMPLATE = """ // This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! @@ -31,13 +36,13 @@ const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; """.lstrip() def format_primitive(value): - if type(value) is bool: + if isinstance(value, bool): return ("false", "true")[value] - elif type(value) in (int, float): + elif isinstance(value, numbers.Number): return str(value) - elif type(value) is str: + elif isinstance(value, basestring): return json.dumps(value) - elif type(value) is list: + elif isinstance(value, collections.Sequence): return "{ " + ", ".join( format_primitive(item) for item in value ) + " }" @@ -61,14 +66,14 @@ def format_field(field, value): return format_primitive(value) def field_to_meta(field, value): - if hasattr(value, "_values"): - return ("{}_count".format(field.name), format_primitive(len(value._values))) + if field.label == field.LABEL_REPEATED: + return ("{}_count".format(field.name), format_primitive(len(value))) else: return ("has_{}".format(field.name), format_primitive(True)) def message_to_struct(_message, proto): message = json_format.ParseDict(_message, proto()) - return dict(chain.from_iterable( + return collections.OrderedDict(chain.from_iterable( ( field_to_meta(field, value), (field.name, format_field(field, value)), From 85da1ac671dde1110a94feea22885381d05e1f98 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 9 Oct 2017 18:12:46 +0100 Subject: [PATCH 0608/1154] travis.yml: Download protoc from GitHub --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8fc80d9b4e..1b354cfec4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,26 +8,29 @@ addons: - build-essential - gcc-arm-none-eabi - libnewlib-arm-none-eabi - - protobuf-compiler - - libprotobuf-dev - - python-protobuf env: global: - MAKEFLAGS=-j2 + - PROTOBUF_VERSION=3.4.0 matrix: - DEBUG_LINK=0 FASTFLASH=0 - DEBUG_LINK=1 FASTFLASH=0 - DEBUG_LINK=0 FASTFLASH=1 - DEBUG_LINK=1 FASTFLASH=1 +install: + - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" + - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc + - export PATH="$(pwd)/protoc/bin:$PATH" + - pip2 install --user "protobuf==${PROTOBUF_VERSION}" + script: - make -C vendor/libopencm3 lib/stm32/f2 - make -C vendor/nanopb/generator/proto - make - make -C bootloader - make -C fastflash - - sed -i '/, deprecated = true/d' firmware/protob/messages.proto # protobuf 2.5 compatibility :-/ - make -C firmware/protob - make -C firmware - make -C demo From 15eefd564621028ebd8af2f6031ab98f618112ad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Oct 2017 21:08:11 +0200 Subject: [PATCH 0609/1154] update submodules --- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index b9a2a9c3de..34bd9e50b6 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit b9a2a9c3defd8a4b84d674116cbae2cf46b6080b +Subproject commit 34bd9e50b6470a8d60d2cac56cf409f046829f62 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 636320da58..56114cc0a6 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 636320da585ddb5f5c26257cfb724efd34cde50b +Subproject commit 56114cc0a6e1b6817262bf886d775ec9de400d8e From b56da1e4b424c5f4231daeef0082ca63ce6ec545 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Oct 2017 21:05:59 +0200 Subject: [PATCH 0610/1154] layout: show path for CoSi commit/sign if following SLIP-0018 --- firmware/fsm.c | 4 ++-- firmware/layout2.c | 17 ++++++++++++++--- firmware/layout2.h | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 564336fcc2..f32e700c5c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1343,7 +1343,7 @@ void fsm_msgCosiCommit(CosiCommit *msg) CHECK_PARAM(msg->has_data, _("No data provided")); - layoutCosiCommitSign(msg->data.bytes, msg->data.size, false); + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -1383,7 +1383,7 @@ void fsm_msgCosiSign(CosiSign *msg) CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); - layoutCosiCommitSign(msg->data.bytes, msg->data.size, true); + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/firmware/layout2.c b/firmware/layout2.c index 0ffd7aa6d7..78d7869f54 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -645,8 +645,20 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { } } -void layoutCosiCommitSign(const uint8_t *data, uint32_t len, bool final_sign) +void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign) { + char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); + if (address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9) { + char desc_buf[32]; + if (final_sign) { + strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); + desc_buf[16] = '0' + (address_n[1] & 0x7FFFFFFF); + } else { + strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf)); + desc_buf[18] = '0' + (address_n[1] & 0x7FFFFFFF); + } + desc = desc_buf; + } char str[4][17]; if (len == 32) { data2hex(data , 8, str[0]); @@ -659,7 +671,6 @@ void layoutCosiCommitSign(const uint8_t *data, uint32_t len, bool final_sign) strlcpy(str[2], "unsupported", sizeof(str[2])); strlcpy(str[3], "length", sizeof(str[3])); } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - final_sign ? _("CoSi sign message?") : _("CoSi commit message?"), + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, str[0], str[1], str[2], str[3], NULL, NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index d87c80e418..3747914cad 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -57,6 +57,6 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encryp void layoutNEMMosaicDescription(const char *description); void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); -void layoutCosiCommitSign(const uint8_t *data, uint32_t len, bool final_sign); +void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); #endif From ca30449d07976571267e47690980cf7970611b83 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Oct 2017 21:23:18 +0200 Subject: [PATCH 0611/1154] build: add rebuild dep --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 29e617a65d..6f0f921aa1 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -105,7 +105,7 @@ bootloader.o: ../fastflash/bootloader.bin coins.c crypto.c fsm.c transaction.c: coins_count.h coins.c: coins_array.h -nem2.c layout2.c: nem_mosaics.h +nem2.c layout2.c fsm.c: nem_mosaics.h ################# # Code Generation From 5831e53854de85b27155692a808d924be992f879 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 9 Oct 2017 23:02:42 +0200 Subject: [PATCH 0612/1154] layout2: refactor and fix layoutCosiCommitSign --- firmware/layout2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 78d7869f54..6e8fbb2e6e 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -645,11 +645,16 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { } } +static inline bool is_slip18(const uint32_t *address_n, size_t address_n_count) +{ + return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9; +} + void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign) { char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); - if (address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9) { - char desc_buf[32]; + char desc_buf[32]; + if (is_slip18(address_n, address_n_count)) { if (final_sign) { strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); desc_buf[16] = '0' + (address_n[1] & 0x7FFFFFFF); From d006ef6bf7edfa2334fa4d03f004aa09d072526a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 10 Oct 2017 19:54:21 +0100 Subject: [PATCH 0613/1154] Makefile.include: Generate dependency files before build (#225) * Makefile.include: Generate .d files before build * Makefile.include: Generate .small.d files before build --- Makefile.include | 10 ++++++++-- firmware/Makefile | 8 -------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Makefile.include b/Makefile.include index cd4813fe31..d01ccbdda3 100644 --- a/Makefile.include +++ b/Makefile.include @@ -134,10 +134,16 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP $(AS) $(CPUFLAGS) -o $@ $< %.o: %.c Makefile - $(CC) $(CFLAGS) -MMD -o $@ -c $< + $(CC) $(CFLAGS) -MMD -MP -o $@ -c $< %.small.o: %.c Makefile - $(CC) $(CFLAGS) -MMD -o $@ -c $< + $(CC) $(CFLAGS) -MMD -MP -o $@ -c $< + +%.d: %.c Makefile + @$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< + +%.small.d: %.c Makefile + @$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< clean:: rm -f $(OBJS) diff --git a/firmware/Makefile b/firmware/Makefile index 6f0f921aa1..b0b9dcf166 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -101,14 +101,6 @@ bootloader.o: ../fastflash/bootloader.bin --rename-section .data=.rodata \ $< $@ -# ensure header files are generated prior to compiling sources -coins.c crypto.c fsm.c transaction.c: coins_count.h -coins.c: coins_array.h - -nem2.c layout2.c fsm.c: nem_mosaics.h - -################# -# Code Generation coins_count.h: coins-gen.py coins.json ./$< count > $@ From 6edb97133baebb58751dcfd688ed4a316279eddb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 29 Oct 2017 21:50:38 +0100 Subject: [PATCH 0614/1154] build: use recent protobuf in docker --- Dockerfile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ecca657a37..c92ec89f51 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,5 +5,10 @@ FROM debian:9 # install build tools and dependencies RUN apt-get update && apt-get install -y \ - build-essential git python python-ecdsa gcc-arm-none-eabi \ - protobuf-compiler libprotobuf-dev python-protobuf + build-essential git python python-ecdsa gcc-arm-none-eabi curl +RUN apt-get install -y unzip python-pip + +ENV PROTOBUF_VERSION=3.4.0 +RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" +RUN unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d /usr +RUN pip2 install "protobuf==${PROTOBUF_VERSION}" From eebd53fd09f507042e21c7ca741484ac5f051e2a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 3 Nov 2017 17:54:02 +0000 Subject: [PATCH 0615/1154] layout2: Disable oledSwipeLeft with DEBUG_LINK (#239) This greatly reduces time for device tests --- firmware/layout2.c | 19 ++++++++++++++----- firmware/layout2.h | 3 +++ firmware/pinmatrix.c | 3 ++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 6e8fbb2e6e..8df08f2c01 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -38,10 +38,19 @@ void *layoutLast = layoutHome; +void layoutSwipe(void) { +#if DEBUG_LINK + oledClear(); +#else + oledSwipeLeft(); +#endif +} + + void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { layoutLast = layoutDialogSwipe; - oledSwipeLeft(); + layoutSwipe(); layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, line6); } @@ -51,7 +60,7 @@ void layoutProgressSwipe(const char *desc, int permil) oledClear(); } else { layoutLast = layoutProgressSwipe; - oledSwipeLeft(); + layoutSwipe(); } layoutProgress(desc, permil); } @@ -68,7 +77,7 @@ void layoutHome(void) if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { oledClear(); } else { - oledSwipeLeft(); + layoutSwipe(); } layoutLast = layoutHome; const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start"); @@ -225,7 +234,7 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) void layoutResetWord(const char *word, int pass, int word_pos, bool last) { layoutLast = layoutResetWord; - oledSwipeLeft(); + layoutSwipe(); const char *btnYes; if (last) { @@ -280,7 +289,7 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) void layoutAddress(const char *address, const char *desc, bool qrcode) { if (layoutLast != layoutAddress) { - oledSwipeLeft(); + layoutSwipe(); } else { oledClear(); } diff --git a/firmware/layout2.h b/firmware/layout2.h index 3747914cad..7de41cf0e4 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -24,9 +24,12 @@ #include "types.pb.h" #include "bitmaps.h" #include "bignum.h" +#include "trezor.h" extern void *layoutLast; +void layoutSwipe(void); + void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index b55bfe0f4e..3328ab0465 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -20,6 +20,7 @@ #include #include "pinmatrix.h" +#include "layout2.h" #include "oled.h" #include "rng.h" @@ -31,7 +32,7 @@ void pinmatrix_draw(const char *text) &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, }; - oledSwipeLeft(); + layoutSwipe(); const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { From fa02dec70475fb55c08bf5414bb78dd2f2a8879a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 3 Nov 2017 18:56:55 +0100 Subject: [PATCH 0616/1154] layout2: use macro for layoutSwipe --- firmware/layout2.c | 9 --------- firmware/layout2.h | 6 +++++- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 8df08f2c01..1522442ddb 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -38,15 +38,6 @@ void *layoutLast = layoutHome; -void layoutSwipe(void) { -#if DEBUG_LINK - oledClear(); -#else - oledSwipeLeft(); -#endif -} - - void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { layoutLast = layoutDialogSwipe; diff --git a/firmware/layout2.h b/firmware/layout2.h index 7de41cf0e4..a2bdfdee73 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -28,7 +28,11 @@ extern void *layoutLast; -void layoutSwipe(void); +#if DEBUG_LINK +#define layoutSwipe oledClear +#else +#define layoutSwipe oledSwipeLeft +#endif void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); From 5e98b0ffd6fd679c07b04f9eaa1b04db63fd7216 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 3 Nov 2017 18:57:50 +0100 Subject: [PATCH 0617/1154] Added U2F entry for Bitfinex (#237) --- firmware/u2f_knownapps.h | 9 +++++++++ gen/bitmaps.c | 2 ++ gen/bitmaps.h | 1 + gen/bitmaps/u2f_bitfinex.png | Bin 0 -> 285 bytes 4 files changed, 12 insertions(+) create mode 100644 gen/bitmaps/u2f_bitfinex.png diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 3279262c55..0d7b38cb1a 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -103,6 +103,15 @@ static const U2FWellKnown u2f_well_known[] = { "Gandi", &bmp_u2f_gandi, }, + { + // https://www.bitfinex.com + { 0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, + 0xfe, 0xbb, 0x30, 0xe7, 0x32, 0x69, 0xec, 0xa5, + 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, 0x0b, 0xf7, + 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63 }, + "Bitfinex", + &bmp_u2f_bitfinex + }, { // https://demo.yubico.com { 0x55, 0x67, 0x3b, 0x51, 0x38, 0xcc, 0x90, 0xd3, diff --git a/gen/bitmaps.c b/gen/bitmaps.c index f2e69441da..b86073fd2a 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -24,6 +24,7 @@ const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; +const uint8_t bmp_u2f_bitfinex_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xa0, 0x00, 0x0f, 0xff, 0x20, 0x00, 0x3f, 0xff, 0x60, 0x00, 0x7f, 0xfe, 0xe0, 0x00, 0xff, 0xfc, 0xe0, 0x01, 0xff, 0xf1, 0xe0, 0x01, 0xff, 0xe3, 0xe0, 0x03, 0xff, 0xc7, 0xe0, 0x03, 0xff, 0x8f, 0xc0, 0x07, 0xfe, 0x0f, 0xc0, 0x07, 0xfc, 0x1f, 0xc0, 0x07, 0xf0, 0x7f, 0x80, 0x07, 0x80, 0xff, 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_fastmail_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x4f, 0xff, 0xff, 0xf2, 0x67, 0xff, 0xff, 0xe6, 0x73, 0xff, 0xff, 0xce, 0x79, 0xff, 0xff, 0x9e, 0x7c, 0xff, 0xff, 0x3e, 0x7e, 0x7f, 0xfe, 0x7e, 0x7f, 0x3f, 0xfc, 0xfe, 0x7f, 0x9f, 0xf9, 0xfe, 0x7f, 0xcf, 0xf3, 0xfe, 0x7f, 0xe7, 0xe7, 0xfe, 0x7f, 0xf3, 0xcf, 0xfe, 0x7f, 0xf8, 0x1f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_gandi_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x01, 0x8f, 0xe1, 0x00, 0x03, 0xc7, 0xc3, 0x80, 0x03, 0xe0, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x30, 0x00, 0x00, 0xf0, 0xfc, 0x00, 0x00, 0xf1, 0xfe, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf1, 0xcf, 0x00, 0x00, 0xf0, 0x8f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, }; @@ -57,6 +58,7 @@ const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data}; const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; +const BITMAP bmp_u2f_bitfinex = {32, 32, bmp_u2f_bitfinex_data}; const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; const BITMAP bmp_u2f_fastmail = {32, 32, bmp_u2f_fastmail_data}; const BITMAP bmp_u2f_gandi = {32, 32, bmp_u2f_gandi_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index 2a348e2e34..29f7b5b064 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -32,6 +32,7 @@ extern const BITMAP bmp_logo48_empty; extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; extern const BITMAP bmp_u2f_bitbucket; +extern const BITMAP bmp_u2f_bitfinex; extern const BITMAP bmp_u2f_dropbox; extern const BITMAP bmp_u2f_fastmail; extern const BITMAP bmp_u2f_gandi; diff --git a/gen/bitmaps/u2f_bitfinex.png b/gen/bitmaps/u2f_bitfinex.png new file mode 100644 index 0000000000000000000000000000000000000000..48a1048456d5dea18014964b630db2f0e6a4cd9b GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7a$D;Kb?2i11Zh|kH}&M z25w;xW@MN(M*=9wUgGKN%Kng>kz0=MA8QXinf?Q%OpAXxT-~~C=FWKytT(DySG{7JA3E=y!{P#k3LfJJ^$GrUD+OH-`Z9IgQr=m#>eEy;wxGS?8M?AF8q-~@{TL31 z<;XVZDZAZkk^8VIHXyQemcv)I5@843pD*+}ejN^L5fqY4=JGw*!}F@`g2cZ5lga^t Z@{3KwY*#I_ivhZt!PC{xWt~$(6977sWiS8$ literal 0 HcmV?d00001 From 4805f27e8cd77a87ebdc88618c16a90e6257bd44 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 10 Oct 2017 16:05:42 +0200 Subject: [PATCH 0618/1154] Fix checking change address There was a signed/unsigned problem: size_t is unsigned, but we use -1 to indicate mismatch. The problem was that when checking the input address path, it still did this unintentionally when a mismatch was detected, forbidding to sign with mismatched inputs, even when there is no change address. We now use 1 for mismatch. Also we don't allow change address anymore if the inputs have a path of length 1. This simplifies the code a bit. --- firmware/signing.c | 62 +++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index b8aaaa0823..4bd1ecccb7 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -68,6 +68,12 @@ static uint8_t multisig_fp[32]; static uint32_t in_address_n[8]; static size_t in_address_n_count; +/* marker for in_address_n_count to indicate a mismatch in bip32 paths in + input */ +#define BIP32_NOCHANGEALLOWED 1 +/* maximum allowed change index */ +#define MAX_BIP32_LAST_ELEMENT 1000000 + enum { SIGHASH_ALL = 1, SIGHASH_FORKID = 0x40, @@ -328,61 +334,45 @@ void phase2_request_next_input(void) void extract_input_bip32_path(const TxInputType *tinput) { - if (in_address_n_count == (size_t) -1) { + if (in_address_n_count == BIP32_NOCHANGEALLOWED) { return; } size_t count = tinput->address_n_count; - if (count < 1) { + if (count < 2) { // no change address allowed - in_address_n_count = (size_t) -1; + in_address_n_count = BIP32_NOCHANGEALLOWED; return; } if (in_address_n_count == 0) { // initialize in_address_n on first input seen in_address_n_count = count; - if (count > 2) { // if longer than 2 elements, store first N - 2 - memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); - } + // store first N - 2 + memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); return; } // check whether they are same length if (in_address_n_count != count) { - in_address_n_count = (size_t) -1; + in_address_n_count = BIP32_NOCHANGEALLOWED; return; } - if (count > 2 && memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { + if (memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { // mismatch -> no change address allowed - in_address_n_count = (size_t) -1; + in_address_n_count = BIP32_NOCHANGEALLOWED; return; } } -#define MAX_BIP32_LAST_ELEMENT 1000000 - bool check_change_bip32_path(const TxOutputType *toutput) { size_t count = toutput->address_n_count; - if (count < 1 || in_address_n_count < 1) { - return 0; - } - - if (count != in_address_n_count) { - return 0; - } - - if (toutput->address_n[count - 1] > MAX_BIP32_LAST_ELEMENT) { - return 0; - } - - if (count >= 2) { - if (0 != memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) || - toutput->address_n[count - 2] != 1) { - return 0; - } - } - - return 1; + // Note: count >= 2 and count == in_address_n_count + // imply that in_address_n_count != BIP32_NOCHANGEALLOWED + return (count >= 2 + && count == in_address_n_count + && 0 == memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) + && toutput->address_n[count - 2] == 1 + && toutput->address_n[count - 1] <= MAX_BIP32_LAST_ELEMENT); } bool compile_input_script_sig(TxInputType *tinput) @@ -397,14 +387,12 @@ bool compile_input_script_sig(TxInputType *tinput) return false; } } - if (in_address_n_count >= 1) { + if (in_address_n_count != BIP32_NOCHANGEALLOWED) { // check that input address didn't change size_t count = tinput->address_n_count; - if (count != in_address_n_count) { - return false; - } - if (count >= 2 - && 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) { + if (count < 2 + || count != in_address_n_count + || 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) { return false; } } From a24e8a048426c771511f4ed99509ba994c07e95b Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 30 Oct 2017 12:20:47 +0100 Subject: [PATCH 0619/1154] Remove magic constants Use defines for wallet depth and change chain. Updated some comments to clarify what is checked. --- firmware/signing.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 4bd1ecccb7..05e6c2666f 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -68,11 +68,16 @@ static uint8_t multisig_fp[32]; static uint32_t in_address_n[8]; static size_t in_address_n_count; -/* marker for in_address_n_count to indicate a mismatch in bip32 paths in +/* A marker for in_address_n_count to indicate a mismatch in bip32 paths in input */ #define BIP32_NOCHANGEALLOWED 1 -/* maximum allowed change index */ -#define MAX_BIP32_LAST_ELEMENT 1000000 +/* The number of bip32 levels used in a wallet (chain and address) */ +#define BIP32_WALLET_DEPTH 2 +/* The chain id used for change */ +#define BIP32_CHANGE_CHAIN 1 +/* The maximum allowed change address. This should be large enough for normal + use and still allow to quickly brute-force the correct bip32 path. */ +#define BIP32_MAX_LAST_ELEMENT 1000000 enum { SIGHASH_ALL = 1, @@ -338,7 +343,7 @@ void extract_input_bip32_path(const TxInputType *tinput) return; } size_t count = tinput->address_n_count; - if (count < 2) { + if (count < BIP32_WALLET_DEPTH) { // no change address allowed in_address_n_count = BIP32_NOCHANGEALLOWED; return; @@ -346,16 +351,19 @@ void extract_input_bip32_path(const TxInputType *tinput) if (in_address_n_count == 0) { // initialize in_address_n on first input seen in_address_n_count = count; - // store first N - 2 - memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); + // store the bip32 path up to the account + memcpy(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)); return; } - // check whether they are same length + // check that all addresses use a path of same length if (in_address_n_count != count) { in_address_n_count = BIP32_NOCHANGEALLOWED; return; } - if (memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { + // check that the bip32 path up to the account matches + if (memcmp(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) != 0) { // mismatch -> no change address allowed in_address_n_count = BIP32_NOCHANGEALLOWED; return; @@ -366,13 +374,17 @@ bool check_change_bip32_path(const TxOutputType *toutput) { size_t count = toutput->address_n_count; - // Note: count >= 2 and count == in_address_n_count + // Check that the change path has the same bip32 path length, + // the same path up to the account, and that the wallet components + // (chain id and address) are as expected. + // Note: count >= BIP32_WALLET_DEPTH and count == in_address_n_count // imply that in_address_n_count != BIP32_NOCHANGEALLOWED - return (count >= 2 + return (count >= BIP32_WALLET_DEPTH && count == in_address_n_count - && 0 == memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) - && toutput->address_n[count - 2] == 1 - && toutput->address_n[count - 1] <= MAX_BIP32_LAST_ELEMENT); + && 0 == memcmp(in_address_n, toutput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) + && toutput->address_n[count - 2] == BIP32_CHANGE_CHAIN + && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } bool compile_input_script_sig(TxInputType *tinput) From 18d8cb3c56f6164e69565ee78e3c6dcef04b81dc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 5 Nov 2017 17:46:34 +0100 Subject: [PATCH 0620/1154] add project website (trezor.io) to license header --- bootloader/bootloader.c | 2 +- bootloader/bootloader.h | 2 +- bootloader/signatures.c | 2 +- bootloader/signatures.h | 2 +- bootloader/usb.c | 2 +- bootloader/usb.h | 2 +- buttons.c | 2 +- buttons.h | 2 +- demo/demo.c | 2 +- fastflash/signatures.c | 2 +- firmware/coins.c | 2 +- firmware/coins.h | 2 +- firmware/crypto.c | 2 +- firmware/crypto.h | 2 +- firmware/debug.c | 2 +- firmware/debug.h | 2 +- firmware/ethereum.c | 2 +- firmware/ethereum.h | 2 +- firmware/ethereum_tokens.h | 2 +- firmware/fastflash.c | 2 +- firmware/fastflash.h | 2 +- firmware/fsm.c | 2 +- firmware/fsm.h | 2 +- firmware/gettext.h | 2 +- firmware/layout2.c | 2 +- firmware/layout2.h | 2 +- firmware/messages.c | 2 +- firmware/messages.h | 2 +- firmware/nem2.c | 2 +- firmware/nem2.h | 2 +- firmware/pinmatrix.c | 2 +- firmware/pinmatrix.h | 2 +- firmware/protect.c | 2 +- firmware/protect.h | 2 +- firmware/recovery-table.h | 2 +- firmware/recovery.c | 2 +- firmware/recovery.h | 2 +- firmware/reset.c | 2 +- firmware/reset.h | 2 +- firmware/signing.c | 2 +- firmware/signing.h | 2 +- firmware/storage.c | 2 +- firmware/storage.h | 2 +- firmware/transaction.c | 2 +- firmware/transaction.h | 2 +- firmware/trezor.c | 2 +- firmware/trezor.h | 2 +- firmware/u2f.c | 2 +- firmware/u2f.h | 2 +- firmware/u2f_knownapps.h | 2 +- firmware/usb.c | 2 +- firmware/usb.h | 2 +- gen/wordlist/build-recovery-table.pl | 2 +- layout.c | 2 +- layout.h | 2 +- memory.c | 2 +- memory.h | 2 +- oled.c | 2 +- oled.h | 2 +- rng.c | 2 +- rng.h | 2 +- serialno.c | 2 +- serialno.h | 2 +- setup.c | 2 +- setup.h | 2 +- timer.c | 2 +- timer.h | 2 +- util.c | 2 +- util.h | 2 +- 69 files changed, 69 insertions(+), 69 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 6a7ba9e05e..6a9e71f528 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 7324909cf1..ee4b8722d4 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/bootloader/signatures.c b/bootloader/signatures.c index 0b6ea5b9f6..c49901e671 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/bootloader/signatures.h b/bootloader/signatures.h index 019609346d..60037d69a5 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/bootloader/usb.c b/bootloader/usb.c index 42dee2c977..d3498dbd0c 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/bootloader/usb.h b/bootloader/usb.h index 5b2782c878..fea6e680e7 100644 --- a/bootloader/usb.h +++ b/bootloader/usb.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/buttons.c b/buttons.c index 5bac9dcd55..9207eac00c 100644 --- a/buttons.c +++ b/buttons.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/buttons.h b/buttons.h index 3091081494..140e380c66 100644 --- a/buttons.h +++ b/buttons.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/demo/demo.c b/demo/demo.c index 86c4c13a40..7a92d15b1d 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/fastflash/signatures.c b/fastflash/signatures.c index d452a067d6..556dd6a946 100644 --- a/fastflash/signatures.c +++ b/fastflash/signatures.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Saleem Rashid * diff --git a/firmware/coins.c b/firmware/coins.c index f2f69a0d18..ae914f777b 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/coins.h b/firmware/coins.h index a00fa27049..0ffc55eb7a 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/crypto.c b/firmware/crypto.c index e81eb6f146..7679706ca1 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/crypto.h b/firmware/crypto.h index 2c52cb330f..7caf6ed133 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/debug.c b/firmware/debug.c index fd72ed29b8..b455f290c6 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/debug.h b/firmware/debug.h index 93cfd0f36b..94f9a0642a 100644 --- a/firmware/debug.h +++ b/firmware/debug.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 67a7590247..48a8496625 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Alex Beregszaszi * Copyright (C) 2016 Pavol Rusnak diff --git a/firmware/ethereum.h b/firmware/ethereum.h index de8866242d..5327b845fb 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Alex Beregszaszi * diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index ddc40b3b42..5f3499f4d8 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/fastflash.c b/firmware/fastflash.c index 25f33e5d30..7d7d8600b9 100644 --- a/firmware/fastflash.c +++ b/firmware/fastflash.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Saleem Rashid * diff --git a/firmware/fastflash.h b/firmware/fastflash.h index e35b443675..fe8bc05a9a 100644 --- a/firmware/fastflash.h +++ b/firmware/fastflash.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Saleem Rashid * diff --git a/firmware/fsm.c b/firmware/fsm.c index f32e700c5c..4ff14c90ec 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/fsm.h b/firmware/fsm.h index a738ab59cb..41f2cb123e 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/gettext.h b/firmware/gettext.h index c663dfbc2a..bad59943e0 100644 --- a/firmware/gettext.h +++ b/firmware/gettext.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Pavol Rusnak * diff --git a/firmware/layout2.c b/firmware/layout2.c index 1522442ddb..e17f2566f3 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/layout2.h b/firmware/layout2.h index a2bdfdee73..f64ee2a7c1 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/messages.c b/firmware/messages.c index d5d2ba553c..15c510bd99 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/messages.h b/firmware/messages.h index ac481101e6..e0a5c8b6fc 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/nem2.c b/firmware/nem2.c index 67c0089ece..a2be49c00c 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Saleem Rashid * diff --git a/firmware/nem2.h b/firmware/nem2.h index 34d1afeea1..ed7c90fba1 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2017 Saleem Rashid * diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 3328ab0465..39f60fc874 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/pinmatrix.h b/firmware/pinmatrix.h index 9c6c312937..a1c70bd9f7 100644 --- a/firmware/pinmatrix.h +++ b/firmware/pinmatrix.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/protect.c b/firmware/protect.c index 5c3881c4fa..82a1989170 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/protect.h b/firmware/protect.h index 4a7a361644..efa6163cfb 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/recovery-table.h b/firmware/recovery-table.h index ebf40753fd..0efb114553 100644 --- a/firmware/recovery-table.h +++ b/firmware/recovery-table.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Jochen Hoenicke * diff --git a/firmware/recovery.c b/firmware/recovery.c index deb59cc379..bdc1485dea 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * Copyright (C) 2016 Jochen Hoenicke diff --git a/firmware/recovery.h b/firmware/recovery.h index fdd61dc453..d0a63508ea 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/reset.c b/firmware/reset.c index 8217d27317..a5532013d0 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/reset.h b/firmware/reset.h index 65b0230890..a4c54c5a9b 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/signing.c b/firmware/signing.c index 05e6c2666f..1673fd9fed 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/signing.h b/firmware/signing.h index ef1b9914ee..cec7933d72 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/storage.c b/firmware/storage.c index a7a4ee3ce0..c8f264d4a2 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/storage.h b/firmware/storage.h index 0b27f3f200..37235a0af3 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/transaction.c b/firmware/transaction.c index 199045f212..70ab0f1b53 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/transaction.h b/firmware/transaction.h index f43dd1ec29..d3ea1ea0fb 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/trezor.c b/firmware/trezor.c index 15ce9fbe79..9c0dac40ea 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/trezor.h b/firmware/trezor.h index 7abbe9ce8a..1bcb3cd9ff 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/u2f.c b/firmware/u2f.c index 41c1f33452..bd0b51f6ef 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2015 Mark Bryars * diff --git a/firmware/u2f.h b/firmware/u2f.h index 6ed7f02f06..9eb0cca620 100644 --- a/firmware/u2f.h +++ b/firmware/u2f.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2015 Mark Bryars * diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 0d7b38cb1a..299622de08 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Jochen Hoenicke * diff --git a/firmware/usb.c b/firmware/usb.c index 9b7085337f..deae841d64 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/firmware/usb.h b/firmware/usb.h index 318a5a4ad2..46426777f6 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/gen/wordlist/build-recovery-table.pl b/gen/wordlist/build-recovery-table.pl index c67325f532..60d12eb8df 100644 --- a/gen/wordlist/build-recovery-table.pl +++ b/gen/wordlist/build-recovery-table.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl print <<'EOF'; /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Jochen Hoenicke * diff --git a/layout.c b/layout.c index 28a71ac9f5..98e6e59960 100644 --- a/layout.c +++ b/layout.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/layout.h b/layout.h index 27f81d49e6..5ea34ec335 100644 --- a/layout.h +++ b/layout.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/memory.c b/memory.c index 76014806d1..da07841913 100644 --- a/memory.c +++ b/memory.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/memory.h b/memory.h index 3d9c8914a2..fb5d8af5a9 100644 --- a/memory.h +++ b/memory.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/oled.c b/oled.c index 52116f20ef..6daee8a92f 100644 --- a/oled.c +++ b/oled.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/oled.h b/oled.h index f5e711e1ea..9c5531a99d 100644 --- a/oled.h +++ b/oled.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/rng.c b/rng.c index 1df238e872..2220947642 100644 --- a/rng.c +++ b/rng.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/rng.h b/rng.h index 3e25c0eedd..f3fa07323a 100644 --- a/rng.h +++ b/rng.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/serialno.c b/serialno.c index e16f31afa9..c621f95471 100644 --- a/serialno.c +++ b/serialno.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/serialno.h b/serialno.h index 82fe483a25..4e157f9ce5 100644 --- a/serialno.h +++ b/serialno.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/setup.c b/setup.c index b84bdd37db..4dda1b7c01 100644 --- a/setup.c +++ b/setup.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/setup.h b/setup.h index 4e6865fef2..c5236fc341 100644 --- a/setup.h +++ b/setup.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/timer.c b/timer.c index bd19990049..7a3dfcfb36 100644 --- a/timer.c +++ b/timer.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Saleem Rashid * diff --git a/timer.h b/timer.h index a8753ee920..235ba5f317 100644 --- a/timer.h +++ b/timer.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2016 Saleem Rashid * diff --git a/util.c b/util.c index 36b9449e7d..09eba316eb 100644 --- a/util.c +++ b/util.c @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * diff --git a/util.h b/util.h index 8e4c6cefdc..1494cb6f46 100644 --- a/util.h +++ b/util.h @@ -1,5 +1,5 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ * * Copyright (C) 2014 Pavol Rusnak * From b5fa8a266a26c03322a9c0ac05683e9dc05ab415 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 30 Oct 2017 22:13:09 +0100 Subject: [PATCH 0621/1154] New CoinInfo separated from protobuf structures Having CoinType using the protobuf structures has several disadvantages. - We always need to change trezor-common if we need a new field (like bech32 prefix) - Every time Trezor initializes it sends all this information out and nobody cares. - The protobuf structures add storage overhead due to their fixed size. I also removed most of the `has_` fields except for forkid: - `has_segwit` was merged with segwit - `has_coin_shortcut` can be replaced by test for NULL if necessary. The fields were reordered for better padding. --- firmware/coins-gen.py | 28 ++++++---------------------- firmware/coins.c | 13 ++++++------- firmware/coins.h | 30 +++++++++++++++++++++++------- firmware/crypto.c | 4 ++-- firmware/crypto.h | 5 +++-- firmware/fsm.c | 25 ++++++++++++++++--------- firmware/layout2.c | 14 +++++++------- firmware/layout2.h | 7 ++++--- firmware/signing.c | 6 +++--- firmware/signing.h | 3 ++- firmware/transaction.c | 12 ++++++------ firmware/transaction.h | 5 +++-- 12 files changed, 81 insertions(+), 71 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 9535466e52..0c226d9e8a 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -13,34 +13,18 @@ if len(sys.argv) != 2 or sys.argv[1] not in ("count", "array"): def get_fields(coin): return [ - 'true' if coin['coin_name'] is not None else 'false', '"%s"' % coin['coin_name'] if coin['coin_name'] is not None else 'NULL', - - 'true' if coin['coin_shortcut'] is not None else 'false', '" %s"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', - - 'true' if coin['address_type'] is not None else 'false', - '%d' % coin['address_type'] if coin['address_type'] is not None else '0', - - 'true' if coin['maxfee_kb'] is not None else 'false', '%d' % coin['maxfee_kb'] if coin['maxfee_kb'] is not None else '0', - - 'true' if coin['address_type_p2sh'] is not None else 'false', - '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', - - 'true' if coin['signed_message_header'] is not None else 'false', '"\\x%02x" "%s"' % (len(coin['signed_message_header']), coin['signed_message_header'].replace('\n', '\\n')) if coin['signed_message_header'] is not None else 'NULL', - - 'true' if coin['xpub_magic'] is not None else 'false', - '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '00000000', - - 'true' if coin['xprv_magic'] is not None else 'false', - '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '00000000', - - 'true' if coin['segwit'] is not None else 'false', + 'true' if coin['address_type'] is not None else 'false', + 'true' if coin['address_type_p2sh'] is not None else 'false', 'true' if coin['segwit'] else 'false', - 'true' if coin['forkid'] is not None else 'false', + '%d' % coin['address_type'] if coin['address_type'] is not None else '0', + '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', + '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '00000000', + '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '00000000', '%d' % coin['forkid'] if coin['forkid'] else '0' ] diff --git a/firmware/coins.c b/firmware/coins.c index ae914f777b..3af074b535 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -23,13 +23,12 @@ #include "ecdsa.h" #include "base58.h" -// filled CoinType Protobuf structure defined in https://github.com/trezor/trezor-common/blob/master/protob/types.proto#L133 -// address types > 0xFF represent a two-byte prefix in big-endian order -const CoinType coins[COINS_COUNT] = { +// filled CoinInfo structure defined in coins.h +const CoinInfo coins[COINS_COUNT] = { #include "coins_array.h" }; -const CoinType *coinByName(const char *name) +const CoinInfo *coinByName(const char *name) { if (!name) return 0; for (int i = 0; i < COINS_COUNT; i++) { @@ -40,7 +39,7 @@ const CoinType *coinByName(const char *name) return 0; } -const CoinType *coinByAddressType(uint32_t address_type) +const CoinInfo *coinByAddressType(uint32_t address_type) { for (int i = 0; i < COINS_COUNT; i++) { if (address_type == coins[i].address_type) { @@ -50,7 +49,7 @@ const CoinType *coinByAddressType(uint32_t address_type) return 0; } -bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *address_type) +bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type) { if (!addr) return false; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; @@ -61,7 +60,7 @@ bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *ad return false; } -bool coinExtractAddressTypeRaw(const CoinType *coin, const uint8_t *addr_raw, uint32_t *address_type) +bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type) { if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { *address_type = coin->address_type; diff --git a/firmware/coins.h b/firmware/coins.h index 0ffc55eb7a..549f455e92 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -20,17 +20,33 @@ #ifndef __COINS_H__ #define __COINS_H__ -#include "messages.pb.h" +#include +#include #include "coins_count.h" -_Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); +typedef struct _CoinInfo { + const char *coin_name; + const char *coin_shortcut; + uint64_t maxfee_kb; + const char *signed_message_header; + bool has_address_type; + bool has_address_type_p2sh; + bool has_segwit; + bool has_forkid; + // address types > 0xFF represent a two-byte prefix in big-endian order + uint32_t address_type; + uint32_t address_type_p2sh; + uint32_t xpub_magic; + uint32_t xprv_magic; + uint32_t forkid; +} CoinInfo; -extern const CoinType coins[COINS_COUNT]; +extern const CoinInfo coins[COINS_COUNT]; -const CoinType *coinByName(const char *name); -const CoinType *coinByAddressType(uint32_t address_type); -bool coinExtractAddressType(const CoinType *coin, const char *addr, uint32_t *address_type); -bool coinExtractAddressTypeRaw(const CoinType *coin, const uint8_t *addr_raw, uint32_t *address_type); +const CoinInfo *coinByName(const char *name); +const CoinInfo *coinByAddressType(uint32_t address_type); +bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); +bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); #endif diff --git a/firmware/crypto.c b/firmware/crypto.c index 7679706ca1..3a8d6ec45a 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -110,7 +110,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin } } -int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) +int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) { SHA256_CTX ctx; sha256_Init(&ctx); @@ -143,7 +143,7 @@ int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script return result; } -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) { // check for invalid signature prefix if (signature[0] < 27 || signature[0] > 43) { diff --git a/firmware/crypto.h b/firmware/crypto.h index 7caf6ed133..dbf393db02 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -27,6 +27,7 @@ #include #include #include +#include "coins.h" #include "types.pb.h" uint32_t ser_length(uint32_t len, uint8_t *out); @@ -37,9 +38,9 @@ int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageSign(const CoinType *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinType *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 4ff14c90ec..08687ef0e6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -163,9 +163,9 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } -const CoinType *fsm_getCoin(bool has_name, const char *name) +const CoinInfo *fsm_getCoin(bool has_name, const char *name) { - const CoinType *coin; + const CoinInfo *coin; if (has_name) { coin = coinByName(name); } else { @@ -208,6 +208,8 @@ void fsm_msgInitialize(Initialize *msg) fsm_msgGetFeatures(0); } +_Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); + void fsm_msgGetFeatures(GetFeatures *msg) { (void)msg; @@ -233,7 +235,12 @@ void fsm_msgGetFeatures(GetFeatures *msg) strlcpy(resp->label, storage.label, sizeof(resp->label)); } resp->coins_count = COINS_COUNT; - memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType)); + for (int i = 0; i < COINS_COUNT; i++) { + resp->coins[i].has_coin_name = true; + strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); + resp->coins[i].has_maxfee_kb = true; + resp->coins[i].maxfee_kb = coins[i].maxfee_kb; + } resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); @@ -358,7 +365,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; const char *curve = SECP256K1_NAME; @@ -471,7 +478,7 @@ void fsm_msgSignTx(SignTx *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0); if (!node) return; @@ -640,7 +647,7 @@ void fsm_msgGetAddress(GetAddress *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -794,7 +801,7 @@ void fsm_msgSignMessage(SignMessage *msg) CHECK_PIN - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); if (!node) return; @@ -822,7 +829,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided")); - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint32_t address_type; @@ -992,7 +999,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) const HDNode *node = 0; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (signing) { - const CoinType *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; CHECK_PIN diff --git a/firmware/layout2.c b/firmware/layout2.c index e17f2566f3..998f705f33 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -97,10 +97,10 @@ void layoutHome(void) system_millis_lock_start = system_millis; } -void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) +void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { char str_out[32]; - bn_format_uint64(out->amount, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); + bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); static char first_half[17 + 1]; strlcpy(first_half, out->address, sizeof(first_half)); layoutDialogSwipe(&bmp_icon_question, @@ -116,11 +116,11 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out) ); } -void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee) +void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee) { char str_out[32], str_fee[32]; - bn_format_uint64(amount_out, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); - bn_format_uint64(amount_fee, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); + bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); + bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), @@ -134,10 +134,10 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_ ); } -void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee) +void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) { char str_fee[32]; - bn_format_uint64(fee, NULL, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); + bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), diff --git a/firmware/layout2.h b/firmware/layout2.h index f64ee2a7c1..32685c8e30 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -22,6 +22,7 @@ #include "layout.h" #include "types.pb.h" +#include "coins.h" #include "bitmaps.h" #include "bignum.h" #include "trezor.h" @@ -39,9 +40,9 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); -void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out); -void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee); -void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee); +void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); +void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyAddress(const char *address); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); diff --git a/firmware/signing.c b/firmware/signing.c index 1673fd9fed..cc2ba989e9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -30,7 +30,7 @@ static uint32_t inputs_count; static uint32_t outputs_count; -static const CoinType *coin; +static const CoinInfo *coin; static const HDNode *root; static CONFIDENTIAL HDNode node; static bool signing = false; @@ -424,7 +424,7 @@ bool compile_input_script_sig(TxInputType *tinput) return tinput->script_sig.size > 0; } -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time) +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time) { inputs_count = _inputs_count; outputs_count = _outputs_count; @@ -827,7 +827,7 @@ void signing_txack(TransactionType *tx) } } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - if (!coin->has_segwit || !coin->segwit) { + if (!coin->has_segwit) { fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); signing_abort(); return; diff --git a/firmware/signing.h b/firmware/signing.h index cec7933d72..012ac66e04 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -23,9 +23,10 @@ #include #include #include "bip32.h" +#include "coins.h" #include "types.pb.h" -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); +void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); void signing_abort(void); void signing_txack(TransactionType *tx); diff --git a/firmware/transaction.c b/firmware/transaction.c index 70ab0f1b53..2dbaac397d 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -58,7 +58,7 @@ uint32_t op_push(uint32_t i, uint8_t *out) { return 5; } -bool compute_address(const CoinType *coin, +bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, @@ -77,14 +77,14 @@ bool compute_address(const CoinType *coin, } if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wsh: script hash is single sha256 - if (!coin->has_segwit || !coin->segwit) { + if (!coin->has_segwit) { return 0; } // disable native segwit for now return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wsh encapsuled in p2sh address - if (!coin->has_segwit || !coin->segwit) { + if (!coin->has_segwit) { return 0; } if (!coin->has_address_type_p2sh) { @@ -111,14 +111,14 @@ bool compute_address(const CoinType *coin, } } else if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wpkh: pubkey hash is ripemd160 of sha256 - if (!coin->has_segwit || !coin->segwit) { + if (!coin->has_segwit) { return 0; } // disable native segwit for now return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wpkh embedded in p2sh - if (!coin->has_segwit || !coin->segwit) { + if (!coin->has_segwit) { return 0; } if (!coin->has_address_type_p2sh) { @@ -131,7 +131,7 @@ bool compute_address(const CoinType *coin, return 1; } -int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) { memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; diff --git a/firmware/transaction.h b/firmware/transaction.h index d3ea1ea0fb..34654e1516 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -24,6 +24,7 @@ #include #include "sha2.h" #include "bip32.h" +#include "coins.h" #include "types.pb.h" typedef struct { @@ -45,13 +46,13 @@ typedef struct { SHA256_CTX ctx; } TxStruct; -bool compute_address(const CoinType *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); +bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data); From 15666310235781421c2b48087991f3ca82c0e6d4 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 31 Oct 2017 18:32:08 +0100 Subject: [PATCH 0622/1154] Improved backwards compatibility of GetFeatures Set all CoinType fields except signed_message_header. Move static assert into the function where it is needed. --- firmware/fsm.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 08687ef0e6..71b954bb23 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -208,8 +208,6 @@ void fsm_msgInitialize(Initialize *msg) fsm_msgGetFeatures(0); } -_Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); - void fsm_msgGetFeatures(GetFeatures *msg) { (void)msg; @@ -234,12 +232,32 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_label = true; strlcpy(resp->label, storage.label, sizeof(resp->label)); } + + _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); resp->coins_count = COINS_COUNT; for (int i = 0; i < COINS_COUNT; i++) { - resp->coins[i].has_coin_name = true; - strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); + if (coins[i].coin_name) { + resp->coins[i].has_coin_name = true; + strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); + } + if (coins[i].coin_shortcut) { + resp->coins[i].has_coin_shortcut = true; + strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut, sizeof(resp->coins[i].coin_shortcut)); + } + resp->coins[i].has_address_type = coins[i].has_address_type; + resp->coins[i].address_type = coins[i].address_type; resp->coins[i].has_maxfee_kb = true; resp->coins[i].maxfee_kb = coins[i].maxfee_kb; + resp->coins[i].has_address_type_p2sh = coins[i].has_address_type_p2sh; + resp->coins[i].address_type_p2sh = coins[i].address_type_p2sh; + resp->coins[i].has_xpub_magic = coins[i].xpub_magic != 0; + resp->coins[i].xpub_magic = coins[i].xpub_magic; + resp->coins[i].has_xprv_magic = coins[i].xprv_magic != 0; + resp->coins[i].xprv_magic = coins[i].xprv_magic; + resp->coins[i].has_segwit = true; + resp->coins[i].segwit = coins[i].has_segwit; + resp->coins[i].has_forkid = coins[i].has_forkid; + resp->coins[i].forkid = coins[i].forkid; } resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; From cf3dc6051ca6af582c42647209e813081f5c6e60 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 4 Nov 2017 18:15:50 +0100 Subject: [PATCH 0623/1154] Omit leading space in shortcut in GetFeatures --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 71b954bb23..cead638c69 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -242,7 +242,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) } if (coins[i].coin_shortcut) { resp->coins[i].has_coin_shortcut = true; - strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut, sizeof(resp->coins[i].coin_shortcut)); + strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut + 1, sizeof(resp->coins[i].coin_shortcut)); } resp->coins[i].has_address_type = coins[i].has_address_type; resp->coins[i].address_type = coins[i].address_type; From 97581928de6d58de6edbdaafc1fc8bd4a16683c2 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 8 Sep 2017 15:29:55 +0200 Subject: [PATCH 0624/1154] Enable Segwit Bech32 addresses Increase the size of the addresses in protobuf. Fix layout2.c to handle longer addresses. Add a field bech32_prefix to coins.h Adapted the coins-gen script. Added bech32 support in signing.c and transaction.c --- firmware/Makefile | 1 + firmware/coins-gen.py | 7 +++--- firmware/coins.h | 1 + firmware/fsm.c | 6 ++--- firmware/layout2.c | 32 +++++++++++++----------- firmware/layout2.h | 2 +- firmware/protob/messages.options | 10 ++++---- firmware/protob/types.options | 2 +- firmware/signing.c | 17 ++----------- firmware/transaction.c | 42 +++++++++++++++++++++++--------- 10 files changed, 67 insertions(+), 53 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index b0b9dcf166..3c1fc84b0b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -53,6 +53,7 @@ OBJS += ../vendor/trezor-crypto/bip39.o OBJS += ../vendor/trezor-crypto/pbkdf2.o OBJS += ../vendor/trezor-crypto/base32.o OBJS += ../vendor/trezor-crypto/base58.o +OBJS += ../vendor/trezor-crypto/segwit_addr.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 0c226d9e8a..1587fb0829 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -23,9 +23,10 @@ def get_fields(coin): 'true' if coin['forkid'] is not None else 'false', '%d' % coin['address_type'] if coin['address_type'] is not None else '0', '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', - '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '00000000', - '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '00000000', - '%d' % coin['forkid'] if coin['forkid'] else '0' + '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '0x00000000', + '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '0x00000000', + '%d' % coin['forkid'] if coin['forkid'] else '0', + '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL' ] diff --git a/firmware/coins.h b/firmware/coins.h index 549f455e92..3d13a1b739 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -40,6 +40,7 @@ typedef struct _CoinInfo { uint32_t xpub_magic; uint32_t xprv_magic; uint32_t forkid; + const char *bech32_prefix; } CoinInfo; extern const CoinInfo coins[COINS_COUNT]; diff --git a/firmware/fsm.c b/firmware/fsm.c index cead638c69..4f0011fd1e 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -694,7 +694,7 @@ void fsm_msgGetAddress(GetAddress *msg) } bool qrcode = false; for (;;) { - layoutAddress(address, desc, qrcode); + layoutAddress(address, desc, qrcode, msg->script_type == InputScriptType_SPENDWITNESS); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } @@ -732,7 +732,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) bool qrcode = false; for (;;) { - layoutAddress(address, desc, qrcode); + layoutAddress(address, desc, qrcode, false); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } @@ -1160,7 +1160,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) bool qrcode = false; for (;;) { - layoutAddress(resp->address, desc, qrcode); + layoutAddress(resp->address, desc, qrcode, false); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } diff --git a/firmware/layout2.c b/firmware/layout2.c index 998f705f33..f8ac92f152 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -277,7 +277,7 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } -void layoutAddress(const char *address, const char *desc, bool qrcode) +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase) { if (layoutLast != layoutAddress) { layoutSwipe(); @@ -286,40 +286,44 @@ void layoutAddress(const char *address, const char *desc, bool qrcode) } layoutLast = layoutAddress; + uint32_t addrlen = strlen(address); if (qrcode) { static unsigned char bitdata[QR_MAX_BITDATA]; - int side = qr_encode(QR_LEVEL_M, 0, address, 0, bitdata); + char address_upcase[addrlen + 1]; + if (ignorecase) { + for (uint32_t i = 0; i < addrlen + 1; i++) { + address_upcase[i] = address[i] >= 'a' && address[i] <= 'z' ? + address[i] + 'A' - 'a' : address[i]; + } + } + int side = qr_encode(addrlen <= (ignorecase ? 60 : 40) ? QR_LEVEL_M : QR_LEVEL_L, 0, + ignorecase ? address_upcase : address, 0, bitdata); + oledInvert(0, 0, 63, 63); if (side > 0 && side <= 29) { - oledInvert(0, 0, (side + 2) * 2, (side + 2) * 2); + int offset = 32 - side; for (int i = 0; i < side; i++) { for (int j = 0; j< side; j++) { int a = j * side + i; if (bitdata[a / 8] & (1 << (7 - a % 8))) { - oledClearPixel(2 + i * 2, 2 + j * 2); - oledClearPixel(3 + i * 2, 2 + j * 2); - oledClearPixel(2 + i * 2, 3 + j * 2); - oledClearPixel(3 + i * 2, 3 + j * 2); + oledBox(offset + i * 2, offset + j * 2, + offset + 1 + i * 2, offset + 1 + j * 2, false); } } } } else if (side > 0 && side <= 60) { - oledInvert(0, 0, (side + 3), (side + 3)); + int offset = 32 - (side / 2); for (int i = 0; i < side; i++) { for (int j = 0; j< side; j++) { int a = j * side + i; if (bitdata[a / 8] & (1 << (7 - a % 8))) { - oledClearPixel(2 + i, 2 + j); + oledClearPixel(offset + i, offset + j); } } } } } else { - uint32_t addrlen = strlen(address); - uint32_t rowlen = addrlen / 2; - if (addrlen % 2) { - rowlen++; - } + uint32_t rowlen = (addrlen - 1) / (addrlen <= 40 ? 2 : addrlen <= 60 ? 3 : 4) + 1; const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { oledDrawString(0, 0 * 9, desc); diff --git a/firmware/layout2.h b/firmware/layout2.h index 32685c8e30..a68a08b030 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -50,7 +50,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutResetWord(const char *word, int pass, int word_pos, bool last); -void layoutAddress(const char *address, const char *desc, bool qrcode); +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 9964171d58..279c4b9444 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -33,7 +33,7 @@ PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 GetAddress.coin_name max_size:21 -Address.address max_size:60 +Address.address max_size:76 EthereumGetAddress.address_n max_count:8 EthereumAddress.address max_size:20 @@ -57,12 +57,12 @@ SignMessage.address_n max_count:8 SignMessage.message max_size:1024 SignMessage.coin_name max_size:21 -VerifyMessage.address max_size:60 +VerifyMessage.address max_size:76 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 VerifyMessage.coin_name max_size:21 -MessageSignature.address max_size:60 +MessageSignature.address max_size:76 MessageSignature.signature max_size:65 EthereumSignMessage.address_n max_count:8 @@ -97,7 +97,7 @@ DecryptMessage skip_message:true # deprecated DecryptedMessage skip_message:true -# DecryptedMessage.address max_size:60 +# DecryptedMessage.address max_size:76 # DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 @@ -133,7 +133,7 @@ SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 SignIdentity.ecdsa_curve_name max_size:32 -SignedIdentity.address max_size:60 +SignedIdentity.address max_size:76 SignedIdentity.public_key max_size:33 SignedIdentity.signature max_size:65 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index ce84f0961a..a0847d2a32 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -12,7 +12,7 @@ TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 -TxOutputType.address max_size:54 +TxOutputType.address max_size:76 TxOutputType.address_n max_count:8 TxOutputType.op_return_data max_size:80 diff --git a/firmware/signing.c b/firmware/signing.c index cc2ba989e9..83014035f9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -392,7 +392,7 @@ bool compile_input_script_sig(TxInputType *tinput) if (!multisig_fp_mismatch) { // check that this is still multisig uint8_t h[32]; - if (tinput->script_type != InputScriptType_SPENDMULTISIG + if (!tinput->has_multisig || cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 || memcmp(multisig_fp, h, 32) != 0) { // Transaction has changed during signing @@ -469,8 +469,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf static bool signing_check_input(TxInputType *txinput) { /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (txinput->has_multisig && !multisig_fp_mismatch - && txinput->script_type == InputScriptType_SPENDMULTISIG) { + if (txinput->has_multisig && !multisig_fp_mismatch) { uint8_t h[32]; if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); @@ -705,12 +704,6 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { if (txinput->script_type == InputScriptType_SPENDWITNESS || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - // disable native segwit for now - if (txinput->script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_DataError, _("Native segwit is disabled")); - signing_abort(); - return false; - } if (!compile_input_script_sig(txinput)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); @@ -832,12 +825,6 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - // disable native segwit for now - if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS) { - fsm_sendFailure(FailureType_Failure_DataError, _("Native segwit is disabled")); - signing_abort(); - return; - } if (!tx->inputs[0].has_amount) { fsm_sendFailure(FailureType_Failure_DataError, _("Segwit input without amount")); signing_abort(); diff --git a/firmware/transaction.c b/firmware/transaction.c index 2dbaac397d..39ada73bc8 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -31,6 +31,9 @@ #include "address.h" #include "messages.pb.h" #include "types.pb.h" +#include "segwit_addr.h" + +#define SEGWIT_VERSION_0 0 static const uint8_t segwit_header[2] = {0,1}; @@ -77,11 +80,12 @@ bool compute_address(const CoinInfo *coin, } if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wsh: script hash is single sha256 - if (!coin->has_segwit) { + if (!coin->has_segwit || !coin->bech32_prefix) { + return 0; + } + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 32)) { return 0; } - // disable native segwit for now - return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wsh encapsuled in p2sh address if (!coin->has_segwit) { @@ -111,11 +115,13 @@ bool compute_address(const CoinInfo *coin, } } else if (script_type == InputScriptType_SPENDWITNESS) { // segwit p2wpkh: pubkey hash is ripemd160 of sha256 - if (!coin->has_segwit) { + if (!coin->has_segwit || !coin->bech32_prefix) { + return 0; + } + ecdsa_get_pubkeyhash(node->public_key, digest); + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { return 0; } - // disable native segwit for now - return 0; } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { // segwit p2wpkh embedded in p2sh if (!coin->has_segwit) { @@ -163,8 +169,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T input_script_type = InputScriptType_SPENDMULTISIG; break; case OutputScriptType_PAYTOWITNESS: - // disable native segwit for now - return 0; + input_script_type = InputScriptType_SPENDWITNESS; + break; case OutputScriptType_PAYTOP2SHWITNESS: input_script_type = InputScriptType_SPENDP2SHWITNESS; break; @@ -187,8 +193,9 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; - if (address_check_prefix(addr_raw, coin->address_type) // p2pkh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { + if (coin->has_address_type // p2pkh + && address_check_prefix(addr_raw, coin->address_type) + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes @@ -196,13 +203,26 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; - } else if (address_check_prefix(addr_raw, coin->address_type_p2sh) // p2sh + } else if (coin->has_address_type_p2sh // p2sh + && address_check_prefix(addr_raw, coin->address_type_p2sh) && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; + } else if (coin->bech32_prefix) { + int witver; + if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { + return 0; + } + // segwit: + // push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i) + // push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40) + out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver; + out->script_pubkey.bytes[1] = addr_raw_len; + memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len); + out->script_pubkey.size = addr_raw_len + 2; } else { return 0; } From 0f50b816e600ada1975f175b383ad5e8230a6fe1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 1 Nov 2017 21:42:52 +0100 Subject: [PATCH 0625/1154] Wrap long addresses in three lines --- firmware/layout2.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index f8ac92f152..c353ed4b07 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -101,17 +101,29 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { char str_out[32]; bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); - static char first_half[17 + 1]; - strlcpy(first_half, out->address, sizeof(first_half)); + static char lines[2][28]; + const char *addr = out->address; + int addrlen = strlen(addr); + int numlines = addrlen <= 34 ? 2 : 3; + strcpy(lines[0], _("to ")); + int linelen = (addrlen + (numlines == 3 ? 3 : 0) - 1) / numlines + 1; + if (linelen > 27) + linelen = 27; + if (numlines == 3) { + strlcpy(lines[0] + 3, addr, linelen - 3 + 1); + addr += linelen - 3; + } + strlcpy(lines[1], addr, linelen + 1); + addr += linelen; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Confirm sending"), str_out, - _("to"), - first_half, - out->address + 17, + lines[0], + lines[1], + addr, NULL ); } From bbf6b1b09786778be0e3580632f061e8df961d60 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 1 Nov 2017 22:18:29 +0100 Subject: [PATCH 0626/1154] Implemented VerifyMessage for bech32 --- firmware/crypto.c | 37 +++++++++++++++++++++++++------------ firmware/crypto.h | 2 +- firmware/fsm.c | 8 +------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 3a8d6ec45a..391410a9e4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -31,6 +31,8 @@ #include "address.h" #include "macros.h" #include "coins.h" +#include "base58.h" +#include "segwit_addr.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -143,7 +145,7 @@ int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script return result; } -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature) +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) { // check for invalid signature prefix if (signature[0] < 27 || signature[0] > 43) { @@ -177,30 +179,41 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // check if the address is correct uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - if (address_type != coin->address_type) { - return 4; - } - ecdsa_get_address_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_raw(pubkey, coin->address_type, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || len != address_prefix_bytes_len(coin->address_type) + 20) { return 2; } } else // segwit-in-p2sh if (signature[0] >= 35 && signature[0] <= 38) { - if (address_type != coin->address_type_p2sh) { - return 4; - } - ecdsa_get_address_segwit_p2sh_raw(pubkey, address_type, addr_raw); - if (memcmp(addr_raw, address_raw, address_prefix_bytes_len(address_type) + 20) != 0) { + size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { return 2; } } else // segwit if (signature[0] >= 39 && signature[0] <= 42) { - return 2; // not supported yet + int witver; + size_t len; + if (!coin->bech32_prefix + || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { + return 4; + } + ecdsa_get_pubkeyhash(pubkey, addr_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 + || witver != 0 || len != 20) { + return 2; + } + } else { + return 4; } return 0; diff --git a/firmware/crypto.h b/firmware/crypto.h index dbf393db02..e974df26ac 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -40,7 +40,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint32_t address_type, const uint8_t *address_raw, const uint8_t *signature); +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature); /* ECIES disabled int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); diff --git a/firmware/fsm.c b/firmware/fsm.c index 4f0011fd1e..f2f9d35389 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -849,14 +849,8 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint32_t address_type; - if (!coinExtractAddressType(coin, msg->address, &address_type) || !ecdsa_address_decode(msg->address, address_type, addr_raw)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); - return; - } layoutProgressSwipe(_("Verifying"), 0); - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, address_type, addr_raw, msg->signature.bytes) == 0) { + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); From 600c61b3dcbfeb10e90e3f776b0b0bf0c3f6a7f3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 4 Nov 2017 16:48:26 +0100 Subject: [PATCH 0627/1154] Updated trezor-crypto. --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 56114cc0a6..95a522bf1a 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 56114cc0a6e1b6817262bf886d775ec9de400d8e +Subproject commit 95a522bf1a453880050521661258d7943e966d1f From 892bb8501a1282535a9c721d0a3187f51aa5585b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 5 Nov 2017 19:30:33 +0100 Subject: [PATCH 0628/1154] fsm: ignore case for NEM addresses --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index f2f9d35389..086cccacb7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1154,7 +1154,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) bool qrcode = false; for (;;) { - layoutAddress(resp->address, desc, qrcode, false); + layoutAddress(resp->address, desc, qrcode, true); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } From b6f11c9f93398c4c9486094fc7b7fdf60feaf0cc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 31 Oct 2017 20:49:01 +0000 Subject: [PATCH 0629/1154] signing: Add signing_hash_type function This also enables SIGHASH_FORKID for SegWit --- firmware/signing.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 83014035f9..b9ca03edb9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -610,6 +610,16 @@ static bool signing_check_fee(void) { return true; } +static uint32_t signing_hash_type(void) { + uint32_t hash_type = SIGHASH_ALL; + + if (coin->has_forkid) { + hash_type |= (coin->forkid << 8) | SIGHASH_FORKID; + } + + return hash_type; +} + static void phase1_request_next_output(void) { if (idx1 < outputs_count - 1) { idx1++; @@ -628,8 +638,8 @@ static void phase1_request_next_output(void) { } } -static void signing_hash_bip143(const TxInputType *txinput, uint8_t sighash, uint32_t forkid, uint8_t *hash) { - uint32_t hash_type = (forkid << 8) | sighash; +static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { + uint32_t hash_type = signing_hash_type(); sha256_Init(&hashers[0]); sha256_Update(&hashers[0], (const uint8_t *)&version, 4); sha256_Update(&hashers[0], hash_prevouts, 32); @@ -645,7 +655,7 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t sighash, uin sha256_Raw(hash, 32, hash); } -static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash, uint8_t sighash) { +static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; @@ -657,6 +667,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, } resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); + uint8_t sighash = signing_hash_type() & 0xff; if (txinput->has_multisig) { // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), public_key); @@ -689,10 +700,9 @@ static bool signing_sign_input(void) { return false; } - uint8_t sighash = SIGHASH_ALL; tx_hash_final(&ti, hash, false); resp.has_serialized = true; - if (!signing_sign_hash(&input, privkey, pubkey, hash, sighash)) + if (!signing_sign_hash(&input, privkey, pubkey, hash)) return false; resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); return true; @@ -716,10 +726,10 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { } authorized_amount -= txinput->amount; - signing_hash_bip143(txinput, SIGHASH_ALL, 0, hash); + signing_hash_bip143(txinput, hash); resp.has_serialized = true; - if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash, SIGHASH_ALL)) + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) return false; if (txinput->has_multisig) { uint32_t r = 1; // skip number of items (filled in later) @@ -1035,8 +1045,8 @@ void signing_txack(TransactionType *tx) authorized_amount -= tx->inputs[0].amount; uint8_t hash[32]; - signing_hash_bip143(&tx->inputs[0], SIGHASH_ALL | SIGHASH_FORKID, coin->forkid, hash); - if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash, SIGHASH_ALL | SIGHASH_FORKID)) + signing_hash_bip143(&tx->inputs[0], hash); + if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash)) return; // since this took a longer time, update progress signatures++; From c6246b5fba8b779e4b62cbde71b9874f4065aa66 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 31 Oct 2017 20:55:15 +0000 Subject: [PATCH 0630/1154] coins: Add force_bip143 --- firmware/coins-gen.py | 1 + firmware/coins.h | 1 + firmware/fsm.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 1587fb0829..75bbe63522 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -21,6 +21,7 @@ def get_fields(coin): 'true' if coin['address_type_p2sh'] is not None else 'false', 'true' if coin['segwit'] else 'false', 'true' if coin['forkid'] is not None else 'false', + 'true' if coin['force_bip143'] else 'false', '%d' % coin['address_type'] if coin['address_type'] is not None else '0', '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '0x00000000', diff --git a/firmware/coins.h b/firmware/coins.h index 3d13a1b739..953520d5b8 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -34,6 +34,7 @@ typedef struct _CoinInfo { bool has_address_type_p2sh; bool has_segwit; bool has_forkid; + bool force_bip143; // address types > 0xFF represent a two-byte prefix in big-endian order uint32_t address_type; uint32_t address_type_p2sh; diff --git a/firmware/fsm.c b/firmware/fsm.c index 086cccacb7..b1e8c73474 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -258,6 +258,8 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->coins[i].segwit = coins[i].has_segwit; resp->coins[i].has_forkid = coins[i].has_forkid; resp->coins[i].forkid = coins[i].forkid; + resp->coins[i].has_force_bip143 = true; + resp->coins[i].force_bip143 = coins[i].force_bip143; } resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; From d39e4be1c8f4652f22f6d9cb54c5e72d704014c8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 31 Oct 2017 20:55:29 +0000 Subject: [PATCH 0631/1154] signing: Use force_bip143 instead of has_forkid --- firmware/signing.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index b9ca03edb9..b1077657ab 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -807,9 +807,9 @@ void signing_txack(TransactionType *tx) } #endif - if (coin->has_forkid) { + if (coin->force_bip143) { if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("SIGHASH_FORKID input without amount")); + fsm_sendFailure(FailureType_Failure_DataError, _("BIP 143 input without amount")); signing_abort(); return; } @@ -1027,7 +1027,7 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - if (!coin->has_forkid) { + if (!coin->force_bip143) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; From a8bc3cb6bd15a137c09fefcf56a94619e6d1d4ba Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 31 Oct 2017 22:21:51 +0100 Subject: [PATCH 0632/1154] Remove add_hash_type fields. The 4 byte hash_type/forkid is part of the signed message, but not part of the transaction. Instead of hacking it into the transaction, add it after the transaction when computing the signature. --- firmware/signing.c | 8 +++++--- firmware/transaction.c | 19 +++---------------- firmware/transaction.h | 4 ++-- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index b1077657ab..8f940df657 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -453,7 +453,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, false); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0); // segwit hashes for hashPrevouts and hashSequence sha256_Init(&hashers[0]); sha256_Init(&hashers[1]); @@ -700,6 +700,8 @@ static bool signing_sign_input(void) { return false; } + uint32_t hash_type = signing_hash_type(); + sha256_Update(&ti.ctx, (const uint8_t *)&hash_type, 4); tx_hash_final(&ti, hash, false); resp.has_serialized = true; if (!signing_sign_hash(&input, privkey, pubkey, hash)) @@ -867,7 +869,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_META: - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, false); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; if (tp.inputs_len > 0) { @@ -940,7 +942,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, true); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0); sha256_Init(&hashers[0]); } // check prevouts and script type diff --git a/firmware/transaction.c b/firmware/transaction.c index 39ada73bc8..965e9cffbf 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -455,25 +455,13 @@ uint32_t tx_serialize_middle_hash(TxStruct *tx) uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); - if (tx->add_hash_type) { - uint32_t ht = 1; - memcpy(out + 4, &ht, 4); - return 8; - } else { - return 4; - } + return 4; } uint32_t tx_serialize_footer_hash(TxStruct *tx) { sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->lock_time), 4); - if (tx->add_hash_type) { - uint32_t ht = 1; - sha256_Update(&(tx->ctx), (const uint8_t *)&ht, 4); - return 8; - } else { - return 4; - } + return 4; } uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) @@ -545,13 +533,12 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; tx->version = version; tx->lock_time = lock_time; - tx->add_hash_type = add_hash_type; tx->have_inputs = 0; tx->have_outputs = 0; tx->extra_data_len = extra_data_len; diff --git a/firmware/transaction.h b/firmware/transaction.h index 34654e1516..f5e4ee30d4 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -33,7 +33,7 @@ typedef struct { uint32_t version; uint32_t lock_time; - bool add_hash_type, is_segwit; + bool is_segwit; uint32_t have_inputs; uint32_t have_outputs; @@ -64,7 +64,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); From 8da27700518b9d247afaf9a3d748567817edfbf0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 31 Oct 2017 23:08:56 +0100 Subject: [PATCH 0633/1154] Increase coin count --- firmware/protob/messages.options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 279c4b9444..93f53eb578 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:10 +Features.coins max_count:11 Features.revision max_size:20 Features.bootloader_hash max_size:32 From b8bca1c444101de139d2b4467ac7e7d31df30cda Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 7 Nov 2017 02:33:53 +0100 Subject: [PATCH 0634/1154] Fix segwit forkid signatures --- firmware/signing.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 8f940df657..ff1ddf6f87 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -733,6 +733,8 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { resp.has_serialized = true; if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) return false; + + uint8_t sighash = signing_hash_type() & 0xff; if (txinput->has_multisig) { uint32_t r = 1; // skip number of items (filled in later) resp.serialized.serialized_tx.bytes[r] = 0; r++; @@ -742,7 +744,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { continue; } nwitnesses++; - txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = 1; + txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = sighash; r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); } uint32_t script_len = compile_script_multisig(&txinput->multisig, 0); @@ -753,7 +755,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { } else { // single signature uint32_t r = 0; r += ser_length(2, resp.serialized.serialized_tx.bytes + r); - resp.serialized.signature.bytes[resp.serialized.signature.size] = 1; + resp.serialized.signature.bytes[resp.serialized.signature.size] = sighash; r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.size = r; From a4d46b7ae1618cc3aa582b609d9d2ed140dbadbf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 13 Nov 2017 22:32:11 +0100 Subject: [PATCH 0635/1154] vendor: update trezor-common, increase coins count --- firmware/protob/messages.options | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 93f53eb578..3d748bff8e 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:11 +Features.coins max_count:13 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/vendor/trezor-common b/vendor/trezor-common index 34bd9e50b6..7325936f86 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 34bd9e50b6470a8d60d2cac56cf409f046829f62 +Subproject commit 7325936f8612ce1cadff6cfb0c0045b3668c3260 From e1fa7af1da79e86ccaae5f3cd2a6c4644f546f8a Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 8 Nov 2017 01:13:21 +0100 Subject: [PATCH 0636/1154] Byte-precise size estimate for fees Fixes issue #232. It assumes largest possible signature size for all inputs. For segwit multisig it can be .25 bytes off due to difference between segwit encoding (varint) vs. non-segwit encoding (op_push) of the multisig script. --- firmware/crypto.h | 2 + firmware/signing.c | 21 ++++++++-- firmware/transaction.c | 93 +++++++++++++++++++++++++++++++++++++++--- firmware/transaction.h | 3 +- 4 files changed, 110 insertions(+), 9 deletions(-) diff --git a/firmware/crypto.h b/firmware/crypto.h index e974df26ac..c77e4a9a00 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -30,6 +30,8 @@ #include "coins.h" #include "types.pb.h" +#define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5) + uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); diff --git a/firmware/signing.c b/firmware/signing.c index ff1ddf6f87..6cef721e63 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -67,6 +67,7 @@ static bool multisig_fp_set, multisig_fp_mismatch; static uint8_t multisig_fp[32]; static uint32_t in_address_n[8]; static size_t in_address_n_count; +static uint32_t tx_weight; /* A marker for in_address_n_count to indicate a mismatch in bip32 paths in input */ @@ -79,6 +80,13 @@ static size_t in_address_n_count; use and still allow to quickly brute-force the correct bip32 path. */ #define BIP32_MAX_LAST_ELEMENT 1000000 +/* transaction header size: 4 byte version */ +#define TXSIZE_HEADER 4 +/* transaction footer size: 4 byte lock time */ +#define TXSIZE_FOOTER 4 +/* transaction segwit overhead 2 marker */ +#define TXSIZE_SEGWIT_OVERHEAD 2 + enum { SIGHASH_ALL = 1, SIGHASH_FORKID = 0x40, @@ -433,6 +441,10 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf version = _version; lock_time = _lock_time; + tx_weight = 4 * (TXSIZE_HEADER + TXSIZE_FOOTER + + ser_length_size(inputs_count) + + ser_length_size(outputs_count)); + signatures = 0; idx1 = 0; to_spend = 0; @@ -590,15 +602,13 @@ static bool signing_check_fee(void) { return false; } uint64_t fee = to_spend - spending; - uint64_t tx_est_size_kb = (transactionEstimateSize(inputs_count, outputs_count) + 999) / 1000; - if (fee > tx_est_size_kb * coin->maxfee_kb) { + if (fee > ((uint64_t) tx_weight * coin->maxfee_kb)/4000) { layoutFeeOverThreshold(coin, fee); if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } - layoutProgress(_("Signing transaction"), progress); } // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); @@ -799,6 +809,7 @@ void signing_txack(TransactionType *tx) switch (signing_stage) { case STAGE_REQUEST_1_INPUT: signing_check_input(&tx->inputs[0]); + tx_weight += tx_input_weight(&tx->inputs[0]); if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { memcpy(&input, tx->inputs, sizeof(TxInputType)); @@ -849,6 +860,9 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + if (!to.is_segwit) { + tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; + } #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs if (idx1 == 0) { @@ -939,6 +953,7 @@ void signing_txack(TransactionType *tx) if (!signing_check_output(&tx->outputs[0])) { return; } + tx_weight += tx_output_weight(coin, &tx->outputs[0]); phase1_request_next_output(); return; case STAGE_REQUEST_4_INPUT: diff --git a/firmware/transaction.c b/firmware/transaction.c index 965e9cffbf..40a872d0a3 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -35,19 +35,41 @@ #define SEGWIT_VERSION_0 0 +/* transaction input size (without script): 32 prevhash, 4 idx, 4 sequence */ +#define TXSIZE_INPUT 40 +/* transaction output size (without script): 8 amount */ +#define TXSIZE_OUTPUT 8 +/* size of a pubkey */ +#define TXSIZE_PUBKEY 33 +/* size of a DER signature (3 type bytes, 3 len bytes, 33 R, 32 S, 1 sighash */ +#define TXSIZE_SIGNATURE 72 +/* size of a multiscript without pubkey (1 M, 1 N, 1 checksig) */ +#define TXSIZE_MULTISIGSCRIPT 3 +/* size of a p2wpkh script (1 version, 1 push, 20 hash) */ +#define TXSIZE_WITNESSPKHASH 22 +/* size of a p2wsh script (1 version, 1 push, 32 hash) */ +#define TXSIZE_WITNESSSCRIPT 34 +/* size of a p2pkh script (dup, hash, push, 20 pubkeyhash, equal, checksig) */ +#define TXSIZE_P2PKHASH 25 +/* size of a p2sh script (hash, push, 20 scripthash, equal) */ +#define TXSIZE_P2SCRIPT 23 + static const uint8_t segwit_header[2] = {0,1}; +#define op_push_size(len) ((len) < 0x4c ? 1 : (len) < 0x100 ? 2 : \ + (len) < 0x10000 ? 3 : 5) + uint32_t op_push(uint32_t i, uint8_t *out) { if (i < 0x4C) { out[0] = i & 0xFF; return 1; } - if (i < 0xFF) { + if (i < 0x100) { out[0] = 0x4C; out[1] = i & 0xFF; return 2; } - if (i < 0xFFFF) { + if (i < 0x10000) { out[0] = 0x4D; out[1] = i & 0xFF; out[2] = (i >> 8) & 0xFF; @@ -560,7 +582,68 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs) -{ - return 10 + inputs * 149 + outputs * 35; +uint32_t tx_input_weight(const TxInputType *txinput) { + uint32_t input_script_size; + if (txinput->has_multisig) { + uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT + + txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); + input_script_size = 1 // the OP_FALSE bug in multisig + + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) + + op_push_size(multisig_script_size) + multisig_script_size; + } else { + input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); + } + uint32_t weight = 4 * TXSIZE_INPUT; + if (txinput->script_type == InputScriptType_SPENDADDRESS + || txinput->script_type == InputScriptType_SPENDMULTISIG) { + input_script_size += ser_length_size(input_script_size); + weight += 4 * input_script_size; + } else if (txinput->script_type == InputScriptType_SPENDWITNESS + || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + weight += 4 * (2 + (txinput->has_multisig + ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH)); + } else { + weight += 4; // empty input script + } + weight += input_script_size; // discounted witness + } + return weight; +} + +uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { + uint32_t output_script_size = 0; + if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { + output_script_size = 1 + op_push_size(txoutput->op_return_data.size) + + txoutput->op_return_data.size; + } else if (txoutput->address_n_count > 0) { + if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + output_script_size = txoutput->has_multisig + ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { + output_script_size = TXSIZE_P2SCRIPT; + } else { + output_script_size = txoutput->has_multisig + ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; + } + } else { + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int witver; + size_t addr_raw_len; + if (coin->bech32_prefix + && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { + output_script_size = 2 + addr_raw_len; + } else { + addr_raw_len = base58_decode_check(txoutput->address, addr_raw, MAX_ADDR_RAW_SIZE); + if (coin->has_address_type + && address_check_prefix(addr_raw, coin->address_type)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (coin->has_address_type_p2sh + && address_check_prefix(addr_raw, coin->address_type_p2sh)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } + } + output_script_size += ser_length_size(output_script_size); + return 4 * (TXSIZE_OUTPUT + output_script_size); } diff --git a/firmware/transaction.h b/firmware/transaction.h index f5e4ee30d4..d802ece30c 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -71,6 +71,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); +uint32_t tx_input_weight(const TxInputType *txinput); +uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput); #endif From e3460b9f00873842fe5d4b3310db155451f94ed4 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Fri, 3 Nov 2017 19:48:28 +0000 Subject: [PATCH 0637/1154] reset: Call storage_commit after initialization Fixes #230 --- firmware/reset.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index a5532013d0..d4a1570d68 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -118,7 +118,10 @@ void reset_backup(bool separated) storage.has_needs_backup = true; storage.needs_backup = false; - storage_commit(); + + if (separated) { + storage_commit(); + } for (int pass = 0; pass < 2; pass++) { int i = 0, word_pos = 1; @@ -149,6 +152,7 @@ void reset_backup(bool separated) if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { + storage_commit(); fsm_sendSuccess(_("Device successfully initialized")); } layoutHome(); From 61044b3fc3a422e70f7f9c48e5307bd9ccb97687 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 14 Nov 2017 14:29:46 +0100 Subject: [PATCH 0638/1154] u2f: add u2f.bin.coffee --- firmware/u2f_knownapps.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 299622de08..a6a25ea858 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -120,6 +120,16 @@ static const U2FWellKnown u2f_well_known[] = { 0x21, 0x96, 0xf1, 0x06, 0xd1, 0x6c, 0xa3, 0x12 }, "Yubico U2F Demo", &bmp_u2f_yubico + }, + { + // https://u2f.bin.coffee + { + 0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, + 0xb4, 0xc2, 0x89, 0xdc, 0x16, 0x74, 0x6b, 0xcc, + 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, 0xe1, 0x32, + 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68 }, + "u2f.bin.coffee", + NULL } }; From de3b78bd0bb020b953b07a75d3c9d4b75de53f92 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 14 Nov 2017 17:53:17 +0100 Subject: [PATCH 0639/1154] layout: print bip32 path in GetAddress dialog --- firmware/fsm.c | 10 +++++----- firmware/layout2.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- firmware/layout2.h | 2 +- firmware/u2f.c | 8 ++++---- 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b1e8c73474..081845cc14 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -163,7 +163,7 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } -const CoinInfo *fsm_getCoin(bool has_name, const char *name) +static const CoinInfo *fsm_getCoin(bool has_name, const char *name) { const CoinInfo *coin; if (has_name) { @@ -179,7 +179,7 @@ const CoinInfo *fsm_getCoin(bool has_name, const char *name) return coin; } -HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count) +static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; if (!storage_getRootNode(&node, curve, true)) { @@ -696,7 +696,7 @@ void fsm_msgGetAddress(GetAddress *msg) } bool qrcode = false; for (;;) { - layoutAddress(address, desc, qrcode, msg->script_type == InputScriptType_SPENDWITNESS); + layoutAddress(address, desc, qrcode, msg->script_type == InputScriptType_SPENDWITNESS, msg->address_n, msg->address_n_count); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } @@ -734,7 +734,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) bool qrcode = false; for (;;) { - layoutAddress(address, desc, qrcode, false); + layoutAddress(address, desc, qrcode, false, msg->address_n, msg->address_n_count); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } @@ -1156,7 +1156,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) bool qrcode = false; for (;;) { - layoutAddress(resp->address, desc, qrcode, true); + layoutAddress(resp->address, desc, qrcode, true, msg->address_n, msg->address_n_count); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { break; } diff --git a/firmware/layout2.c b/firmware/layout2.c index c353ed4b07..9dafb8d43f 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -164,7 +164,7 @@ void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) } // split longer string into 4 rows, rowlen chars each -const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) +static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) { static char str[4][32 + 1]; if (rowlen > 32) { @@ -289,7 +289,45 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase) +static const char *address_n_str(const uint32_t *address_n, size_t address_n_count) +{ + if (address_n_count > 8) { + return _("Unknown long path"); + } + if (address_n_count == 0) { + return _("Path: m"); + } + + // "Path: m" / i ' + static char address_str[7 + 8 * (1 + 9 + 1) + 1]; + char *c = address_str + sizeof(address_str) - 1; + + *c = 0; c--; + + for (int n = (int)address_n_count - 1; n >= 0; n--) { + uint32_t i = address_n[n]; + if (i & 0x80000000) { + *c = '\''; c--; + } + i = i & 0x7fffffff; + do { + *c = '0' + (i % 10); c--; + i /= 10; + } while (i > 0); + *c = '/'; c--; + } + *c = 'm'; c--; + *c = ' '; c--; + *c = ':'; c--; + *c = 'h'; c--; + *c = 't'; c--; + *c = 'a'; c--; + *c = 'P'; + + return c; +} + +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count) { if (layoutLast != layoutAddress) { layoutSwipe(); @@ -313,7 +351,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno oledInvert(0, 0, 63, 63); if (side > 0 && side <= 29) { - int offset = 32 - side; + int offset = 32 - side; for (int i = 0; i < side; i++) { for (int j = 0; j< side; j++) { int a = j * side + i; @@ -343,6 +381,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno for (int i = 0; i < 4; i++) { oledDrawString(0, (i + 1) * 9 + 4, str[i]); } + oledDrawString(0, 42, address_n_str(address_n, address_n_count)); } if (!qrcode) { diff --git a/firmware/layout2.h b/firmware/layout2.h index a68a08b030..48e001fb94 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -50,7 +50,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutResetWord(const char *word, int pass, int word_pos, bool last); -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase); +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); diff --git a/firmware/u2f.c b/firmware/u2f.c index bd0b51f6ef..1a8270e1fd 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -430,7 +430,7 @@ void u2f_version(const APDU *a) send_u2f_msg(version_response, sizeof(version_response)); } -void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) { +static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) { static char buf[8+2+8+1]; for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { @@ -448,7 +448,7 @@ void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, *appicon = NULL; } -const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) +static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; if (!storage_getRootNode(&node, NIST256P1_NAME, false)) { @@ -467,7 +467,7 @@ const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) return &node; } -const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) +static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) { uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; @@ -499,7 +499,7 @@ const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) } -const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) +static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) { uint32_t key_path[KEY_PATH_ENTRIES]; key_path[0] = U2F_KEY_PATH; From 54659d49d85024898d2fd31c4db9da12b4ae96f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 15 Nov 2017 15:42:56 +0100 Subject: [PATCH 0640/1154] layout: op_return now requires confirmation by user --- firmware/layout2.c | 80 ++++++++++++++++++++++++++++++------------ firmware/layout2.h | 1 + firmware/transaction.c | 6 ++++ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 9dafb8d43f..dfe4d93098 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -36,6 +36,33 @@ #define BITCOIN_DIVISIBILITY (8) +// split longer string into 4 rows, rowlen chars each +static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) +{ + static char str[4][32 + 1]; + if (rowlen > 32) { + rowlen = 32; + } + memset(str, 0, sizeof(str)); + strlcpy(str[0], (char *)msg, rowlen + 1); + if (len > rowlen) { + strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); + } + if (len > rowlen * 2) { + strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); + } + if (len > rowlen * 3) { + strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); + } + if (len > rowlen * 4) { + str[3][rowlen - 1] = '.'; + str[3][rowlen - 2] = '.'; + str[3][rowlen - 3] = '.'; + } + static const char *ret[4] = { str[0], str[1], str[2], str[3] }; + return ret; +} + void *layoutLast = layoutHome; void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) @@ -128,6 +155,37 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) ); } +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) +{ + bool ascii_only = true; + for (uint32_t i = 0; i < size; i++) { + if (data[i] < ' ' || data[i] > '~') { + ascii_only = false; + break; + } + } + const char **str; + if (!ascii_only) { + char hex[65]; + memset(hex, 0, sizeof(hex)); + data2hex(data, (size > 32) ? 32 : size, hex); + str = split_message((const uint8_t *)hex, size * 2, 16); + } else { + str = split_message(data, size, 20); + } + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + NULL, + _("Confirm OP_RETURN:"), + str[0], + str[1], + str[2], + str[3], + NULL + ); +} + void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee) { char str_out[32], str_fee[32]; @@ -163,28 +221,6 @@ void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) ); } -// split longer string into 4 rows, rowlen chars each -static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) -{ - static char str[4][32 + 1]; - if (rowlen > 32) { - rowlen = 32; - } - memset(str, 0, sizeof(str)); - strlcpy(str[0], (char *)msg, rowlen + 1); - if (len > rowlen) { - strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); - } - if (len > rowlen * 2) { - strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); - } - if (len > rowlen * 3) { - strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); - } - static const char *ret[4] = { str[0], str[1], str[2], str[3] }; - return ret; -} - void layoutSignMessage(const uint8_t *msg, uint32_t len) { const char **str = split_message(msg, len, 16); diff --git a/firmware/layout2.h b/firmware/layout2.h index 48e001fb94..2c523a242e 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -41,6 +41,7 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); diff --git a/firmware/transaction.c b/firmware/transaction.c index 40a872d0a3..a5740e8725 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -171,6 +171,12 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T if (in->amount != 0) { return 0; // failed to compile output } + if (needs_confirm) { + layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; // user aborted + } + } uint32_t r = 0; out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); From cc0896c33451d308a51c2fefe2e8939c8a93fb94 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Nov 2017 18:34:50 +0100 Subject: [PATCH 0641/1154] add bip44 coin_type to CoinInfo --- firmware/coins-gen.py | 3 ++- firmware/coins.c | 10 ++++++++++ firmware/coins.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 75bbe63522..0cf4bbc987 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -27,7 +27,8 @@ def get_fields(coin): '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '0x00000000', '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '0x00000000', '%d' % coin['forkid'] if coin['forkid'] else '0', - '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL' + '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', + '0x%08x' % (0x80000000 + coin['bip44']), ] diff --git a/firmware/coins.c b/firmware/coins.c index 3af074b535..1d62abca98 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -49,6 +49,16 @@ const CoinInfo *coinByAddressType(uint32_t address_type) return 0; } +const CoinInfo *coinByCoinType(uint32_t coin_type) +{ + for (int i = 0; i < COINS_COUNT; i++) { + if (coin_type == coins[i].coin_type) { + return &(coins[i]); + } + } + return 0; +} + bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type) { if (!addr) return false; diff --git a/firmware/coins.h b/firmware/coins.h index 953520d5b8..bf9cd2e09d 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -42,12 +42,14 @@ typedef struct _CoinInfo { uint32_t xprv_magic; uint32_t forkid; const char *bech32_prefix; + uint32_t coin_type; } CoinInfo; extern const CoinInfo coins[COINS_COUNT]; const CoinInfo *coinByName(const char *name); const CoinInfo *coinByAddressType(uint32_t address_type); +const CoinInfo *coinByCoinType(uint32_t coin_type); bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); From a713fca85789d23c50ecdd0c13345dd1021023a9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Nov 2017 18:34:59 +0100 Subject: [PATCH 0642/1154] layout: recognize known bip44/bip49 paths in GetAddress dialog --- firmware/layout2.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/firmware/layout2.c b/firmware/layout2.c index dfe4d93098..9156ae3fba 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -325,6 +325,25 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } +static const char *slip44_extras(uint32_t coin_type) +{ + if ((coin_type & 0x80000000) == 0) { + return 0; + } + switch (coin_type & 0x7fffffff) { + case 40: return "EXP"; // Expanse + case 43: return "NEM"; // NEM + case 60: return "ETH"; // Ethereum Mainnet + case 61: return "ETC"; // Ethereum Classic Mainnet + case 108: return "UBQ"; // UBIQ + case 137: return "RSK"; // Rootstock Mainnet + case 37310: return "tRSK"; // Rootstock Testnet + } + return 0; +} + +#define BIP32_MAX_LAST_ELEMENT 1000000 + static const char *address_n_str(const uint32_t *address_n, size_t address_n_count) { if (address_n_count > 8) { @@ -334,6 +353,53 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou return _("Path: m"); } + // known BIP44/49 path + static char path[100]; + if (address_n_count == 5 && + (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49)) && + (address_n[1] & 0x80000000) && + (address_n[2] & 0x80000000) && + (address_n[3] <= 1) && + (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { + bool segwit = (address_n[0] == (0x80000000 + 49)); + bool legacy = false; + const CoinInfo *coin = coinByCoinType(address_n[1]); + const char *abbr = 0; + if (segwit) { + if (coin && coin->has_segwit && coin->has_address_type_p2sh) { + abbr = coin->coin_shortcut + 1; + } + } else { + if (coin) { + if (coin->has_segwit && coin->has_address_type_p2sh) { + legacy = true; + } + abbr = coin->coin_shortcut + 1; + } else { + abbr = slip44_extras(address_n[1]); + } + } + uint32_t accnum = (address_n[2] & 0x7fffffff) + 1; + if (abbr && accnum < 100) { + memset(path, 0, sizeof(path)); + strlcpy(path, abbr, sizeof(path)); + if (legacy) { + strlcat(path, " legacy", sizeof(path)); + } + strlcat(path, " account #", sizeof(path)); + char acc[3]; + memset(acc, 0, sizeof(acc)); + if (accnum < 10) { + acc[0] = '0' + accnum; + } else { + acc[0] = '0' + (accnum / 10); + acc[1] = '0' + (accnum % 10); + } + strlcat(path, acc, sizeof(path)); + return path; + } + } + // "Path: m" / i ' static char address_str[7 + 8 * (1 + 9 + 1) + 1]; char *c = address_str + sizeof(address_str) - 1; From 3386b16a1c187fb1fa8c48c6328fb6691a8fc570 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Nov 2017 19:22:55 +0100 Subject: [PATCH 0643/1154] GetAddress: detect mismatched coin and path, show warning --- firmware/fsm.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 081845cc14..7be43a75e3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -694,6 +694,34 @@ void fsm_msgGetAddress(GetAddress *msg) } else { strlcpy(desc, _("Address:"), sizeof(desc)); } + + bool mismatch = false; + if (msg->address_n_count == 5) { + if (msg->address_n[0] == (0x80000000 + 44)) { + mismatch |= msg->script_type != InputScriptType_SPENDADDRESS; + mismatch |= coin != coinByCoinType(msg->address_n[1]); + } else + if (msg->address_n[0] == (0x80000000 + 45)) { + mismatch |= msg->script_type != InputScriptType_SPENDMULTISIG; + mismatch |= coin != coinByCoinType(msg->address_n[1]); + } else + if (msg->address_n[0] == (0x80000000 + 49)) { + mismatch |= !coin->has_segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= msg->script_type != InputScriptType_SPENDP2SHWITNESS; + mismatch |= coin != coinByCoinType(msg->address_n[1]); + } + } + + if (mismatch) { + layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + bool qrcode = false; for (;;) { layoutAddress(address, desc, qrcode, msg->script_type == InputScriptType_SPENDWITNESS, msg->address_n, msg->address_n_count); From 4770df8912189e34859c406ce5bc08c3dff144c4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Nov 2017 19:50:42 +0100 Subject: [PATCH 0644/1154] update version to 1.6.0 --- firmware/ChangeLog | 13 +++++++++++-- firmware/trezor.h | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index ffadf9b859..41c7f9b6a3 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,7 +1,16 @@ +Version 1.6.0 +* Stable release, optional update +* Native SegWit (Bech32) address support +* Show recognized BIP44/BIP49 paths in GetAddress dialog +* NEM support +* Expanse and UBIQ chains support +* Bitcoin Gold, DigiByte, Monacoin support +* Ed25519 collective signatures (CoSi) support + Version 1.5.2 * Stable release, required update -* clean memory on start -* fix storage import from older versions +* Clean memory on start +* Fix storage import from older versions Version 1.5.1 * Stable release, optional update diff --git a/firmware/trezor.h b/firmware/trezor.h index 1bcb3cd9ff..c240cbc696 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,8 +21,8 @@ #define __TREZOR_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 5 -#define VERSION_PATCH 2 +#define VERSION_MINOR 6 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 723cf295a72ce07b96047901bb8c2e461a2488f8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 16 Nov 2017 20:03:26 +0100 Subject: [PATCH 0645/1154] device label -> device name --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 7be43a75e3..2a79ee430c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -602,7 +602,7 @@ void fsm_msgApplySettings(ApplySettings *msg) CHECK_PIN if (msg->has_label) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change label to"), msg->label, "?", NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); From cfe8a98c681704ea4d5a5dc4f4b4463251f66d87 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 24 Nov 2017 12:35:16 +0100 Subject: [PATCH 0646/1154] signing segwit change output typo --- firmware/signing.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/signing.c b/firmware/signing.c index 6cef721e63..787eebee16 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -552,6 +552,9 @@ static bool signing_check_output(TxOutputType *txoutput) { } /* * only allow segwit change if amount is smaller than what segwit inputs paid. + * this was added during the times segwit was not yet fully activated + * to make sure the user is not tricked to use witness change output + * instead of regular one therefore creating ANYONECANSPEND output */ if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) From a82bbbb30d5aed60413b1980d90790a04effafc7 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 29 Nov 2017 13:39:19 +0100 Subject: [PATCH 0647/1154] layout: encode -> encrypt typo updates #252 --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 9156ae3fba..84a48bed2a 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -250,7 +250,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key) { const char **str = split_message((const uint8_t *)key, strlen(key), 16); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - encrypt ? _("Encode value of this key?") : _("Decode value of this key?"), + encrypt ? _("Encrypt value of this key?") : _("Decrypt value of this key?"), str[0], str[1], str[2], str[3], NULL, NULL); } From f44635a9cafc7682f1f80dbdbb6645d1070ce552 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 29 Nov 2017 23:03:37 +0100 Subject: [PATCH 0648/1154] vendor: update trezor-common --- firmware/protob/messages.options | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 3d748bff8e..87f8869faf 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:13 +Features.coins max_count:15 Features.revision max_size:20 Features.bootloader_hash max_size:32 diff --git a/vendor/trezor-common b/vendor/trezor-common index 7325936f86..dc181b97b8 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 7325936f8612ce1cadff6cfb0c0045b3668c3260 +Subproject commit dc181b97b864cc667a11f7a82f2ef43eedb585a4 From bc7c66aa763858fa751e8f6353a8e18a776da65c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Dec 2017 22:30:11 +0100 Subject: [PATCH 0649/1154] add Features.model field (set to "1") --- bootloader/usb.c | 7 +++++-- firmware/fsm.c | 1 + firmware/protob/messages.options | 1 + vendor/trezor-common | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index d3498dbd0c..24e88983fa 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -227,6 +227,7 @@ static void send_msg_features(usbd_device *dev) // - patch_version = VERSION_PATCH // - bootloader_mode = True // - firmware_present = True/False + // - model = "1" if (brand_new_firmware) { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, // header @@ -242,8 +243,9 @@ static void send_msg_features(usbd_device *dev) "\x20" VERSION_PATCH_CHAR "\x28" "\x01" "\x90\x01" "\x00" + "\xaa" "\x01" "1" // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } else { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, @@ -260,8 +262,9 @@ static void send_msg_features(usbd_device *dev) "\x20" VERSION_PATCH_CHAR "\x28" "\x01" "\x90\x01" "\x01" + "\xaa" "\x01" "1" // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } } diff --git a/firmware/fsm.c b/firmware/fsm.c index 2a79ee430c..a4c48aa645 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -267,6 +267,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); + resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 87f8869faf..cbd4f007c0 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -5,6 +5,7 @@ Features.label max_size:33 Features.coins max_count:15 Features.revision max_size:20 Features.bootloader_hash max_size:32 +Features.model max_size:17 ApplySettings.language max_size:17 ApplySettings.label max_size:33 diff --git a/vendor/trezor-common b/vendor/trezor-common index dc181b97b8..8e96b42260 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit dc181b97b864cc667a11f7a82f2ef43eedb585a4 +Subproject commit 8e96b42260b84e1e0f0b00a5e528d19258c57031 From dd7b21a6cadc8254f4f026f2ac3ad8ed426de7ac Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 14:38:25 +0000 Subject: [PATCH 0650/1154] hasher: Initial commit --- firmware/Makefile | 1 + firmware/hasher.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ firmware/hasher.h | 50 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 firmware/hasher.c create mode 100644 firmware/hasher.h diff --git a/firmware/Makefile b/firmware/Makefile index 3c1fc84b0b..7eb5244811 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -20,6 +20,7 @@ OBJS += protect.o OBJS += layout2.o OBJS += recovery.o OBJS += reset.o +OBJS += hasher.o OBJS += signing.o OBJS += crypto.o OBJS += ethereum.o diff --git a/firmware/hasher.c b/firmware/hasher.c new file mode 100644 index 0000000000..ff16389ea7 --- /dev/null +++ b/firmware/hasher.c @@ -0,0 +1,63 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "hasher.h" + +void hasher_Init(Hasher *hasher, HasherType type) { + hasher->type = type; + + switch (hasher->type) { + case HASHER_SHA2: + sha256_Init(&hasher->ctx.sha2); + break; + } +} + +void hasher_Reset(Hasher *hasher) { + hasher_Init(hasher, hasher->type); +} + +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Update(&hasher->ctx.sha2, data, length); + break; + } +} + +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + switch (hasher->type) { + case HASHER_SHA2: + sha256_Final(&hasher->ctx.sha2, hash); + break; + } +} + +void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { + hasher_Final(hasher, hash); + hasher_Raw(hasher->type, hash, HASHER_DIGEST_LENGTH, hash); +} + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + + hasher_Init(&hasher, type); + hasher_Update(&hasher, data, length); + hasher_Final(&hasher, hash); +} diff --git a/firmware/hasher.h b/firmware/hasher.h new file mode 100644 index 0000000000..0338379ed4 --- /dev/null +++ b/firmware/hasher.h @@ -0,0 +1,50 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __HASHER_H__ +#define __HASHER_H__ + +#include +#include + +#include "sha2.h" + +#define HASHER_DIGEST_LENGTH 32 + +typedef enum { + HASHER_SHA2, +} HasherType; + +typedef struct { + HasherType type; + + union { + SHA256_CTX sha2; + } ctx; +} Hasher; + +void hasher_Init(Hasher *hasher, HasherType type); +void hasher_Reset(Hasher *hasher); +void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); +void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); +void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); + +void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); + +#endif From 54b086953564f97ecef09e3774d9b3b5b198edad Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 14:38:37 +0000 Subject: [PATCH 0651/1154] signing: Use Hasher instead of SHA256_CTX --- firmware/coins-gen.py | 1 + firmware/coins.h | 2 ++ firmware/crypto.c | 12 ++++---- firmware/crypto.h | 3 +- firmware/signing.c | 57 ++++++++++++++++------------------- firmware/signing.h | 1 + firmware/transaction.c | 67 +++++++++++++++++++++--------------------- firmware/transaction.h | 13 ++++---- 8 files changed, 78 insertions(+), 78 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index 0cf4bbc987..c35e7f4642 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -29,6 +29,7 @@ def get_fields(coin): '%d' % coin['forkid'] if coin['forkid'] else '0', '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', '0x%08x' % (0x80000000 + coin['bip44']), + 'HASHER_SHA2', ] diff --git a/firmware/coins.h b/firmware/coins.h index bf9cd2e09d..a9eb89f311 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -24,6 +24,7 @@ #include #include "coins_count.h" +#include "hasher.h" typedef struct _CoinInfo { const char *coin_name; @@ -43,6 +44,7 @@ typedef struct _CoinInfo { uint32_t forkid; const char *bech32_prefix; uint32_t coin_type; + HasherType hasher_type; } CoinInfo; extern const CoinInfo coins[COINS_COUNT]; diff --git a/firmware/crypto.c b/firmware/crypto.c index 391410a9e4..17b67a468a 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -54,21 +54,21 @@ uint32_t ser_length(uint32_t len, uint8_t *out) return 5; } -uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len) +uint32_t ser_length_hash(Hasher *hasher, uint32_t len) { if (len < 253) { - sha256_Update(ctx, (const uint8_t *)&len, 1); + hasher_Update(hasher, (const uint8_t *)&len, 1); return 1; } if (len < 0x10000) { uint8_t d = 253; - sha256_Update(ctx, &d, 1); - sha256_Update(ctx, (const uint8_t *)&len, 2); + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 2); return 3; } uint8_t d = 254; - sha256_Update(ctx, &d, 1); - sha256_Update(ctx, (const uint8_t *)&len, 4); + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 4); return 5; } diff --git a/firmware/crypto.h b/firmware/crypto.h index c77e4a9a00..7744c2909d 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -28,13 +28,14 @@ #include #include #include "coins.h" +#include "hasher.h" #include "types.pb.h" #define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5) uint32_t ser_length(uint32_t len, uint8_t *out); -uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len); +uint32_t ser_length_hash(Hasher *hasher, uint32_t len); int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); diff --git a/firmware/signing.c b/firmware/signing.c index 787eebee16..5c74d3d249 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -53,7 +53,7 @@ static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; -static SHA256_CTX hashers[3]; +static Hasher hashers[3]; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; @@ -323,13 +323,11 @@ void phase1_request_next_input(void) send_req_1_input(); } else { // compute segwit hashPrevouts & hashSequence - sha256_Final(&hashers[0], hash_prevouts); - sha256_Raw(hash_prevouts, 32, hash_prevouts); - sha256_Final(&hashers[1], hash_sequence); - sha256_Raw(hash_sequence, 32, hash_sequence); - sha256_Final(&hashers[2], hash_check); + hasher_Double(&hashers[0], hash_prevouts); + hasher_Double(&hashers[1], hash_sequence); + hasher_Final(&hashers[2], hash_check); // init hashOutputs - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); idx1 = 0; send_req_3_output(); } @@ -467,9 +465,9 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf tx_init(&to, inputs_count, outputs_count, version, lock_time, 0); // segwit hashes for hashPrevouts and hashSequence - sha256_Init(&hashers[0]); - sha256_Init(&hashers[1]); - sha256_Init(&hashers[2]); + hasher_Init(&hashers[0], coin->hasher_type); + hasher_Init(&hashers[1], coin->hasher_type); + hasher_Init(&hashers[2], coin->hasher_type); layoutProgressSwipe(_("Signing transaction"), 0); @@ -507,7 +505,7 @@ static bool signing_check_input(TxInputType *txinput) { tx_sequence_hash(&hashers[1], txinput); // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hashers[2], txinput); - sha256_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); + hasher_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -638,8 +636,7 @@ static void phase1_request_next_output(void) { idx1++; send_req_3_output(); } else { - sha256_Final(&hashers[0], hash_outputs); - sha256_Raw(hash_outputs, 32, hash_outputs); + hasher_Double(&hashers[0], hash_outputs); if (!signing_check_fee()) { return; } @@ -653,19 +650,18 @@ static void phase1_request_next_output(void) { static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - sha256_Init(&hashers[0]); - sha256_Update(&hashers[0], (const uint8_t *)&version, 4); - sha256_Update(&hashers[0], hash_prevouts, 32); - sha256_Update(&hashers[0], hash_sequence, 32); + hasher_Reset(&hashers[0]); + hasher_Update(&hashers[0], (const uint8_t *)&version, 4); + hasher_Update(&hashers[0], hash_prevouts, 32); + hasher_Update(&hashers[0], hash_sequence, 32); tx_prevout_hash(&hashers[0], txinput); tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); - sha256_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); + hasher_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); tx_sequence_hash(&hashers[0], txinput); - sha256_Update(&hashers[0], hash_outputs, 32); - sha256_Update(&hashers[0], (const uint8_t*) &lock_time, 4); - sha256_Update(&hashers[0], (const uint8_t*) &hash_type, 4); - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); + hasher_Update(&hashers[0], hash_outputs, 32); + hasher_Update(&hashers[0], (const uint8_t*) &lock_time, 4); + hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); + hasher_Double(&hashers[0], hash); } static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { @@ -705,8 +701,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, static bool signing_sign_input(void) { uint8_t hash[32]; - sha256_Final(&hashers[0], hash); - sha256_Raw(hash, 32, hash); + hasher_Double(&hashers[0], hash); if (memcmp(hash, hash_outputs, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); @@ -714,7 +709,7 @@ static bool signing_sign_input(void) { } uint32_t hash_type = signing_hash_type(); - sha256_Update(&ti.ctx, (const uint8_t *)&hash_type, 4); + hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); tx_hash_final(&ti, hash, false); resp.has_serialized = true; if (!signing_sign_hash(&input, privkey, pubkey, hash)) @@ -963,11 +958,11 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0); - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); } // check prevouts and script type tx_prevout_hash(&hashers[0], tx->inputs); - sha256_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + hasher_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); @@ -995,13 +990,13 @@ void signing_txack(TransactionType *tx) send_req_4_input(); } else { uint8_t hash[32]; - sha256_Final(&hashers[0], hash); + hasher_Final(&hashers[0], hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } - sha256_Init(&hashers[0]); + hasher_Reset(&hashers[0]); idx2 = 0; send_req_4_output(); } @@ -1096,7 +1091,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script - if (!compile_script_multisig_hash(&tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { + if (!compile_script_multisig_hash(&tx->inputs[0].multisig, coin->hasher_type, tx->inputs[0].script_sig.bytes + 3)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; diff --git a/firmware/signing.h b/firmware/signing.h index 012ac66e04..e4ee8c55d6 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -24,6 +24,7 @@ #include #include "bip32.h" #include "coins.h" +#include "hasher.h" #include "types.pb.h" void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); diff --git a/firmware/transaction.c b/firmware/transaction.c index a5740e8725..ec2ed1dd1c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -97,7 +97,7 @@ bool compute_address(const CoinInfo *coin, if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) { return 0; } - if (compile_script_multisig_hash(multisig, digest) == 0) { + if (compile_script_multisig_hash(multisig, coin->hasher_type, digest) == 0) { return 0; } if (script_type == InputScriptType_SPENDWITNESS) { @@ -119,7 +119,7 @@ bool compute_address(const CoinInfo *coin, raw[0] = 0; // push version raw[1] = 32; // push 32 bytes memcpy(raw+2, digest, 32); // push hash - sha256_Raw(raw, 34, digest); + hasher_Raw(coin->hasher_type, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); @@ -305,7 +305,7 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 return r; } -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash) +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash) { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; @@ -313,22 +313,22 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; - SHA256_CTX ctx; - sha256_Init(&ctx); + Hasher hasher; + hasher_Init(&hasher, hasher_type); uint8_t d[2]; - d[0] = 0x50 + m; sha256_Update(&ctx, d, 1); + d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); for (uint32_t i = 0; i < n; i++) { - d[0] = 33; sha256_Update(&ctx, d, 1); // OP_PUSH 33 + d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); if (!pubkey) return 0; - sha256_Update(&ctx, pubkey, 33); + hasher_Update(&hasher, pubkey, 33); } d[0] = 0x50 + n; d[1] = 0xAE; - sha256_Update(&ctx, d, 2); + hasher_Update(&hasher, d, 2); - sha256_Final(&ctx, hash); + hasher_Final(&hasher, hash); return 1; } @@ -367,33 +367,33 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin // tx methods -uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input) +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) { for (int i = 0; i < 32; i++) { - sha256_Update(ctx, &(input->prev_hash.bytes[31 - i]), 1); + hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); } - sha256_Update(ctx, (const uint8_t *)&input->prev_index, 4); + hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); return 36; } -uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data) +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) { - int r = ser_length_hash(ctx, size); - sha256_Update(ctx, data, size); + int r = ser_length_hash(hasher, size); + hasher_Update(hasher, data, size); return r + size; } -uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input) +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) { - sha256_Update(ctx, (const uint8_t *)&input->sequence, 4); + hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); return 4; } -uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output) +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output) { uint32_t r = 0; - sha256_Update(ctx, (const uint8_t *)&output->amount, 8); r += 8; - r += tx_script_hash(ctx, output->script_pubkey.size, output->script_pubkey.bytes); + hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; + r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); return r; } @@ -418,12 +418,12 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_header_hash(TxStruct *tx) { int r = 4; - sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->version), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); if (tx->is_segwit) { - sha256_Update(&(tx->ctx), segwit_header, 2); + hasher_Update(&(tx->hasher), segwit_header, 2); r += 2; } - return r + ser_length_hash(&(tx->ctx), tx->inputs_len); + return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) @@ -460,9 +460,9 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) if (tx->have_inputs == 0) { r += tx_serialize_header_hash(tx); } - r += tx_prevout_hash(&(tx->ctx), input); - r += tx_script_hash(&(tx->ctx), input->script_sig.size, input->script_sig.bytes); - r += tx_sequence_hash(&(tx->ctx), input); + r += tx_prevout_hash(&(tx->hasher), input); + r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); + r += tx_sequence_hash(&(tx->hasher), input); tx->have_inputs++; tx->size += r; @@ -477,7 +477,7 @@ uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_middle_hash(TxStruct *tx) { - return ser_length_hash(&(tx->ctx), tx->outputs_len); + return ser_length_hash(&(tx->hasher), tx->outputs_len); } uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) @@ -488,7 +488,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_footer_hash(TxStruct *tx) { - sha256_Update(&(tx->ctx), (const uint8_t *)&(tx->lock_time), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); return 4; } @@ -531,7 +531,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) if (tx->have_outputs == 0) { r += tx_serialize_middle_hash(tx); } - r += tx_output_hash(&(tx->ctx), output); + r += tx_output_hash(&(tx->hasher), output); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { @@ -555,7 +555,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ // we are receiving too much data return 0; } - sha256_Update(&(tx->ctx), data, datalen); + hasher_Update(&(tx->hasher), data, datalen); tx->extra_data_received += datalen; tx->size += datalen; return datalen; @@ -573,13 +573,12 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->extra_data_received = 0; tx->size = 0; tx->is_segwit = false; - sha256_Init(&(tx->ctx)); + hasher_Init(&(tx->hasher), HASHER_SHA2); } void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { - sha256_Final(&(t->ctx), hash); - sha256_Raw(hash, 32, hash); + hasher_Double(&(t->hasher), hash); if (!reverse) return; for (uint8_t i = 0; i < 16; i++) { uint8_t k = hash[31 - i]; diff --git a/firmware/transaction.h b/firmware/transaction.h index d802ece30c..2e9230d3b0 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -25,6 +25,7 @@ #include "sha2.h" #include "bip32.h" #include "coins.h" +#include "hasher.h" #include "types.pb.h" typedef struct { @@ -43,21 +44,21 @@ typedef struct { uint32_t size; - SHA256_CTX ctx; + Hasher hasher; } TxStruct; bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, uint8_t *hash); +uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); -uint32_t tx_prevout_hash(SHA256_CTX *ctx, const TxInputType *input); -uint32_t tx_script_hash(SHA256_CTX *ctx, uint32_t size, const uint8_t *data); -uint32_t tx_sequence_hash(SHA256_CTX *ctx, const TxInputType *input); -uint32_t tx_output_hash(SHA256_CTX *ctx, const TxOutputBinType *output); +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); From a1e911aa4c06a88d563a692f54e840f0a87fd3e7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 16:23:37 +0000 Subject: [PATCH 0652/1154] transaction: Do not hardcode HASHER_SHA2 --- firmware/signing.c | 6 +++--- firmware/transaction.c | 4 ++-- firmware/transaction.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 5c74d3d249..3402cdea8d 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -463,7 +463,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->hasher_type); // segwit hashes for hashPrevouts and hashSequence hasher_Init(&hashers[0], coin->hasher_type); hasher_Init(&hashers[1], coin->hasher_type); @@ -883,7 +883,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_META: - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->hasher_type); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; if (tp.inputs_len > 0) { @@ -957,7 +957,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->hasher_type); hasher_Reset(&hashers[0]); } // check prevouts and script type diff --git a/firmware/transaction.c b/firmware/transaction.c index ec2ed1dd1c..c7cce44f14 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -561,7 +561,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_type) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; @@ -573,7 +573,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->extra_data_received = 0; tx->size = 0; tx->is_segwit = false; - hasher_Init(&(tx->hasher), HASHER_SHA2); + hasher_Init(&(tx->hasher), hasher_type); } void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) diff --git a/firmware/transaction.h b/firmware/transaction.h index 2e9230d3b0..a65f58970c 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -65,7 +65,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_type); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); From 0e60ba54b77615e6c687b6838ee744afa5668aa7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 16:38:27 +0000 Subject: [PATCH 0653/1154] crypto: Use Hasher for message signing --- firmware/crypto.c | 37 ++++++++++++++++--------------------- vendor/trezor-crypto | 2 +- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 17b67a468a..924e5766a3 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -112,18 +112,22 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin } } -int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); +static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + hasher_Init(&hasher, coin->hasher_type); + hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); - sha256_Update(&ctx, varint, l); - sha256_Update(&ctx, message, message_len); - uint8_t hash[32]; - sha256_Final(&ctx, hash); - sha256_Raw(hash, 32, hash); + hasher_Update(&hasher, varint, l); + hasher_Update(&hasher, message, message_len); + hasher_Double(&hasher, hash); +} + +int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) +{ + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, message, message_len, hash); + uint8_t pby; int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); if (result == 0) { @@ -152,17 +156,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes return 1; } - // calculate hash - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); - uint8_t varint[5]; - uint32_t l = ser_length(message_len, varint); - sha256_Update(&ctx, varint, l); - sha256_Update(&ctx, message, message_len); - uint8_t hash[32]; - sha256_Final(&ctx, hash); - sha256_Raw(hash, 32, hash); + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, message, message_len, hash); uint8_t recid = (signature[0] - 27) % 4; bool compressed = signature[0] >= 31; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 95a522bf1a..764cc4c6e8 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 95a522bf1a453880050521661258d7943e966d1f +Subproject commit 764cc4c6e8ef32e7e1a77f0496ae090f11a36def From dc781725c62aa9b05a0bcd48428ebc27ec469e0d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 16:44:29 +0000 Subject: [PATCH 0654/1154] hasher: Move to trezor-crypto This reverts commit dd7b21a6cadc8254f4f026f2ac3ad8ed426de7ac. --- firmware/Makefile | 3 ++- firmware/hasher.c | 63 ----------------------------------------------- firmware/hasher.h | 50 ------------------------------------- 3 files changed, 2 insertions(+), 114 deletions(-) delete mode 100644 firmware/hasher.c delete mode 100644 firmware/hasher.h diff --git a/firmware/Makefile b/firmware/Makefile index 7eb5244811..7a5a16a3eb 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -20,7 +20,6 @@ OBJS += protect.o OBJS += layout2.o OBJS += recovery.o OBJS += reset.o -OBJS += hasher.o OBJS += signing.o OBJS += crypto.o OBJS += ethereum.o @@ -59,6 +58,8 @@ OBJS += ../vendor/trezor-crypto/segwit_addr.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha3.o +OBJS += ../vendor/trezor-crypto/blake256.o +OBJS += ../vendor/trezor-crypto/hasher.o OBJS += ../vendor/trezor-crypto/aes/aescrypt.o OBJS += ../vendor/trezor-crypto/aes/aeskey.o diff --git a/firmware/hasher.c b/firmware/hasher.c deleted file mode 100644 index ff16389ea7..0000000000 --- a/firmware/hasher.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2017 Saleem Rashid - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "hasher.h" - -void hasher_Init(Hasher *hasher, HasherType type) { - hasher->type = type; - - switch (hasher->type) { - case HASHER_SHA2: - sha256_Init(&hasher->ctx.sha2); - break; - } -} - -void hasher_Reset(Hasher *hasher) { - hasher_Init(hasher, hasher->type); -} - -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) { - switch (hasher->type) { - case HASHER_SHA2: - sha256_Update(&hasher->ctx.sha2, data, length); - break; - } -} - -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - switch (hasher->type) { - case HASHER_SHA2: - sha256_Final(&hasher->ctx.sha2, hash); - break; - } -} - -void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) { - hasher_Final(hasher, hash); - hasher_Raw(hasher->type, hash, HASHER_DIGEST_LENGTH, hash); -} - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher; - - hasher_Init(&hasher, type); - hasher_Update(&hasher, data, length); - hasher_Final(&hasher, hash); -} diff --git a/firmware/hasher.h b/firmware/hasher.h deleted file mode 100644 index 0338379ed4..0000000000 --- a/firmware/hasher.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2017 Saleem Rashid - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#ifndef __HASHER_H__ -#define __HASHER_H__ - -#include -#include - -#include "sha2.h" - -#define HASHER_DIGEST_LENGTH 32 - -typedef enum { - HASHER_SHA2, -} HasherType; - -typedef struct { - HasherType type; - - union { - SHA256_CTX sha2; - } ctx; -} Hasher; - -void hasher_Init(Hasher *hasher, HasherType type); -void hasher_Reset(Hasher *hasher); -void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length); -void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); -void hasher_Double(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]); - -void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]); - -#endif From 268e7de109f083ff83620b02c998768f93125fe1 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 18:02:13 +0000 Subject: [PATCH 0655/1154] Update trezor-crypto --- firmware/coins.c | 2 +- firmware/crypto.c | 10 +++++----- firmware/signing.c | 2 +- firmware/transaction.c | 14 +++++++------- firmware/u2f.c | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 1d62abca98..ae057cf6e1 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -63,7 +63,7 @@ bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *ad { if (!addr) return false; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int len = base58_decode_check(addr, addr_raw, MAX_ADDR_RAW_SIZE); + int len = base58_decode_check(addr, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); if (len >= 21) { return coinExtractAddressTypeRaw(coin, addr_raw, address_type); } diff --git a/firmware/crypto.c b/firmware/crypto.c index 924e5766a3..3eeba4a641 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -178,8 +178,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_raw(pubkey, coin->address_type, recovered_raw); + size_t len = base58_decode_check(address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_raw(pubkey, coin->address_type, coin->hasher_type, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type) + 20) { return 2; @@ -187,8 +187,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes } else // segwit-in-p2sh if (signature[0] >= 35 && signature[0] <= 38) { - size_t len = base58_decode_check(address, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, recovered_raw); + size_t len = base58_decode_check(address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->hasher_type, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { return 2; @@ -202,7 +202,7 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { return 4; } - ecdsa_get_pubkeyhash(pubkey, addr_raw); + ecdsa_get_pubkeyhash(pubkey, coin->hasher_type, addr_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) { return 2; diff --git a/firmware/signing.c b/firmware/signing.c index 3402cdea8d..38f87ebe1c 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -424,7 +424,7 @@ bool compile_input_script_sig(TxInputType *tinput) tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, hash); + ecdsa_get_pubkeyhash(node.public_key, coin->hasher_type, hash); tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); } return tinput->script_sig.size > 0; diff --git a/firmware/transaction.c b/firmware/transaction.c index c7cce44f14..9067bb9d21 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -123,7 +123,7 @@ bool compute_address(const CoinInfo *coin, prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->hasher_type, address, MAX_ADDR_SIZE)) { return 0; } } else { @@ -131,7 +131,7 @@ bool compute_address(const CoinInfo *coin, prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->hasher_type, address, MAX_ADDR_SIZE)) { return 0; } } @@ -140,7 +140,7 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_segwit || !coin->bech32_prefix) { return 0; } - ecdsa_get_pubkeyhash(node->public_key, digest); + ecdsa_get_pubkeyhash(node->public_key, coin->hasher_type, digest); if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { return 0; } @@ -152,9 +152,9 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_address_type_p2sh) { return 0; } - ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, address, MAX_ADDR_SIZE); + ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->hasher_type, address, MAX_ADDR_SIZE); } else { - ecdsa_get_address(node->public_key, coin->address_type, address, MAX_ADDR_SIZE); + ecdsa_get_address(node->public_key, coin->address_type, coin->hasher_type, address, MAX_ADDR_SIZE); } return 1; } @@ -219,7 +219,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T return 0; // failed to compile output } - addr_raw_len = base58_decode_check(in->address, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(in->address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; if (coin->has_address_type // p2pkh && address_check_prefix(addr_raw, coin->address_type) @@ -639,7 +639,7 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { output_script_size = 2 + addr_raw_len; } else { - addr_raw_len = base58_decode_check(txoutput->address, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(txoutput->address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { output_script_size = TXSIZE_P2PKHASH; diff --git a/firmware/u2f.c b/firmware/u2f.c index 1a8270e1fd..23902183a2 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -613,7 +613,7 @@ void u2f_register(const APDU *a) memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); - if (ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { send_u2f_error(U2F_SW_WRONG_DATA); return; } @@ -735,7 +735,7 @@ void u2f_authenticate(const APDU *a) sig_base.flags = resp->flags; memcpy(sig_base.ctr, resp->ctr, 4); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - if (ecdsa_sign(&nist256p1, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { + if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { send_u2f_error(U2F_SW_WRONG_DATA); return; } From 6e25e0b3634a7eda6f930cefbae2ddd142dfbd06 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 18:28:53 +0000 Subject: [PATCH 0656/1154] coins: Use curve_info instead of HasherType --- firmware/coins-gen.py | 2 +- firmware/coins.c | 3 ++- firmware/coins.h | 3 ++- firmware/crypto.c | 12 ++++++------ firmware/signing.c | 16 ++++++++-------- firmware/transaction.c | 18 +++++++++--------- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index c35e7f4642..b4ccf5f765 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -29,7 +29,7 @@ def get_fields(coin): '%d' % coin['forkid'] if coin['forkid'] else '0', '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', '0x%08x' % (0x80000000 + coin['bip44']), - 'HASHER_SHA2', + '&%s_info' % 'secp256k1', ] diff --git a/firmware/coins.c b/firmware/coins.c index ae057cf6e1..94766a1757 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -22,6 +22,7 @@ #include "address.h" #include "ecdsa.h" #include "base58.h" +#include "secp256k1.h" // filled CoinInfo structure defined in coins.h const CoinInfo coins[COINS_COUNT] = { @@ -63,7 +64,7 @@ bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *ad { if (!addr) return false; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int len = base58_decode_check(addr, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + int len = base58_decode_check(addr, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); if (len >= 21) { return coinExtractAddressTypeRaw(coin, addr_raw, address_type); } diff --git a/firmware/coins.h b/firmware/coins.h index a9eb89f311..9ee822a5e5 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -23,6 +23,7 @@ #include #include +#include "bip32.h" #include "coins_count.h" #include "hasher.h" @@ -44,7 +45,7 @@ typedef struct _CoinInfo { uint32_t forkid; const char *bech32_prefix; uint32_t coin_type; - HasherType hasher_type; + const curve_info *curve; } CoinInfo; extern const CoinInfo coins[COINS_COUNT]; diff --git a/firmware/crypto.c b/firmware/crypto.c index 3eeba4a641..2d12d9b5d6 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -114,7 +114,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { Hasher hasher; - hasher_Init(&hasher, coin->hasher_type); + hasher_Init(&hasher, coin->curve->hasher_type); hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); @@ -178,8 +178,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - size_t len = base58_decode_check(address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_raw(pubkey, coin->address_type, coin->hasher_type, recovered_raw); + size_t len = base58_decode_check(address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_type, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type) + 20) { return 2; @@ -187,8 +187,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes } else // segwit-in-p2sh if (signature[0] >= 35 && signature[0] <= 38) { - size_t len = base58_decode_check(address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->hasher_type, recovered_raw); + size_t len = base58_decode_check(address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_type, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { return 2; @@ -202,7 +202,7 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { return 4; } - ecdsa_get_pubkeyhash(pubkey, coin->hasher_type, addr_raw); + ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_type, addr_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) { return 2; diff --git a/firmware/signing.c b/firmware/signing.c index 38f87ebe1c..e31078b65b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -424,7 +424,7 @@ bool compile_input_script_sig(TxInputType *tinput) tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, coin->hasher_type, hash); + ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_type, hash); tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); } return tinput->script_sig.size > 0; @@ -463,11 +463,11 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInf multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->hasher_type); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); // segwit hashes for hashPrevouts and hashSequence - hasher_Init(&hashers[0], coin->hasher_type); - hasher_Init(&hashers[1], coin->hasher_type); - hasher_Init(&hashers[2], coin->hasher_type); + hasher_Init(&hashers[0], coin->curve->hasher_type); + hasher_Init(&hashers[1], coin->curve->hasher_type); + hasher_Init(&hashers[2], coin->curve->hasher_type); layoutProgressSwipe(_("Signing transaction"), 0); @@ -883,7 +883,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_META: - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->hasher_type); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_type); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; if (tp.inputs_len > 0) { @@ -957,7 +957,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->hasher_type); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); hasher_Reset(&hashers[0]); } // check prevouts and script type @@ -1091,7 +1091,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script - if (!compile_script_multisig_hash(&tx->inputs[0].multisig, coin->hasher_type, tx->inputs[0].script_sig.bytes + 3)) { + if (!compile_script_multisig_hash(&tx->inputs[0].multisig, coin->curve->hasher_type, tx->inputs[0].script_sig.bytes + 3)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; diff --git a/firmware/transaction.c b/firmware/transaction.c index 9067bb9d21..2e8f24664c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -97,7 +97,7 @@ bool compute_address(const CoinInfo *coin, if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) { return 0; } - if (compile_script_multisig_hash(multisig, coin->hasher_type, digest) == 0) { + if (compile_script_multisig_hash(multisig, coin->curve->hasher_type, digest) == 0) { return 0; } if (script_type == InputScriptType_SPENDWITNESS) { @@ -119,11 +119,11 @@ bool compute_address(const CoinInfo *coin, raw[0] = 0; // push version raw[1] = 32; // push 32 bytes memcpy(raw+2, digest, 32); // push hash - hasher_Raw(coin->hasher_type, raw, 34, digest); + hasher_Raw(coin->curve->hasher_type, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, coin->hasher_type, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_type, address, MAX_ADDR_SIZE)) { return 0; } } else { @@ -131,7 +131,7 @@ bool compute_address(const CoinInfo *coin, prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, coin->hasher_type, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_type, address, MAX_ADDR_SIZE)) { return 0; } } @@ -140,7 +140,7 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_segwit || !coin->bech32_prefix) { return 0; } - ecdsa_get_pubkeyhash(node->public_key, coin->hasher_type, digest); + ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_type, digest); if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { return 0; } @@ -152,9 +152,9 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_address_type_p2sh) { return 0; } - ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->hasher_type, address, MAX_ADDR_SIZE); + ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_type, address, MAX_ADDR_SIZE); } else { - ecdsa_get_address(node->public_key, coin->address_type, coin->hasher_type, address, MAX_ADDR_SIZE); + ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_type, address, MAX_ADDR_SIZE); } return 1; } @@ -219,7 +219,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T return 0; // failed to compile output } - addr_raw_len = base58_decode_check(in->address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; if (coin->has_address_type // p2pkh && address_check_prefix(addr_raw, coin->address_type) @@ -639,7 +639,7 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { output_script_size = 2 + addr_raw_len; } else { - addr_raw_len = base58_decode_check(txoutput->address, coin->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { output_script_size = TXSIZE_P2PKHASH; From 7cd99459053a59523aa942ce848ccde6dce99bc2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 18:35:37 +0000 Subject: [PATCH 0657/1154] fsm: Use coin->curve_name --- firmware/coins-gen.py | 1 + firmware/coins.c | 1 + firmware/coins.h | 1 + firmware/fsm.c | 8 ++++---- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index b4ccf5f765..af5a3a8de1 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -29,6 +29,7 @@ def get_fields(coin): '%d' % coin['forkid'] if coin['forkid'] else '0', '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', '0x%08x' % (0x80000000 + coin['bip44']), + '%s_NAME' % 'secp256k1'.upper(), '&%s_info' % 'secp256k1', ] diff --git a/firmware/coins.c b/firmware/coins.c index 94766a1757..0618c60ddf 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -20,6 +20,7 @@ #include #include "coins.h" #include "address.h" +#include "curves.h" #include "ecdsa.h" #include "base58.h" #include "secp256k1.h" diff --git a/firmware/coins.h b/firmware/coins.h index 9ee822a5e5..eae9bbd61c 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -45,6 +45,7 @@ typedef struct _CoinInfo { uint32_t forkid; const char *bech32_prefix; uint32_t coin_type; + const char *curve_name; const curve_info *curve; } CoinInfo; diff --git a/firmware/fsm.c b/firmware/fsm.c index a4c48aa645..96760a97b7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -389,7 +389,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - const char *curve = SECP256K1_NAME; + const char *curve = coin->curve_name; if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } @@ -501,7 +501,7 @@ void fsm_msgSignTx(SignTx *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0); + const HDNode *node = fsm_getDerivedNode(coin->curve_name, 0, 0); if (!node) return; signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); @@ -670,7 +670,7 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count); if (!node) return; hdnode_fill_public_key(node); @@ -852,7 +852,7 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe(_("Signing"), 0); From 8c02b50414614c560808025b1523fdc4943c4061 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 10 Dec 2017 23:40:06 +0100 Subject: [PATCH 0658/1154] add installation info to readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 62d2377bb8..620efd8a29 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,10 @@ This creates file `build/bootloader-TAG.bin` and prints its fingerprint and size 3. Compute fingerprint: `tail -c +257 trezor.signed.bin | sha256sum` Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). Firmware has a special header (of length 256 bytes) holding signatures themselves, which must be avoided while calculating the fingerprint, that's why tail command has to be used. + +## How to install custom built firmware? + +**WARNING: This will erase the recovery seed stored on the device! You should never do this on TREZOR that contains coins!** + +1. Install python-trezor: `pip install trezor`, (more info +2. `trezorctl firmware_update -f build/trezor-TAG.bin` From d822e1f19ee714e8479285114b0b9fef257733b4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 10 Dec 2017 23:40:47 +0100 Subject: [PATCH 0659/1154] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 620efd8a29..2b84ad2b5f 100644 --- a/README.md +++ b/README.md @@ -34,5 +34,5 @@ Step 3 should produce the same sha256 fingerprint like your local build (for the **WARNING: This will erase the recovery seed stored on the device! You should never do this on TREZOR that contains coins!** -1. Install python-trezor: `pip install trezor`, (more info +1. Install python-trezor: `pip install trezor` (more info) 2. `trezorctl firmware_update -f build/trezor-TAG.bin` From 14d15dab993bfc75c21611129703c15bf8582349 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 12 Dec 2017 01:48:07 +0100 Subject: [PATCH 0660/1154] fsm: refactor path checking code into path_mismatch function --- firmware/fsm.c | 79 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 96760a97b7..e1c6b84c37 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -660,6 +660,67 @@ void fsm_msgApplyFlags(ApplyFlags *msg) fsm_sendSuccess(_("Flags applied")); } +static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) +{ + bool mismatch = false; + + // m : no path + if (msg->address_n_count == 0) { + return false; + } + + // m/44' : BIP44 Legacy + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 44)) { + mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); + mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/45' - BIP45 Copay Abandoned Multisig P2SH + // m / purpose' / cosigner_index / change / address_index + if (msg->address_n[0] == (0x80000000 + 45)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count == 4); + mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/45' - BIP48 Copay Multisig P2SH + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 48)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/49' : BIP49 SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 49)) { + mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + return false; +} + void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); @@ -696,23 +757,7 @@ void fsm_msgGetAddress(GetAddress *msg) strlcpy(desc, _("Address:"), sizeof(desc)); } - bool mismatch = false; - if (msg->address_n_count == 5) { - if (msg->address_n[0] == (0x80000000 + 44)) { - mismatch |= msg->script_type != InputScriptType_SPENDADDRESS; - mismatch |= coin != coinByCoinType(msg->address_n[1]); - } else - if (msg->address_n[0] == (0x80000000 + 45)) { - mismatch |= msg->script_type != InputScriptType_SPENDMULTISIG; - mismatch |= coin != coinByCoinType(msg->address_n[1]); - } else - if (msg->address_n[0] == (0x80000000 + 49)) { - mismatch |= !coin->has_segwit; - mismatch |= !coin->has_address_type_p2sh; - mismatch |= msg->script_type != InputScriptType_SPENDP2SHWITNESS; - mismatch |= coin != coinByCoinType(msg->address_n[1]); - } - } + bool mismatch = path_mismatched(coin, msg); if (mismatch) { layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); From 6deb9fde32a57c33c4ea65700cee2e35c3e89cf2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Sep 2017 10:13:17 +0000 Subject: [PATCH 0661/1154] setup: avoid usb host mode --- setup.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/setup.c b/setup.c index 4dda1b7c01..5adff947e9 100644 --- a/setup.c +++ b/setup.c @@ -25,6 +25,7 @@ #include "rng.h" #include "layout.h" +#include "util.h" uint32_t __stack_chk_guard; @@ -65,9 +66,6 @@ void setup(void) // enable SPI clock rcc_periph_clock_enable(RCC_SPI1); - // enable OTG FS clock - rcc_periph_clock_enable(RCC_OTGFS); - // enable RNG rcc_periph_clock_enable(RCC_RNG); RNG_CR |= RNG_CR_RNGEN; @@ -98,8 +96,14 @@ void setup(void) spi_enable(SPI1); // enable OTG_FS + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); - gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO10 | GPIO11 | GPIO12); + + // enable OTG FS clock + rcc_periph_clock_enable(RCC_OTGFS); + // clear USB OTG_FS peripheral dedicated RAM + memset_reg((void *) 0x50020000, (void *) 0x50020500, 0); } void setupApp(void) @@ -120,4 +124,7 @@ void setupApp(void) // hotfix for old bootloader gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); + gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } From b4a61d60c3eb820c1eb08f3aa5b7fcf5d65328a7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sun, 20 Aug 2017 14:43:21 +0200 Subject: [PATCH 0662/1154] bootloader: Delay flashing firmware magic. Only flash firmware magic at the end. Also simplified the code a bit. --- bootloader/usb.c | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 24e88983fa..a67210e930 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -36,6 +36,8 @@ #include "ecdsa.h" #include "secp256k1.h" +#define FIRMWARE_MAGIC "TRZR" + #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -479,8 +481,16 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } + // check firmware magic + if (memcmp(p, FIRMWARE_MAGIC, 4) != 0) { + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Wrong firmware header.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + return; + } flash_state = STATE_FLASHING; - flash_pos = 0; + p += 4; // Don't flash firmware header yet. + flash_pos = 4; wi = 0; flash_unlock(); while (p < buf + 64) { @@ -560,31 +570,23 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); - // check if to restore old storage area but only if signatures are ok - if ((flags & 0x01) && signatures_ok(NULL)) { - // copy new stuff - memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); - // replace "TRZR" in header with 0000 when hash not confirmed - if (!hash_check_ok) { - meta_backup[0] = 0; - meta_backup[1] = 0; - meta_backup[2] = 0; - meta_backup[3] = 0; - } - // erase storage - erase_metadata_sectors(); - // restore metadata from backup - restore_metadata(meta_backup); + // wipe storage if signatures are not ok or the firmware flag isn't set. + if ((flags & 0x01) == 0 || !signatures_ok(NULL)) { memset(meta_backup, 0, sizeof(meta_backup)); - } else { - // replace "TRZR" in header with 0000 when hash not confirmed - if (!hash_check_ok) { - // no need to erase, because we are just erasing bits - flash_unlock(); - flash_program_word(FLASH_META_START, 0x00000000); - flash_lock(); - } } + // copy new firmware header + memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); + // write "TRZR" in header only when hash was confirmed + if (hash_check_ok) { + memcpy(meta_backup, FIRMWARE_MAGIC, 4); + } else { + memset(meta_backup, 0, 4); + } + + // no need to erase, because we are not changing any already flashed byte. + restore_metadata(meta_backup); + memset(meta_backup, 0, sizeof(meta_backup)); + flash_state = STATE_END; if (hash_check_ok) { layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); From 2387f7181373c6bd6db4a6917bdd90bd7e9b72bf Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 23 Aug 2017 17:21:44 +0200 Subject: [PATCH 0663/1154] bootloader: Check that erasing flash worked --- bootloader/usb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bootloader/usb.c b/bootloader/usb.c index a67210e930..a15ce61c0b 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -439,6 +439,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (brand_new_firmware || button.YesUp) { // backup metadata backup_metadata(meta_backup); + flash_clear_status_flags(); flash_unlock(); // erase metadata area for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { @@ -452,6 +453,20 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } layoutProgress("INSTALLING ... Please wait", 0); flash_lock(); + + // check that metadata was succesfully erased + // flash status register should show now error and + // the config block should contain only \xff. + uint8_t hash[32]; + sha256_Raw((unsigned char *)FLASH_META_START, FLASH_META_LEN, hash); + if ((FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) != 0 + || memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + return; + } + send_msg_success(dev); flash_state = STATE_FLASHSTART; return; From 36f3b7fe0959b75f9b2ebceb3ed0d53c7e3c58f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Sep 2017 12:03:10 +0000 Subject: [PATCH 0664/1154] firmware: mark usb buffer variables confidential --- firmware/messages.c | 6 +++--- firmware/usb.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 15c510bd99..d8411bfa85 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -222,7 +222,7 @@ enum { void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) { - static uint8_t msg_data[MSG_IN_SIZE]; + static CONFIDENTIAL uint8_t msg_data[MSG_IN_SIZE]; memset(msg_data, 0, sizeof(msg_data)); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); bool status = pb_decode(&stream, fields, msg_data); @@ -236,7 +236,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * void msg_read_common(char type, const uint8_t *buf, int len) { static char read_state = READSTATE_IDLE; - static uint8_t msg_in[MSG_IN_SIZE]; + static CONFIDENTIAL uint8_t msg_in[MSG_IN_SIZE]; static uint16_t msg_id = 0xFFFF; static uint32_t msg_size = 0; static uint32_t msg_pos = 0; @@ -304,7 +304,7 @@ const uint8_t *msg_debug_out_data(void) #endif -uint8_t msg_tiny[64]; +CONFIDENTIAL uint8_t msg_tiny[64]; uint16_t msg_tiny_id = 0xFFFF; void msg_read_tiny(const uint8_t *buf, int len) diff --git a/firmware/usb.c b/firmware/usb.c index deae841d64..55bd095178 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -343,7 +343,7 @@ static volatile char tiny = 0; static void hid_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; - static uint8_t buf[64] __attribute__ ((aligned(4))); + static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; debugLog(0, "", "hid_rx_callback"); if (!tiny) { @@ -356,7 +356,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; - static uint8_t buf[64] __attribute__ ((aligned(4))); + static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); debugLog(0, "", "hid_u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; @@ -367,7 +367,7 @@ static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; - static uint8_t buf[64] __attribute__ ((aligned(4))); + static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; debugLog(0, "", "hid_debug_rx_callback"); if (!tiny) { From 41901a8056908a1aa15ef7eaccc42e8c5ff316ab Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Sep 2017 17:09:34 +0200 Subject: [PATCH 0665/1154] firmware: rework protectChangePin bootloader: wait for flash operation to finish --- bootloader/usb.c | 2 ++ firmware/protect.c | 29 ++++++++++++++++------------- firmware/u2f.c | 14 ++++++-------- memory.ld | 2 +- memory_app_1.0.0.ld | 2 +- memory_app_fastflash.ld | 2 +- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index a15ce61c0b..ee007c665c 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -439,6 +439,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (brand_new_firmware || button.YesUp) { // backup metadata backup_metadata(meta_backup); + flash_wait_for_last_operation(); flash_clear_status_flags(); flash_unlock(); // erase metadata area @@ -452,6 +453,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } layoutProgress("INSTALLING ... Please wait", 0); + flash_wait_for_last_operation(); flash_lock(); // check that metadata was succesfully erased diff --git a/firmware/protect.c b/firmware/protect.c index 82a1989170..f270d08351 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -212,24 +212,27 @@ bool protectPin(bool use_cached) bool protectChangePin(void) { - const char *pin; - char pin1[17], pin2[17]; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + static CONFIDENTIAL char pin_compare[17]; + + const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (!pin) { return false; } - strlcpy(pin1, pin, sizeof(pin1)); + + strlcpy(pin_compare, pin, sizeof(pin_compare)); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); - if (!pin) { - return false; - } - strlcpy(pin2, pin, sizeof(pin2)); - if (strcmp(pin1, pin2) == 0) { - storage_setPin(pin1); - return true; - } else { - return false; + + const bool result = pin && (strncmp(pin_compare, pin, sizeof(pin_compare)) == 0); + + if (result) { + storage_setPin(pin_compare); } + + memset(pin_compare, 0, sizeof(pin_compare)); + + return result; } bool protectPassphrase(void) diff --git a/firmware/u2f.c b/firmware/u2f.c index 23902183a2..2c084da40b 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -32,7 +32,6 @@ #include "rng.h" #include "hmac.h" #include "util.h" -#include "macros.h" #include "gettext.h" #include "u2f/u2f.h" @@ -274,7 +273,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) dialog_timeout = U2F_TIMEOUT; U2FHID_FRAME f; - MEMSET_BZERO(&f, sizeof(f)); + memset(&f, 0, sizeof(f)); f.cid = cid; f.init.cmd = U2FHID_WINK; f.init.bcntl = 0; @@ -294,7 +293,7 @@ void u2fhid_init(const U2FHID_FRAME *in) return; } - MEMSET_BZERO(&f, sizeof(f)); + memset(&f, 0, sizeof(f)); f.cid = in->cid; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; @@ -374,7 +373,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // debugLog(0, "", "send_u2fhid_msg"); - MEMSET_BZERO(&f, sizeof(f)); + memset(&f, 0, sizeof(f)); f.cid = cid; f.init.cmd = cmd; f.init.bcnth = len >> 8; @@ -390,7 +389,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // Cont packet(s) for (; l > 0; l -= psz, p += psz) { // debugLog(0, "", "send_u2fhid_msg con"); - MEMSET_BZERO(&f.cont.data, sizeof(f.cont.data)); + memset(&f.cont.data, 0, sizeof(f.cont.data)); f.cont.seq = seq++; psz = MIN(sizeof(f.cont.data), l); memcpy(f.cont.data, p, psz); @@ -407,7 +406,7 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err) { U2FHID_FRAME f; - MEMSET_BZERO(&f, sizeof(f)); + memset(&f, 0, sizeof(f)); f.cid = fcid; f.init.cmd = U2FHID_ERROR; f.init.bcntl = 1; @@ -585,8 +584,7 @@ void u2f_register(const APDU *a) if (last_req_state == REG_PASS) { uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; - MEMSET_BZERO(data, sizeof(data)); - + memset(data, 0, sizeof(data)); resp->registerId = U2F_REGISTER_ID; resp->keyHandleLen = KEY_HANDLE_LEN; diff --git a/memory.ld b/memory.ld index 94667b42d0..b147a90997 100644 --- a/memory.ld +++ b/memory.ld @@ -10,7 +10,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); } >ram } diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index 7a09b7899f..291bfd3120 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -10,7 +10,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); } >ram } diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index 55b0fb65c0..fc17e75f25 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -10,7 +10,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); } >ram } From 57bbcc754adde3ca5d01741e97a8f33d652ef5c2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Aug 2017 09:17:05 +0200 Subject: [PATCH 0666/1154] storage: make storage accessible only via functions add calls also for debug build and use them in fsm --- firmware/fsm.c | 28 ++++++++++++------------ firmware/protect.c | 4 ++-- firmware/recovery.c | 11 ++++------ firmware/reset.c | 25 ++++++++++----------- firmware/storage.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ firmware/storage.h | 14 ++++++++++-- 6 files changed, 96 insertions(+), 39 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index e1c6b84c37..b8b183f1f9 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -217,20 +217,20 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); - resp->has_pin_protection = true; resp->pin_protection = storage.has_pin; - resp->has_passphrase_protection = true; resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; + resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); + resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (storage.has_language) { + if (storage_getLanguage()) { resp->has_language = true; - strlcpy(resp->language, storage.language, sizeof(resp->language)); + strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); } - if (storage.has_label) { + if (storage_getLabel()) { resp->has_label = true; - strlcpy(resp->label, storage.label, sizeof(resp->label)); + strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); } _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); @@ -262,7 +262,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->coins[i].force_bip143 = coins[i].force_bip143; } resp->has_initialized = true; resp->initialized = storage_isInitialized(); - resp->has_imported = true; resp->imported = storage.has_imported && storage.imported; + resp->has_imported = true; resp->imported = storage_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); @@ -1520,9 +1520,9 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) resp.layout.size = OLED_BUFSIZE; memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - if (storage.has_pin) { + if (storage_hasPin()) { resp.has_pin = true; - strlcpy(resp.pin, storage.pin, sizeof(resp.pin)); + strlcpy(resp.pin, storage_getPin(), sizeof(resp.pin)); } resp.has_matrix = true; @@ -1540,18 +1540,18 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - if (storage.has_mnemonic) { + if (storage_hasMnemonic()) { resp.has_mnemonic = true; - strlcpy(resp.mnemonic, storage.mnemonic, sizeof(resp.mnemonic)); + strlcpy(resp.mnemonic, storage_getMnemonic(), sizeof(resp.mnemonic)); } - if (storage.has_node) { + if (storage_hasNode()) { resp.has_node = true; - memcpy(&(resp.node), &(storage.node), sizeof(HDNode)); + memcpy(&(resp.node), storage_getNode(), sizeof(HDNode)); } resp.has_passphrase_protection = true; - resp.passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection; + resp.passphrase_protection = storage_hasPassphraseProtection(); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } diff --git a/firmware/protect.c b/firmware/protect.c index f270d08351..74f5468363 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -155,7 +155,7 @@ static void protectCheckMaxTry(uint32_t wait) { bool protectPin(bool use_cached) { - if (!storage.has_pin || storage.pin[0] == 0 || (use_cached && session_isPinCached())) { + if (!storage_hasPin() || (use_cached && session_isPinCached())) { return true; } uint32_t *fails = storage_getPinFailsPtr(); @@ -237,7 +237,7 @@ bool protectChangePin(void) bool protectPassphrase(void) { - if (!storage.has_passphrase_protection || !storage.passphrase_protection || session_isPassphraseCached()) { + if (!storage_hasPassphraseProtection() || session_isPassphraseCached()) { return true; } diff --git a/firmware/recovery.c b/firmware/recovery.c index bdc1485dea..9d3c955488 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -130,7 +130,7 @@ static void recovery_request(void) { * Check mnemonic and send success/failure. */ static void recovery_done(void) { - char new_mnemonic[sizeof(storage.mnemonic)] = {0}; + char new_mnemonic[241] = {0}; // TODO: remove constant strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); for (uint32_t i = 1; i < word_count; i++) { @@ -141,13 +141,11 @@ static void recovery_done(void) { // New mnemonic is valid. if (!dry_run) { // Update mnemonic on storage. - storage.has_mnemonic = true; - strlcpy(storage.mnemonic, new_mnemonic, sizeof(new_mnemonic)); + storage_setMnemonic(new_mnemonic); memset(new_mnemonic, 0, sizeof(new_mnemonic)); if (!enforce_wordlist) { // not enforcing => mark storage as imported - storage.has_imported = true; - storage.imported = true; + storage_setImported(true); } storage_commit(); fsm_sendSuccess(_("Device recovered")); @@ -421,8 +419,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr return; } - storage.has_passphrase_protection = true; - storage.passphrase_protection = passphrase_protection; + storage_setPassphraseProtection(passphrase_protection); storage_setLanguage(language); storage_setLabel(label); storage_setU2FCounter(u2f_counter); diff --git a/firmware/reset.c b/firmware/reset.c index d4a1570d68..52934772aa 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -65,8 +65,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect return; } - storage.has_passphrase_protection = true; - storage.passphrase_protection = passphrase_protection; + storage_setPassphraseProtection(passphrase_protection); storage_setLanguage(language); storage_setLabel(label); storage_setU2FCounter(u2f_counter); @@ -88,14 +87,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); sha256_Final(&ctx, int_entropy); - strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic)); + storage_setNeedsBackup(true); + storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); memset(int_entropy, 0, 32); awaiting_entropy = false; - storage.has_mnemonic = true; - storage.has_needs_backup = true; - storage.needs_backup = true; - if (skip_backup) { storage_commit(); fsm_sendSuccess(_("Device successfully initialized")); @@ -116,27 +112,28 @@ void reset_backup(bool separated) return; } - storage.has_needs_backup = true; - storage.needs_backup = false; + storage_setNeedsBackup(false); if (separated) { storage_commit(); } + const char *mnemonic = storage_getMnemonic(); + for (int pass = 0; pass < 2; pass++) { int i = 0, word_pos = 1; - while (storage.mnemonic[i] != 0) { + while (mnemonic[i] != 0) { // copy current_word int j = 0; - while (storage.mnemonic[i] != ' ' && storage.mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { - current_word[j] = storage.mnemonic[i]; + while (mnemonic[i] != ' ' && mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { + current_word[j] = mnemonic[i]; i++; j++; } current_word[j] = 0; - if (storage.mnemonic[i] != 0) { + if (mnemonic[i] != 0) { i++; } - layoutResetWord(current_word, pass, word_pos, storage.mnemonic[i] == 0); + layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { storage_reset(); diff --git a/firmware/storage.c b/firmware/storage.c index c8f264d4a2..45d704638a 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -343,6 +343,11 @@ void storage_setPassphraseProtection(bool passphrase_protection) storage.passphrase_protection = passphrase_protection; } +bool storage_hasPassphraseProtection(void) +{ + return storage.has_passphrase_protection && storage.passphrase_protection; +} + void storage_setHomescreen(const uint8_t *data, uint32_t size) { if (data && size == 1024) { @@ -446,6 +451,32 @@ const uint8_t *storage_getHomescreen(void) return (storage.has_homescreen && storage.homescreen.size == 1024) ? storage.homescreen.bytes : 0; } +void storage_setMnemonic(const char *mnemonic) +{ + storage.has_mnemonic = true; + strlcpy(storage.mnemonic, mnemonic, sizeof(storage.mnemonic)); +} + +bool storage_hasNode(void) +{ + return storageRom->has_node; +} + +const HDNode *storage_getNode(void) +{ + return storageRom->has_node ? (const HDNode *)&storageRom->node : 0; +} + +bool storage_hasMnemonic(void) +{ + return storageRom->has_mnemonic; +} + +const char *storage_getMnemonic(void) +{ + return storage.has_mnemonic ? storage.mnemonic : 0; +} + /* Check whether mnemonic matches storage. The mnemonic must be * a null-terminated string. */ @@ -498,6 +529,11 @@ void storage_setPin(const char *pin) sessionPinCached = false; } +const char *storage_getPin(void) +{ + return storageRom->has_pin ? storageRom->pin : 0; +} + void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); @@ -599,11 +635,28 @@ bool storage_isInitialized(void) return storage.has_node || storage.has_mnemonic; } +bool storage_isImported(void) +{ + return storage.has_imported && storage.imported; +} + +void storage_setImported(bool imported) +{ + storage.has_imported = true; + storage.imported = imported; +} + bool storage_needsBackup(void) { return storage.has_needs_backup && storage.needs_backup; } +void storage_setNeedsBackup(bool needs_backup) +{ + storage.has_needs_backup = true; + storage.needs_backup = needs_backup; +} + void storage_applyFlags(uint32_t flags) { if ((storage.flags | flags) == storage.flags) { diff --git a/firmware/storage.h b/firmware/storage.h index 37235a0af3..e6e3a103af 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -44,6 +44,7 @@ const char *storage_getLanguage(void); void storage_setLanguage(const char *lang); void storage_setPassphraseProtection(bool passphrase_protection); +bool storage_hasPassphraseProtection(void); const uint8_t *storage_getHomescreen(void); void storage_setHomescreen(const uint8_t *data, uint32_t size); @@ -51,10 +52,17 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); +void storage_setMnemonic(const char *mnemonic); bool storage_containsMnemonic(const char *mnemonic); +bool storage_hasMnemonic(void); +const char *storage_getMnemonic(void); + +bool storage_hasNode(void); +const HDNode *storage_getNode(void); bool storage_containsPin(const char *pin); bool storage_hasPin(void); +const char *storage_getPin(void); void storage_setPin(const char *pin); void session_cachePin(void); bool session_isPinCached(void); @@ -68,15 +76,17 @@ void storage_setU2FCounter(uint32_t u2fcounter); bool storage_isInitialized(void); +bool storage_isImported(void); +void storage_setImported(bool imported); + bool storage_needsBackup(void); +void storage_setNeedsBackup(bool needs_backup); void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); void storage_wipe(void); -extern Storage storage; - extern char storage_uuid_str[25]; #endif From 70843c905934403c0358990f0707fcaa2610f6a2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Aug 2017 09:44:18 +0200 Subject: [PATCH 0667/1154] storage: introduce storageRam and storageRom --- firmware/storage.c | 156 +++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 45d704638a..98c65db937 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -42,11 +42,12 @@ #include "usb.h" #include "gettext.h" -Storage CONFIDENTIAL storage; - uint32_t storage_uuid[12/sizeof(uint32_t)]; char storage_uuid_str[25]; +Storage CONFIDENTIAL storageRam; +const Storage *storageRom = (const Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)); + /* storage layout: @@ -82,7 +83,7 @@ be added to the storage u2f_counter to get the real counter value. _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); _Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); -_Static_assert((sizeof(storage) & 3) == 0, "storage unaligned"); +_Static_assert((sizeof(storageRam) & 3) == 0, "storage unaligned"); /* Current u2f offset, i.e. u2f counter is * storage.u2f_counter + storage_u2f_offset. @@ -159,15 +160,15 @@ bool storage_from_flash(void) old_storage_size = 1504; } - memset(&storage, 0, sizeof(Storage)); - memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), old_storage_size); + memset(&storageRam, 0, sizeof(Storage)); + memcpy(&storageRam, storageRom, old_storage_size); if (version <= 5) { // convert PIN failure counter from version 5 format - uint32_t pinctr = storage.has_pin_failed_attempts - ? storage.pin_failed_attempts : 0; - if (pinctr > 31) + uint32_t pinctr = storageRom->has_pin_failed_attempts ? storageRom->pin_failed_attempts : 0; + if (pinctr > 31) { pinctr = 31; + } flash_clear_status_flags(); flash_unlock(); // erase extra storage sector @@ -175,12 +176,13 @@ bool storage_from_flash(void) flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); flash_lock(); storage_check_flash_errors(); - storage.has_pin_failed_attempts = false; - storage.pin_failed_attempts = 0; + storageRam.has_pin_failed_attempts = false; + storageRam.pin_failed_attempts = 0; } uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA; - while (*u2fptr == 0) + while (*u2fptr == 0) { u2fptr++; + } storage_u2f_offset = 32 * (u2fptr - (uint32_t*) FLASH_STORAGE_U2FAREA); uint32_t u2fword = *u2fptr; while ((u2fword & 1) == 0) { @@ -189,7 +191,7 @@ bool storage_from_flash(void) } // upgrade storage version if (version != STORAGE_VERSION) { - storage.version = STORAGE_VERSION; + storageRam.version = STORAGE_VERSION; storage_commit(); } return true; @@ -215,8 +217,8 @@ void storage_reset_uuid(void) void storage_reset(void) { // reset storage struct - memset(&storage, 0, sizeof(storage)); - storage.version = STORAGE_VERSION; + memset(&storageRam, 0, sizeof(storageRam)); + storageRam.version = STORAGE_VERSION; session_clear(true); // clear PIN as well } @@ -255,7 +257,7 @@ static void storage_commit_locked(void) flash_program_word(flash, storage_magic); flash += 4; flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid)/4); - flash = storage_flash_words(flash, (uint32_t *)&storage, sizeof(storage)/4); + flash = storage_flash_words(flash, (uint32_t *)&storageRam, sizeof(storageRam)/4); // fill remainder with zero for future extensions while (flash < FLASH_STORAGE_PINAREA) { flash_program_word(flash, 0); @@ -276,30 +278,30 @@ void storage_loadDevice(LoadDevice *msg) { storage_reset(); - storage.has_imported = true; - storage.imported = true; + storageRam.has_imported = true; + storageRam.imported = true; if (msg->has_pin > 0) { storage_setPin(msg->pin); } if (msg->has_passphrase_protection) { - storage.has_passphrase_protection = true; - storage.passphrase_protection = msg->passphrase_protection; + storageRam.has_passphrase_protection = true; + storageRam.passphrase_protection = msg->passphrase_protection; } else { - storage.has_passphrase_protection = false; + storageRam.has_passphrase_protection = false; } if (msg->has_node) { - storage.has_node = true; - storage.has_mnemonic = false; - memcpy(&storage.node, &(msg->node), sizeof(HDNodeType)); + storageRam.has_node = true; + storageRam.has_mnemonic = false; + memcpy(&storageRam.node, &(msg->node), sizeof(HDNodeType)); sessionSeedCached = false; memset(&sessionSeed, 0, sizeof(sessionSeed)); } else if (msg->has_mnemonic) { - storage.has_mnemonic = true; - storage.has_node = false; - strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic)); + storageRam.has_mnemonic = true; + storageRam.has_node = false; + strlcpy(storageRam.mnemonic, msg->mnemonic, sizeof(storageRam.mnemonic)); sessionSeedCached = false; memset(&sessionSeed, 0, sizeof(sessionSeed)); } @@ -320,8 +322,8 @@ void storage_loadDevice(LoadDevice *msg) void storage_setLabel(const char *label) { if (!label) return; - storage.has_label = true; - strlcpy(storage.label, label, sizeof(storage.label)); + storageRam.has_label = true; + strlcpy(storageRam.label, label, sizeof(storageRam.label)); } void storage_setLanguage(const char *lang) @@ -329,8 +331,8 @@ void storage_setLanguage(const char *lang) if (!lang) return; // sanity check if (strcmp(lang, "english") == 0) { - storage.has_language = true; - strlcpy(storage.language, lang, sizeof(storage.language)); + storageRam.has_language = true; + strlcpy(storageRam.language, lang, sizeof(storageRam.language)); } } @@ -339,25 +341,25 @@ void storage_setPassphraseProtection(bool passphrase_protection) sessionSeedCached = false; sessionPassphraseCached = false; - storage.has_passphrase_protection = true; - storage.passphrase_protection = passphrase_protection; + storageRam.has_passphrase_protection = true; + storageRam.passphrase_protection = passphrase_protection; } bool storage_hasPassphraseProtection(void) { - return storage.has_passphrase_protection && storage.passphrase_protection; + return storageRom->has_passphrase_protection && storageRom->passphrase_protection; } void storage_setHomescreen(const uint8_t *data, uint32_t size) { if (data && size == 1024) { - storage.has_homescreen = true; - memcpy(storage.homescreen.bytes, data, size); - storage.homescreen.size = size; + storageRam.has_homescreen = true; + memcpy(storageRam.homescreen.bytes, data, size); + storageRam.homescreen.size = size; } else { - storage.has_homescreen = false; - memset(storage.homescreen.bytes, 0, sizeof(storage.homescreen.bytes)); - storage.homescreen.size = 0; + storageRam.has_homescreen = false; + memset(storageRam.homescreen.bytes, 0, sizeof(storageRam.homescreen.bytes)); + storageRam.homescreen.size = 0; } } @@ -376,20 +378,20 @@ const uint8_t *storage_getSeed(bool usePassphrase) } // if storage has mnemonic, convert it to node and use it - if (storage.has_mnemonic) { + if (storageRom->has_mnemonic) { if (usePassphrase && !protectPassphrase()) { return NULL; } // if storage was not imported (i.e. it was properly generated or recovered) - if (!storage.has_imported || !storage.imported) { + if (!storageRom->has_imported || !storageRom->imported) { // test whether mnemonic is a valid BIP-0039 mnemonic - if (!mnemonic_check(storage.mnemonic)) { + if (!mnemonic_check(storageRom->mnemonic)) { // and if not then halt the device storage_show_error(); } } char oldTiny = usbTiny(1); - mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 + mnemonic_to_seed(storageRom->mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 usbTiny(oldTiny); sessionSeedCached = true; sessionSeedUsesPassphrase = usePassphrase; @@ -402,14 +404,14 @@ const uint8_t *storage_getSeed(bool usePassphrase) bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) { // if storage has node, decrypt and use it - if (storage.has_node && strcmp(curve, SECP256K1_NAME) == 0) { + if (storageRom->has_node && strcmp(curve, SECP256K1_NAME) == 0) { if (!protectPassphrase()) { return false; } - if (hdnode_from_xprv(storage.node.depth, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) { + if (hdnode_from_xprv(storageRom->node.depth, storageRom->node.child_num, storageRom->node.chain_code.bytes, storageRom->node.private_key.bytes, curve, node) == 0) { return false; } - if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { + if (storageRom->has_passphrase_protection && storageRom->passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; @@ -438,23 +440,23 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) const char *storage_getLabel(void) { - return storage.has_label ? storage.label : 0; + return storageRom->has_label ? storageRom->label : 0; } const char *storage_getLanguage(void) { - return storage.has_language ? storage.language : 0; + return storageRom->has_language ? storageRom->language : 0; } const uint8_t *storage_getHomescreen(void) { - return (storage.has_homescreen && storage.homescreen.size == 1024) ? storage.homescreen.bytes : 0; + return (storageRom->has_homescreen && storageRom->homescreen.size == 1024) ? storageRom->homescreen.bytes : 0; } void storage_setMnemonic(const char *mnemonic) { - storage.has_mnemonic = true; - strlcpy(storage.mnemonic, mnemonic, sizeof(storage.mnemonic)); + storageRam.has_mnemonic = true; + strlcpy(storageRam.mnemonic, mnemonic, sizeof(storageRam.mnemonic)); } bool storage_hasNode(void) @@ -474,7 +476,7 @@ bool storage_hasMnemonic(void) const char *storage_getMnemonic(void) { - return storage.has_mnemonic ? storage.mnemonic : 0; + return storageRom->has_mnemonic ? storageRom->mnemonic : 0; } /* Check whether mnemonic matches storage. The mnemonic must be @@ -487,9 +489,9 @@ bool storage_containsMnemonic(const char *mnemonic) { char diff = 0; uint32_t i = 0; for (; mnemonic[i]; i++) { - diff |= (storage.mnemonic[i] - mnemonic[i]); + diff |= (storageRom->mnemonic[i] - mnemonic[i]); } - diff |= storage.mnemonic[i]; + diff |= storageRom->mnemonic[i]; return diff == 0; } @@ -504,26 +506,26 @@ bool storage_containsPin(const char *pin) char diff = 0; uint32_t i = 0; while (pin[i]) { - diff |= storage.pin[i] - pin[i]; + diff |= storageRom->pin[i] - pin[i]; i++; } - diff |= storage.pin[i]; + diff |= storageRom->pin[i]; return diff == 0; } bool storage_hasPin(void) { - return storage.has_pin && storage.pin[0] != 0; + return storageRom->has_pin && storageRom->pin[0] != 0; } void storage_setPin(const char *pin) { if (pin && pin[0]) { - storage.has_pin = true; - strlcpy(storage.pin, pin, sizeof(storage.pin)); + storageRam.has_pin = true; + strlcpy(storageRam.pin, pin, sizeof(storageRam.pin)); } else { - storage.has_pin = false; - storage.pin[0] = 0; + storageRam.has_pin = false; + storageRam.pin[0] = 0; } storage_commit(); sessionPinCached = false; @@ -583,8 +585,8 @@ static void storage_area_recycle(uint32_t new_pinfails) } if (storage_u2f_offset > 0) { - storage.has_u2f_counter = true; - storage.u2f_counter += storage_u2f_offset; + storageRam.has_u2f_counter = true; + storageRam.u2f_counter += storage_u2f_offset; storage_u2f_offset = 0; } storage_commit_locked(); @@ -632,44 +634,44 @@ uint32_t *storage_getPinFailsPtr(void) bool storage_isInitialized(void) { - return storage.has_node || storage.has_mnemonic; + return storageRom->has_node || storageRom->has_mnemonic; } bool storage_isImported(void) { - return storage.has_imported && storage.imported; + return storageRom->has_imported && storageRom->imported; } void storage_setImported(bool imported) { - storage.has_imported = true; - storage.imported = imported; + storageRam.has_imported = true; + storageRam.imported = imported; } bool storage_needsBackup(void) { - return storage.has_needs_backup && storage.needs_backup; + return storageRom->has_needs_backup && storageRom->needs_backup; } void storage_setNeedsBackup(bool needs_backup) { - storage.has_needs_backup = true; - storage.needs_backup = needs_backup; + storageRam.has_needs_backup = true; + storageRam.needs_backup = needs_backup; } void storage_applyFlags(uint32_t flags) { - if ((storage.flags | flags) == storage.flags) { + if ((storageRom->flags | flags) == storageRom->flags) { return; // no new flags } - storage.has_flags = true; - storage.flags |= flags; + storageRam.has_flags = true; + storageRam.flags |= flags; storage_commit(); } uint32_t storage_getFlags(void) { - return storage.has_flags ? storage.flags : 0; + return storageRom->has_flags ? storageRom->flags : 0; } uint32_t storage_nextU2FCounter(void) @@ -686,13 +688,13 @@ uint32_t storage_nextU2FCounter(void) } flash_lock(); storage_check_flash_errors(); - return storage.u2f_counter + storage_u2f_offset; + return storageRom->u2f_counter + storage_u2f_offset; } void storage_setU2FCounter(uint32_t u2fcounter) { - storage.has_u2f_counter = true; - storage.u2f_counter = u2fcounter - storage_u2f_offset; + storageRam.has_u2f_counter = true; + storageRam.u2f_counter = u2fcounter - storage_u2f_offset; storage_commit(); } From f22c849767f40711bba0dc0ffc2bca67401fbed8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 Aug 2017 19:00:25 +0200 Subject: [PATCH 0668/1154] storage: rework storage_commit into storage_update --- firmware/fsm.c | 5 +- firmware/protect.c | 1 + firmware/recovery.c | 9 +- firmware/reset.c | 10 +- firmware/storage.c | 294 +++++++++++++++++++++++++++----------------- firmware/storage.h | 8 +- firmware/trezor.c | 5 +- 7 files changed, 201 insertions(+), 131 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b8b183f1f9..6d903654af 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -330,6 +330,7 @@ void fsm_msgChangePin(ChangePin *msg) if (removal) { storage_setPin(0); + storage_update(); fsm_sendSuccess(_("PIN removed")); } else { if (protectChangePin()) { @@ -457,7 +458,6 @@ void fsm_msgLoadDevice(LoadDevice *msg) } storage_loadDevice(msg); - storage_commit(); fsm_sendSuccess(_("Device loaded")); layoutHome(); } @@ -647,7 +647,7 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_homescreen) { storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } - storage_commit(); + storage_update(); fsm_sendSuccess(_("Settings applied")); layoutHome(); } @@ -1199,6 +1199,7 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg) return; } storage_setU2FCounter(msg->u2f_counter); + storage_update(); fsm_sendSuccess(_("U2F counter set")); layoutHome(); } diff --git a/firmware/protect.c b/firmware/protect.c index 74f5468363..852e0d8b22 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -228,6 +228,7 @@ bool protectChangePin(void) if (result) { storage_setPin(pin_compare); + storage_update(); } memset(pin_compare, 0, sizeof(pin_compare)); diff --git a/firmware/recovery.c b/firmware/recovery.c index 9d3c955488..ed09deeacc 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -147,7 +147,7 @@ static void recovery_done(void) { // not enforcing => mark storage as imported storage_setImported(true); } - storage_commit(); + storage_update(); fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). @@ -174,7 +174,7 @@ static void recovery_done(void) { // New mnemonic is invalid. memset(new_mnemonic, 0, sizeof(new_mnemonic)); if (!dry_run) { - storage_reset(); + session_clear(true); } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); @@ -423,6 +423,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_setLanguage(language); storage_setLabel(label); storage_setU2FCounter(u2f_counter); + storage_update(); } if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { @@ -448,7 +449,7 @@ static void recovery_scrambledword(const char *word) if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) { if (!dry_run) { - storage_reset(); + session_clear(true); } fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); layoutHome(); @@ -467,7 +468,7 @@ static void recovery_scrambledword(const char *word) } if (!found) { if (!dry_run) { - storage_reset(); + session_clear(true); } fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); layoutHome(); diff --git a/firmware/reset.c b/firmware/reset.c index 52934772aa..797837818f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -69,6 +69,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect storage_setLanguage(language); storage_setLabel(label); storage_setU2FCounter(u2f_counter); + storage_update(); EntropyRequest resp; memset(&resp, 0, sizeof(EntropyRequest)); @@ -93,7 +94,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) awaiting_entropy = false; if (skip_backup) { - storage_commit(); + storage_update(); fsm_sendSuccess(_("Device successfully initialized")); layoutHome(); } else { @@ -115,7 +116,7 @@ void reset_backup(bool separated) storage_setNeedsBackup(false); if (separated) { - storage_commit(); + storage_update(); } const char *mnemonic = storage_getMnemonic(); @@ -136,7 +137,8 @@ void reset_backup(bool separated) layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { - storage_reset(); + storage_clear_update(); + session_clear(true); } layoutHome(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); @@ -149,7 +151,7 @@ void reset_backup(bool separated) if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { - storage_commit(); + storage_update(); fsm_sendSuccess(_("Device successfully initialized")); } layoutHome(); diff --git a/firmware/storage.c b/firmware/storage.c index 98c65db937..929eb6e813 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -42,11 +42,20 @@ #include "usb.h" #include "gettext.h" -uint32_t storage_uuid[12/sizeof(uint32_t)]; -char storage_uuid_str[25]; +/* magic constant to check validity of storage block */ +static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t -Storage CONFIDENTIAL storageRam; -const Storage *storageRom = (const Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)); +static uint32_t storage_uuid[12 / sizeof(uint32_t)]; +_Static_assert(((uint32_t)storage_uuid & 3) == 0, "uuid unaligned"); +_Static_assert((sizeof(storage_uuid) & 3) == 0, "uuid unaligned"); + +Storage CONFIDENTIAL storageUpdate; +_Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); +_Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); + +const Storage *storageRom = (const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid)); + +char storage_uuid_str[25]; /* storage layout: @@ -79,11 +88,9 @@ be added to the storage u2f_counter to get the real counter value. #define FLASH_STORAGE_PINAREA_LEN (0x1000) #define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) #define FLASH_STORAGE_U2FAREA_LEN (0x100) -#define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage)) +#define FLASH_STORAGE_REALLEN (sizeof(storage_magic) + sizeof(storage_uuid) + sizeof(Storage)) _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); -_Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned"); -_Static_assert((sizeof(storageRam) & 3) == 0, "storage unaligned"); /* Current u2f offset, i.e. u2f counter is * storage.u2f_counter + storage_u2f_offset. @@ -91,9 +98,6 @@ _Static_assert((sizeof(storageRam) & 3) == 0, "storage unaligned"); */ static uint32_t storage_u2f_offset; -/* magic constant to check validity of storage block */ -static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t - static bool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t CONFIDENTIAL sessionSeed[64]; @@ -121,12 +125,12 @@ void storage_check_flash_errors(void) bool storage_from_flash(void) { - if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, 4) != 0) { + if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, sizeof(storage_magic)) != 0) { // wrong magic return false; } - uint32_t version = ((Storage *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)))->version; + const uint32_t version = storageRom->version; // version 1: since 1.0.0 // version 2: since 1.2.1 // version 3: since 1.3.1 @@ -141,7 +145,7 @@ bool storage_from_flash(void) } // load uuid - memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + 4), sizeof(storage_uuid)); + memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); // copy storage @@ -160,8 +164,16 @@ bool storage_from_flash(void) old_storage_size = 1504; } - memset(&storageRam, 0, sizeof(Storage)); - memcpy(&storageRam, storageRom, old_storage_size); + // erase newly added fields + if (old_storage_size != sizeof(Storage)) { + flash_clear_status_flags(); + flash_unlock(); + for (uint32_t offset = old_storage_size; offset < sizeof(Storage); offset += sizeof(uint32_t)) { + flash_program_word(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid) + offset, 0); + } + flash_lock(); + storage_check_flash_errors(); + } if (version <= 5) { // convert PIN failure counter from version 5 format @@ -174,10 +186,13 @@ bool storage_from_flash(void) // erase extra storage sector flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); + // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts + _Static_assert(((uint32_t)&storageRom->has_pin_failed_attempts & 3) == 0, "storage.has_pin_failed_attempts unaligned"); + _Static_assert(((uint32_t)&storageRom->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); + flash_program_word((uint32_t)&storageRom->has_pin_failed_attempts, 0); + flash_program_word((uint32_t)&storageRom->pin_failed_attempts, 0); flash_lock(); storage_check_flash_errors(); - storageRam.has_pin_failed_attempts = false; - storageRam.pin_failed_attempts = 0; } uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA; while (*u2fptr == 0) { @@ -189,39 +204,25 @@ bool storage_from_flash(void) storage_u2f_offset++; u2fword >>= 1; } - // upgrade storage version - if (version != STORAGE_VERSION) { - storageRam.version = STORAGE_VERSION; - storage_commit(); - } + // note: we don't update storage version on flash at this point, + // but it is already upgraded when it comes to content return true; } void storage_init(void) { if (!storage_from_flash()) { - storage_reset(); - storage_reset_uuid(); - storage_commit(); - storage_clearPinArea(); + storage_wipe(); } } -void storage_reset_uuid(void) +void storage_generate_uuid(void) { // set random uuid random_buffer((uint8_t *)storage_uuid, sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); } -void storage_reset(void) -{ - // reset storage struct - memset(&storageRam, 0, sizeof(storageRam)); - storageRam.version = STORAGE_VERSION; - session_clear(true); // clear PIN as well -} - void session_clear(bool clear_pin) { sessionSeedCached = false; @@ -233,97 +234,163 @@ void session_clear(bool clear_pin) } } -static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) { +static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwords) { for (int i = 0; i < nwords; i++) { flash_program_word(addr, *src++); - addr += 4; + addr += sizeof(uint32_t); } return addr; } -static void storage_commit_locked(void) +// if storage is filled in - update fields that has has_field set to true +// if storage is NULL - do not backup original content - essentialy a wipe +static void storage_commit_locked(bool update) { - uint32_t meta_backup[FLASH_META_DESC_LEN/4]; + if (update) { + if (storageUpdate.has_passphrase_protection) { + sessionSeedCached = false; + sessionPassphraseCached = false; + } + if (storageUpdate.has_pin) { + sessionPinCached = false; + } + + storageUpdate.version = STORAGE_VERSION; + if (!storageUpdate.has_node && !storageUpdate.has_mnemonic) { + storageUpdate.has_node = storageRom->has_node; + memcpy(&storageUpdate.node, &storageRom->node, sizeof(HDNodeType)); + storageUpdate.has_mnemonic = storageRom->has_mnemonic; + strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); + } + if (!storageUpdate.has_passphrase_protection) { + storageUpdate.has_passphrase_protection = storageRom->has_passphrase_protection; + storageUpdate.passphrase_protection = storageRom->passphrase_protection; + } + if (!storageUpdate.has_pin) { + storageUpdate.has_pin = storageRom->has_pin; + strlcpy(storageUpdate.pin, storageRom->pin, sizeof(storageUpdate.pin)); + } else if (!storageUpdate.pin[0]) { + storageUpdate.has_pin = false; + } + if (!storageUpdate.has_language) { + storageUpdate.has_language = storageRom->has_language; + strlcpy(storageUpdate.language, storageRom->language, sizeof(storageUpdate.language)); + } + if (!storageUpdate.has_label) { + storageUpdate.has_label = storageRom->has_label; + strlcpy(storageUpdate.label, storageRom->label, sizeof(storageUpdate.label)); + } else if (!storageUpdate.label[0]) { + storageUpdate.has_label = false; + } + if (!storageUpdate.has_imported) { + storageUpdate.has_imported = storageRom->has_imported; + storageUpdate.imported = storageRom->imported; + } + if (!storageUpdate.has_homescreen) { + storageUpdate.has_homescreen = storageRom->has_homescreen; + memcpy(&storageUpdate.homescreen, &storageRom->homescreen, sizeof(storageUpdate.homescreen)); + } else if (storageUpdate.homescreen.size == 0) { + storageUpdate.has_homescreen = false; + } + if (!storageUpdate.has_u2f_counter) { + storageUpdate.has_u2f_counter = storageRom->has_u2f_counter; + storageUpdate.u2f_counter = storageRom->u2f_counter; + } + if (!storageUpdate.has_needs_backup) { + storageUpdate.has_needs_backup = storageRom->has_needs_backup; + storageUpdate.needs_backup = storageRom->needs_backup; + } + if (!storageUpdate.has_flags) { + storageUpdate.has_flags = storageRom->has_flags; + storageUpdate.flags = storageRom->flags; + } + } // backup meta + uint32_t meta_backup[FLASH_META_DESC_LEN / sizeof(uint32_t)]; memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); // erase storage flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); - // copy meta + + // copy meta back uint32_t flash = FLASH_META_START; - flash = storage_flash_words(flash, meta_backup, FLASH_META_DESC_LEN/4); + flash = storage_flash_words(flash, meta_backup, FLASH_META_DESC_LEN / sizeof(uint32_t)); + // copy storage - flash_program_word(flash, storage_magic); - flash += 4; - flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid)/4); - flash = storage_flash_words(flash, (uint32_t *)&storageRam, sizeof(storageRam)/4); + flash = storage_flash_words(flash, &storage_magic, sizeof(storage_magic) / sizeof(uint32_t)); + flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid) / sizeof(uint32_t)); + + if (update) { + flash = storage_flash_words(flash, (const uint32_t *)&storageUpdate, sizeof(storageUpdate) / sizeof(uint32_t)); + } + storage_clear_update(); + // fill remainder with zero for future extensions while (flash < FLASH_STORAGE_PINAREA) { flash_program_word(flash, 0); - flash += 4; + flash += sizeof(uint32_t); } } -void storage_commit(void) +void storage_clear_update(void) +{ + memset(&storageUpdate, 0, sizeof(storageUpdate)); +} + +void storage_update(void) { flash_clear_status_flags(); flash_unlock(); - storage_commit_locked(); + storage_commit_locked(true); flash_lock(); storage_check_flash_errors(); } void storage_loadDevice(LoadDevice *msg) { - storage_reset(); + session_clear(true); - storageRam.has_imported = true; - storageRam.imported = true; + storageUpdate.has_imported = true; + storageUpdate.imported = true; - if (msg->has_pin > 0) { - storage_setPin(msg->pin); - } - - if (msg->has_passphrase_protection) { - storageRam.has_passphrase_protection = true; - storageRam.passphrase_protection = msg->passphrase_protection; - } else { - storageRam.has_passphrase_protection = false; - } + storage_setPin(msg->has_pin ? msg->pin : ""); + storage_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); if (msg->has_node) { - storageRam.has_node = true; - storageRam.has_mnemonic = false; - memcpy(&storageRam.node, &(msg->node), sizeof(HDNodeType)); + storageUpdate.has_node = true; + storageUpdate.has_mnemonic = false; + memcpy(&storageUpdate.node, &(msg->node), sizeof(HDNodeType)); sessionSeedCached = false; memset(&sessionSeed, 0, sizeof(sessionSeed)); } else if (msg->has_mnemonic) { - storageRam.has_mnemonic = true; - storageRam.has_node = false; - strlcpy(storageRam.mnemonic, msg->mnemonic, sizeof(storageRam.mnemonic)); + storageUpdate.has_mnemonic = true; + storageUpdate.has_node = false; + strlcpy(storageUpdate.mnemonic, msg->mnemonic, sizeof(storageUpdate.mnemonic)); sessionSeedCached = false; memset(&sessionSeed, 0, sizeof(sessionSeed)); } - if (msg->has_language) { - storage_setLanguage(msg->language); + if (msg->has_language && msg->language) { + storageUpdate.has_language = true; + strlcpy(storageUpdate.language, msg->language, sizeof(storageUpdate.language)); } - if (msg->has_label) { - storage_setLabel(msg->label); - } + storage_setLabel(msg->has_label ? msg->label : ""); if (msg->has_u2f_counter) { - storage_setU2FCounter(msg->u2f_counter); + storageUpdate.has_u2f_counter = true; + storageUpdate.u2f_counter = msg->u2f_counter - storage_u2f_offset; } + + storage_update(); } void storage_setLabel(const char *label) { + storageUpdate.has_label = true; if (!label) return; - storageRam.has_label = true; - strlcpy(storageRam.label, label, sizeof(storageRam.label)); + strlcpy(storageUpdate.label, label, sizeof(storageUpdate.label)); } void storage_setLanguage(const char *lang) @@ -331,8 +398,8 @@ void storage_setLanguage(const char *lang) if (!lang) return; // sanity check if (strcmp(lang, "english") == 0) { - storageRam.has_language = true; - strlcpy(storageRam.language, lang, sizeof(storageRam.language)); + storageUpdate.has_language = true; + strlcpy(storageUpdate.language, lang, sizeof(storageUpdate.language)); } } @@ -341,8 +408,8 @@ void storage_setPassphraseProtection(bool passphrase_protection) sessionSeedCached = false; sessionPassphraseCached = false; - storageRam.has_passphrase_protection = true; - storageRam.passphrase_protection = passphrase_protection; + storageUpdate.has_passphrase_protection = true; + storageUpdate.passphrase_protection = passphrase_protection; } bool storage_hasPassphraseProtection(void) @@ -352,18 +419,17 @@ bool storage_hasPassphraseProtection(void) void storage_setHomescreen(const uint8_t *data, uint32_t size) { + storageUpdate.has_homescreen = true; if (data && size == 1024) { - storageRam.has_homescreen = true; - memcpy(storageRam.homescreen.bytes, data, size); - storageRam.homescreen.size = size; + memcpy(storageUpdate.homescreen.bytes, data, size); + storageUpdate.homescreen.size = size; } else { - storageRam.has_homescreen = false; - memset(storageRam.homescreen.bytes, 0, sizeof(storageRam.homescreen.bytes)); - storageRam.homescreen.size = 0; + memset(storageUpdate.homescreen.bytes, 0, sizeof(storageUpdate.homescreen.bytes)); + storageUpdate.homescreen.size = 0; } } -void get_root_node_callback(uint32_t iter, uint32_t total) +static void get_root_node_callback(uint32_t iter, uint32_t total) { usbSleep(1); layoutProgress(_("Waking up"), 1000 * iter / total); @@ -455,8 +521,8 @@ const uint8_t *storage_getHomescreen(void) void storage_setMnemonic(const char *mnemonic) { - storageRam.has_mnemonic = true; - strlcpy(storageRam.mnemonic, mnemonic, sizeof(storageRam.mnemonic)); + storageUpdate.has_mnemonic = true; + strlcpy(storageUpdate.mnemonic, mnemonic, sizeof(storageUpdate.mnemonic)); } bool storage_hasNode(void) @@ -476,7 +542,8 @@ bool storage_hasMnemonic(void) const char *storage_getMnemonic(void) { - return storageRom->has_mnemonic ? storageRom->mnemonic : 0; + return storageUpdate.has_mnemonic ? storageUpdate.mnemonic + : storageRom->has_mnemonic ? storageRom->mnemonic : 0; } /* Check whether mnemonic matches storage. The mnemonic must be @@ -520,14 +587,8 @@ bool storage_hasPin(void) void storage_setPin(const char *pin) { - if (pin && pin[0]) { - storageRam.has_pin = true; - strlcpy(storageRam.pin, pin, sizeof(storageRam.pin)); - } else { - storageRam.has_pin = false; - storageRam.pin[0] = 0; - } - storage_commit(); + storageUpdate.has_pin = true; + strlcpy(storageUpdate.pin, pin, sizeof(storageUpdate.pin)); sessionPinCached = false; } @@ -585,11 +646,11 @@ static void storage_area_recycle(uint32_t new_pinfails) } if (storage_u2f_offset > 0) { - storageRam.has_u2f_counter = true; - storageRam.u2f_counter += storage_u2f_offset; + storageUpdate.has_u2f_counter = true; + storageUpdate.u2f_counter += storage_u2f_offset; storage_u2f_offset = 0; + storage_commit_locked(true); } - storage_commit_locked(); } void storage_resetPinFails(uint32_t *pinfailsptr) @@ -644,19 +705,20 @@ bool storage_isImported(void) void storage_setImported(bool imported) { - storageRam.has_imported = true; - storageRam.imported = imported; + storageUpdate.has_imported = true; + storageUpdate.imported = imported; } bool storage_needsBackup(void) { - return storageRom->has_needs_backup && storageRom->needs_backup; + return storageUpdate.has_needs_backup ? storageUpdate.needs_backup + : storageRom->has_needs_backup && storageRom->needs_backup; } void storage_setNeedsBackup(bool needs_backup) { - storageRam.has_needs_backup = true; - storageRam.needs_backup = needs_backup; + storageUpdate.has_needs_backup = true; + storageUpdate.needs_backup = needs_backup; } void storage_applyFlags(uint32_t flags) @@ -664,9 +726,8 @@ void storage_applyFlags(uint32_t flags) if ((storageRom->flags | flags) == storageRom->flags) { return; // no new flags } - storageRam.has_flags = true; - storageRam.flags |= flags; - storage_commit(); + storageUpdate.has_flags = true; + storageUpdate.flags |= flags; } uint32_t storage_getFlags(void) @@ -693,15 +754,20 @@ uint32_t storage_nextU2FCounter(void) void storage_setU2FCounter(uint32_t u2fcounter) { - storageRam.has_u2f_counter = true; - storageRam.u2f_counter = u2fcounter - storage_u2f_offset; - storage_commit(); + storageUpdate.has_u2f_counter = true; + storageUpdate.u2f_counter = u2fcounter - storage_u2f_offset; } void storage_wipe(void) { - storage_reset(); - storage_reset_uuid(); - storage_commit(); + session_clear(true); + storage_generate_uuid(); + + flash_clear_status_flags(); + flash_unlock(); + storage_commit_locked(false); + flash_lock(); + storage_check_flash_errors(); + storage_clearPinArea(); } diff --git a/firmware/storage.h b/firmware/storage.h index e6e3a103af..7c0eb01ebd 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -25,10 +25,12 @@ #include "messages.pb.h" #include "bip32.h" +extern Storage storageUpdate; + void storage_init(void); -void storage_reset_uuid(void); -void storage_reset(void); -void storage_commit(void); +void storage_generate_uuid(void); +void storage_clear_update(void); +void storage_update(void); void session_clear(bool clear_pin); void storage_loadDevice(LoadDevice *msg); diff --git a/firmware/trezor.c b/firmware/trezor.c index 9c0dac40ea..861d7aff97 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -103,10 +103,7 @@ int main(void) #if DEBUG_LINK oledSetDebugLink(1); - storage_reset(); // wipe storage if debug link - storage_reset_uuid(); - storage_commit(); - storage_clearPinArea(); // reset PIN failures if debug link + storage_wipe(); #endif oledDrawBitmap(40, 0, &bmp_logo64); From 88563ebaa5421a3717cf3f3158e2319f3403bf16 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 12 Dec 2017 19:36:34 +0100 Subject: [PATCH 0669/1154] Fix compile problem, fix clearing single byte --- firmware/storage.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 929eb6e813..8abff13b1f 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -53,7 +53,8 @@ Storage CONFIDENTIAL storageUpdate; _Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); _Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); -const Storage *storageRom = (const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid)); +#define STORAGE_ROM ((const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid))) +const Storage *storageRom = STORAGE_ROM; char storage_uuid_str[25]; @@ -187,9 +188,8 @@ bool storage_from_flash(void) flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts - _Static_assert(((uint32_t)&storageRom->has_pin_failed_attempts & 3) == 0, "storage.has_pin_failed_attempts unaligned"); - _Static_assert(((uint32_t)&storageRom->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); - flash_program_word((uint32_t)&storageRom->has_pin_failed_attempts, 0); + _Static_assert(((uint32_t)&STORAGE_ROM->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); + flash_program_byte((uint32_t)&storageRom->has_pin_failed_attempts, 0); flash_program_word((uint32_t)&storageRom->pin_failed_attempts, 0); flash_lock(); storage_check_flash_errors(); From 73edc7cb74b663037ae0507789fe67ef414308b0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 13 Dec 2017 10:53:27 +0100 Subject: [PATCH 0670/1154] Added U2F root key to storage. Fixes #251. --- firmware/storage.c | 57 +++++++++++++++++++++++++++++++++++++++++++--- firmware/storage.h | 1 + firmware/u2f.c | 16 +++++-------- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 8abff13b1f..248e19bb10 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -41,6 +41,7 @@ #include "layout2.h" #include "usb.h" #include "gettext.h" +#include "u2f.h" /* magic constant to check validity of storage block */ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t @@ -108,7 +109,7 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char CONFIDENTIAL sessionPassphrase[51]; -#define STORAGE_VERSION 8 +#define STORAGE_VERSION 9 void storage_show_error(void) { @@ -126,6 +127,7 @@ void storage_check_flash_errors(void) bool storage_from_flash(void) { + storage_clear_update(); if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, sizeof(storage_magic)) != 0) { // wrong magic return false; @@ -140,6 +142,7 @@ bool storage_from_flash(void) // version 6: since 1.3.6 // version 7: since 1.5.1 // version 8: since 1.5.2 + // version 9: since 1.6.1 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; @@ -156,13 +159,20 @@ bool storage_from_flash(void) old_storage_size = 460; } else if (version == 3 || version == 4 || version == 5) { + // added homescreen old_storage_size = 1488; } else if (version == 6 || version == 7) { + // added u2fcounter old_storage_size = 1496; } else if (version == 8) { + // added flags and needsBackup old_storage_size = 1504; + } else + if (version == 9) { + // added u2froot + old_storage_size = 1704; } // erase newly added fields @@ -204,8 +214,15 @@ bool storage_from_flash(void) storage_u2f_offset++; u2fword >>= 1; } - // note: we don't update storage version on flash at this point, - // but it is already upgraded when it comes to content + // force recomputing u2f root for storage version < 9. + if (version < 9) { + storageUpdate.has_mnemonic = storageRom->has_mnemonic; + strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); + } + // update storage version on flash + if (version != STORAGE_VERSION) { + storage_update(); + } return true; } @@ -242,6 +259,29 @@ static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwor return addr; } +static void get_u2froot_callback(uint32_t iter, uint32_t total) +{ + layoutProgress(_("Updating"), 1000 * iter / total); +} + +static void storage_compute_u2froot(const char* mnemonic, HDNodeType *u2froot) { + static CONFIDENTIAL HDNode node; + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 + usbTiny(oldTiny); + hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); + hdnode_private_ckd(&node, U2F_KEY_PATH); + u2froot->depth = node.depth; + u2froot->child_num = U2F_KEY_PATH; + u2froot->chain_code.size = sizeof(node.chain_code); + memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); + u2froot->has_private_key = true; + u2froot->private_key.size = sizeof(node.private_key); + memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); + memset(&node, 0, sizeof(node)); + session_clear(false); // invalidate seed cache +} + // if storage is filled in - update fields that has has_field set to true // if storage is NULL - do not backup original content - essentialy a wipe static void storage_commit_locked(bool update) @@ -261,6 +301,11 @@ static void storage_commit_locked(bool update) memcpy(&storageUpdate.node, &storageRom->node, sizeof(HDNodeType)); storageUpdate.has_mnemonic = storageRom->has_mnemonic; strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); + storageUpdate.has_u2froot = storageRom->has_u2froot; + memcpy(&storageUpdate.u2froot, &storageRom->u2froot, sizeof(HDNodeType)); + } else if (storageUpdate.has_mnemonic) { + storageUpdate.has_u2froot = true; + storage_compute_u2froot(storageUpdate.mnemonic, &storageUpdate.u2froot); } if (!storageUpdate.has_passphrase_protection) { storageUpdate.has_passphrase_protection = storageRom->has_passphrase_protection; @@ -467,6 +512,12 @@ const uint8_t *storage_getSeed(bool usePassphrase) return NULL; } +bool storage_getU2FRoot(HDNode *node) +{ + return storageRom->has_u2froot + && hdnode_from_xprv(storageRom->u2froot.depth, storageRom->u2froot.child_num, storageRom->u2froot.chain_code.bytes, storageRom->u2froot.private_key.bytes, NIST256P1_NAME, node); +} + bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) { // if storage has node, decrypt and use it diff --git a/firmware/storage.h b/firmware/storage.h index 7c0eb01ebd..9d7935258f 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -37,6 +37,7 @@ void storage_loadDevice(LoadDevice *msg); const uint8_t *storage_getSeed(bool usePassphrase); +bool storage_getU2FRoot(HDNode *node); bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase); const char *storage_getLabel(void); diff --git a/firmware/u2f.c b/firmware/u2f.c index 2c084da40b..5e6a06af53 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -59,7 +59,7 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; #define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH) // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' -#define KEY_PATH_ENTRIES (1 + KEY_PATH_LEN / sizeof(uint32_t)) +#define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t)) // Defined as UsbSignHandler.BOGUS_APP_ID_HASH // in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 @@ -450,7 +450,7 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; - if (!storage_getRootNode(&node, NIST256P1_NAME, false)) { + if (!storage_getU2FRoot(&node)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); return 0; @@ -472,14 +472,13 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handl // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' uint32_t key_path[KEY_PATH_ENTRIES]; - key_path[0] = U2F_KEY_PATH; - for (uint32_t i = 1; i < KEY_PATH_ENTRIES; i++) { + for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) { // high bit for hardened keys key_path[i]= 0x80000000 | random32(); } // First half of keyhandle is key_path - memcpy(key_handle, &key_path[1], KEY_PATH_LEN); + memcpy(key_handle, key_path, KEY_PATH_LEN); // prepare keypair from /random data const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); @@ -501,9 +500,8 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handl static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) { uint32_t key_path[KEY_PATH_ENTRIES]; - key_path[0] = U2F_KEY_PATH; - memcpy(&key_path[1], key_handle, KEY_PATH_LEN); - for (unsigned int i = 1; i < KEY_PATH_ENTRIES; i++) { + memcpy(key_path, key_handle, KEY_PATH_LEN); + for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { // check high bit for hardened keys if (! (key_path[i] & 0x80000000)) { return NULL; @@ -557,8 +555,6 @@ void u2f_register(const APDU *a) // First Time request, return not present and display request dialog if (last_req_state == INIT) { - // wake up crypto system to be ready for signing - getDerivedNode(NULL, 0); // error: testof-user-presence is required buttonUpdate(); // Clear button state if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { From 106642bd44e08121559b6b145d737ba6b368ac82 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 13 Dec 2017 17:56:46 +0100 Subject: [PATCH 0671/1154] fix last commit --- firmware/storage.c | 1 + vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 248e19bb10..436d4460e2 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -215,6 +215,7 @@ bool storage_from_flash(void) u2fword >>= 1; } // force recomputing u2f root for storage version < 9. + // this is done by re-setting the mnemonic, which triggers the computation if (version < 9) { storageUpdate.has_mnemonic = storageRom->has_mnemonic; strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); diff --git a/vendor/trezor-common b/vendor/trezor-common index 8e96b42260..8019bd2730 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 8e96b42260b84e1e0f0b00a5e528d19258c57031 +Subproject commit 8019bd2730ce7e4b2351e2441dbea38191ed14d9 From 2c63d51580b9a594a6e0bda26e9f81fd8d14a115 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 13 Dec 2017 18:04:22 +0100 Subject: [PATCH 0672/1154] u2f: avoid using hdnode_private_ckd_cached in order not to constantly invalidate cache --- firmware/u2f.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 5e6a06af53..0db0f3b4e0 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -458,10 +458,12 @@ static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - layoutHome(); - debugLog(0, "", "ERR: Derive private failed"); - return 0; + for (size_t i = 0; i < address_n_count; i++) { + if (hdnode_private_ckd(&node, address_n[i]) == 0) { + layoutHome(); + debugLog(0, "", "ERR: Derive private failed"); + return 0; + } } return &node; } From 5812f9865d72c8b10f488f0c7559ddabfa476269 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 14 Dec 2017 19:30:21 +0100 Subject: [PATCH 0673/1154] Fix size of version 9 storage --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 436d4460e2..22f8d91c4f 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -172,7 +172,7 @@ bool storage_from_flash(void) } else if (version == 9) { // added u2froot - old_storage_size = 1704; + old_storage_size = 1640; } // erase newly added fields From a304b76d34307dc2d9f7d1cdf678fa9d8434e8f7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 22 Aug 2017 17:06:04 +0100 Subject: [PATCH 0674/1154] storage: Clean up old_storage_size Note that OLD_STORAGE_SIZE(imported) != 460, because OLD_STORAGE_SIZE does not include end padding --- firmware/storage.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 22f8d91c4f..29b74d3084 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -152,27 +152,29 @@ bool storage_from_flash(void) memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); +#define OLD_STORAGE_SIZE(last_member) (offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + // copy storage size_t old_storage_size = 0; if (version == 1 || version == 2) { - old_storage_size = 460; + old_storage_size = OLD_STORAGE_SIZE(imported); } else if (version == 3 || version == 4 || version == 5) { // added homescreen - old_storage_size = 1488; + old_storage_size = OLD_STORAGE_SIZE(homescreen); } else if (version == 6 || version == 7) { // added u2fcounter - old_storage_size = 1496; + old_storage_size = OLD_STORAGE_SIZE(u2f_counter); } else if (version == 8) { // added flags and needsBackup - old_storage_size = 1504; + old_storage_size = OLD_STORAGE_SIZE(flags); } else if (version == 9) { // added u2froot - old_storage_size = 1640; + old_storage_size = OLD_STORAGE_SIZE(u2froot); } // erase newly added fields From cfc5fda603b8a6cd0167c5e214cb2f79c330278a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 22 Aug 2017 17:09:10 +0100 Subject: [PATCH 0675/1154] storage: Compact old_storage_size logic --- firmware/storage.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 29b74d3084..ad61e2f63c 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -157,22 +157,19 @@ bool storage_from_flash(void) // copy storage size_t old_storage_size = 0; - if (version == 1 || version == 2) { + if (version == 0) { + } else if (version <= 2) { old_storage_size = OLD_STORAGE_SIZE(imported); - } else - if (version == 3 || version == 4 || version == 5) { + } else if (version <= 5) { // added homescreen old_storage_size = OLD_STORAGE_SIZE(homescreen); - } else - if (version == 6 || version == 7) { + } else if (version <= 7) { // added u2fcounter old_storage_size = OLD_STORAGE_SIZE(u2f_counter); - } else - if (version == 8) { + } else if (version <= 8) { // added flags and needsBackup old_storage_size = OLD_STORAGE_SIZE(flags); - } else - if (version == 9) { + } else if (version <= 9) { // added u2froot old_storage_size = OLD_STORAGE_SIZE(u2froot); } From ded41c484ce2192b11bb657e7e329de2d9757dc1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 15 Dec 2017 12:28:54 +0100 Subject: [PATCH 0676/1154] storage: Padding to multiple of 4 bytes --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index ad61e2f63c..1309196c9d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -152,7 +152,7 @@ bool storage_from_flash(void) memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); -#define OLD_STORAGE_SIZE(last_member) (offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) +#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) // copy storage size_t old_storage_size = 0; From 810443f197d4910c44fa9c96d1ea947d54c504c1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 16 Dec 2017 15:23:23 +0100 Subject: [PATCH 0677/1154] Fix NULL pointer access Fixes #269 --- firmware/fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 6d903654af..9a7b8524a4 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -329,7 +329,7 @@ void fsm_msgChangePin(ChangePin *msg) CHECK_PIN_UNCACHED if (removal) { - storage_setPin(0); + storage_setPin(""); storage_update(); fsm_sendSuccess(_("PIN removed")); } else { From f17a0a85e06bf9e1e3320e6b2bb3874c55bdf882 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 16 Dec 2017 19:15:54 +0000 Subject: [PATCH 0678/1154] fsm: Add NEMDecryptMessage --- firmware/fsm.c | 66 ++++++++++++++++++++++++++++++++ firmware/fsm.h | 1 + firmware/protob/messages.options | 6 +++ vendor/trezor-crypto | 2 +- 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9a7b8524a4..34211bebe2 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1431,6 +1431,72 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { layoutHome(); } +void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) +{ + RESP_INIT(NEMDecryptedMessage); + + CHECK_INITIALIZED + + CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); + CHECK_PARAM(msg->has_payload, _("No payload provided")); + CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), _("Invalid encrypted payload")); + CHECK_PARAM(msg->has_public_key, _("No public key provided")); + CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); + + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->public_key.bytes, msg->network, address); + + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + _("Decrypt message"), + _("Confirm address?"), + address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count); + if (!node) return; + + const uint8_t *salt = msg->payload.bytes; + uint8_t *iv = &msg->payload.bytes[NEM_SALT_SIZE]; + + const uint8_t *payload = &msg->payload.bytes[NEM_SALT_SIZE + AES_BLOCK_SIZE]; + size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; + + // hdnode_nem_decrypt mutates the IV, so this will modify msg + bool ret = hdnode_nem_decrypt(node, + msg->public_key.bytes, + iv, + salt, + payload, + size, + resp->payload.bytes); + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); + layoutHome(); + return; + } + + resp->has_payload = true; + resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); + + layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); + layoutHome(); +} + void fsm_msgCosiCommit(CosiCommit *msg) { RESP_INIT(CosiCommitment); diff --git a/firmware/fsm.h b/firmware/fsm.h index 41f2cb123e..b91129a34d 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -68,6 +68,7 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); void fsm_msgNEMGetAddress(NEMGetAddress *msg); void fsm_msgNEMSignTx(NEMSignTx *msg); +void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); void fsm_msgCosiCommit(CosiCommit *msg); void fsm_msgCosiSign(CosiSign *msg); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index cbd4f007c0..e7aaffc6f2 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -150,6 +150,12 @@ NEMAddress.address max_size:41 NEMSignedTx.data max_size:2048 NEMSignedTx.signature max_size:64 +NEMDecryptMessage.address_n max_count:8 +NEMDecryptMessage.public_key max_size:32 +NEMDecryptMessage.payload max_size:320 + +NEMDecryptedMessage.payload max_size:256 + CosiCommit.address_n max_count:8 CosiCommit.data max_size:32 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 764cc4c6e8..74e74f5eed 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 764cc4c6e8ef32e7e1a77f0496ae090f11a36def +Subproject commit 74e74f5eed886ff871dc1fb36088e4b465917689 From 9401d2805a2963ef8d9982e0f9ac4438be02b99e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 16 Dec 2017 20:20:50 +0000 Subject: [PATCH 0679/1154] protob: Increase NEM payload max_size See NemProject/NanoWallet#362 --- firmware/protob/messages.options | 4 ++-- firmware/protob/types.options | 2 +- vendor/trezor-common | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index e7aaffc6f2..90dc420af4 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -152,9 +152,9 @@ NEMSignedTx.signature max_size:64 NEMDecryptMessage.address_n max_count:8 NEMDecryptMessage.public_key max_size:32 -NEMDecryptMessage.payload max_size:320 +NEMDecryptMessage.payload max_size:1072 -NEMDecryptedMessage.payload max_size:256 +NEMDecryptedMessage.payload max_size:1024 CosiCommit.address_n max_count:8 CosiCommit.data max_size:32 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index a0847d2a32..e087cb0706 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -42,7 +42,7 @@ NEMTransactionCommon.signer max_size:32 NEMTransfer.recipient max_size:41 NEMTransfer.public_key max_size:32 -NEMTransfer.payload max_size:256 +NEMTransfer.payload max_size:1024 NEMTransfer.mosaics max_count:16 NEMMosaic.namespace max_size:145 diff --git a/vendor/trezor-common b/vendor/trezor-common index 8019bd2730..dee677a9ec 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 8019bd2730ce7e4b2351e2441dbea38191ed14d9 +Subproject commit dee677a9ec6223a92e1f5151d77cf1cde5b043c7 From c06593e86474a1bcb9d462c626b47a609d03d49d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 17 Dec 2017 02:48:18 +0100 Subject: [PATCH 0680/1154] fix vendor/trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index dee677a9ec..8bd52248fa 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit dee677a9ec6223a92e1f5151d77cf1cde5b043c7 +Subproject commit 8bd52248fab2c025e3970d0ba2cc32d39e13caa0 From 83a34ff92572f211d56f21798aa172d72a9a22dd Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 9 Dec 2017 13:30:15 +0000 Subject: [PATCH 0681/1154] util: Add MIN and MAX macros --- firmware/u2f.c | 2 -- oled.c | 19 ++++++++----------- util.h | 4 ++++ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 0db0f3b4e0..33a5f1c1d0 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -40,8 +40,6 @@ #include "u2f_knownapps.h" #include "u2f.h" -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - // About 1/2 Second according to values used in protect.c #define U2F_TIMEOUT (800000/2) #define U2F_OUT_PKT_BUFFER_LEN 128 diff --git a/oled.c b/oled.c index 6daee8a92f..0b73db557c 100644 --- a/oled.c +++ b/oled.c @@ -306,9 +306,6 @@ void oledDrawStringRight(int x, int y, const char* text) oledDrawString(x, y, text); } -#define max(X,Y) ((X) > (Y) ? (X) : (Y)) -#define min(X,Y) ((X) < (Y) ? (X) : (Y)) - void oledDrawBitmap(int x, int y, const BITMAP *bmp) { for (int i = 0; i < bmp->width; i++) { @@ -327,10 +324,10 @@ void oledDrawBitmap(int x, int y, const BITMAP *bmp) */ void oledInvert(int x1, int y1, int x2, int y2) { - x1 = max(x1, 0); - y1 = max(y1, 0); - x2 = min(x2, OLED_WIDTH - 1); - y2 = min(y2, OLED_HEIGHT - 1); + x1 = MAX(x1, 0); + y1 = MAX(y1, 0); + x2 = MIN(x2, OLED_WIDTH - 1); + y2 = MIN(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) { oledInvertPixel(x,y); @@ -343,10 +340,10 @@ void oledInvert(int x1, int y1, int x2, int y2) */ void oledBox(int x1, int y1, int x2, int y2, bool set) { - x1 = max(x1, 0); - y1 = max(y1, 0); - x2 = min(x2, OLED_WIDTH - 1); - y2 = min(y2, OLED_HEIGHT - 1); + x1 = MAX(x1, 0); + y1 = MAX(y1, 0); + x2 = MIN(x2, OLED_WIDTH - 1); + y2 = MIN(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) { set ? oledDrawPixel(x, y) : oledClearPixel(x, y); diff --git a/util.h b/util.h index 1494cb6f46..6e5d4e0845 100644 --- a/util.h +++ b/util.h @@ -25,6 +25,10 @@ #include #include +// Statement expressions make these macros side-effect safe +#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) + void delay(uint32_t wait); // converts uint32 to hexa (8 digits) From 77ff5a1c55998e60a380f35431d0f71c11773d61 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 17 Dec 2017 03:19:26 +0100 Subject: [PATCH 0682/1154] fix typo --- util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.h b/util.h index 6e5d4e0845..85961e64d7 100644 --- a/util.h +++ b/util.h @@ -26,7 +26,7 @@ #include // Statement expressions make these macros side-effect safe -#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) #define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) void delay(uint32_t wait); From eb0574bda7cd4b859c5ae8728ff9c16695088b5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Dec 2017 15:49:02 +0100 Subject: [PATCH 0683/1154] bootloader: don't restore storage from unofficial firmware --- bootloader/usb.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index ee007c665c..e6d17789dd 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -42,6 +42,7 @@ #define ENDPOINT_ADDRESS_OUT (0x01) static bool brand_new_firmware; +static bool old_was_unsigned; static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, @@ -437,8 +438,14 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } while (!button.YesUp && !button.NoUp); } if (brand_new_firmware || button.YesUp) { - // backup metadata - backup_metadata(meta_backup); + // check whether current firmware is signed + if (signatures_ok(NULL)) { + old_was_unsigned = false; + // backup metadata + backup_metadata(meta_backup); + } else { + old_was_unsigned = true; + } flash_wait_for_last_operation(); flash_clear_status_flags(); flash_unlock(); @@ -587,8 +594,11 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); - // wipe storage if signatures are not ok or the firmware flag isn't set. - if ((flags & 0x01) == 0 || !signatures_ok(NULL)) { + // wipe storage if: + // 1) old firmware was unsigned + // 2) firmware restore flag isn't set + // 3) signatures are not ok + if (old_was_unsigned || (flags & 0x01) == 0 || !signatures_ok(NULL)) { memset(meta_backup, 0, sizeof(meta_backup)); } // copy new firmware header From 9732825e243548b20f9c617718333a6d359970b5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Dec 2017 18:36:17 +0100 Subject: [PATCH 0684/1154] move ethereum_tokens-gen.py to trezor-common --- firmware/ethereum_tokens-gen.py | 41 --------------------------------- vendor/trezor-common | 2 +- 2 files changed, 1 insertion(+), 42 deletions(-) delete mode 100755 firmware/ethereum_tokens-gen.py diff --git a/firmware/ethereum_tokens-gen.py b/firmware/ethereum_tokens-gen.py deleted file mode 100755 index 99b305c70e..0000000000 --- a/firmware/ethereum_tokens-gen.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -import requests - -subst = { - (1, 'AVA \U0001F434'): 'AVA', - (1, 'BeerCoin \U0001F37A '): 'BEER', - (1, 'CryptoCarbon'): 'CCRB', - (1, 'DGX 1.0'): 'DGX1', - (1, 'JetCoins'): 'JTC', - (1, 'Unicorn \U0001F984 '): 'UNCRN', -} - - -def get_tokens(chain): - URL = 'https://raw.githubusercontent.com/kvhnuke/etherwallet/mercury/app/scripts/tokens/%sTokens.json' % chain - r = requests.get(URL) - return r.json() - - -def print_tokens(chain, chain_id): - tokens = get_tokens(chain) - - for t in sorted(tokens, key=lambda x: x['symbol'].upper()): - address, symbol, decimal = t['address'], t['symbol'], t['decimal'] - s = (chain_id, symbol) - if s in subst: - symbol = subst[s] - address = '\\x'.join([address[i:i + 2] for i in range(0, len(address), 2)])[2:].lower() - print('\t{%2d, "%s", " %s", %d},' % (chain_id, address, symbol, decimal)) - - return len(tokens) - - -count = 0 - -count += print_tokens('eth', 1) -count += print_tokens('etc', 61) - -print('-' * 32) - -print('#define TOKENS_COUNT %d' % count) diff --git a/vendor/trezor-common b/vendor/trezor-common index 8bd52248fa..13499e256a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 8bd52248fab2c025e3970d0ba2cc32d39e13caa0 +Subproject commit 13499e256acfdde662b98ea402146ca105fb03b3 From 36eac04e61d7a135908381a3bf3e89a986d536c8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 18:40:54 +0000 Subject: [PATCH 0685/1154] protob: Increase Features.coins max_count --- firmware/protob/messages.options | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 90dc420af4..294aff73b8 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -2,7 +2,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:15 +Features.coins max_count:16 Features.revision max_size:20 Features.bootloader_hash max_size:32 Features.model max_size:17 From 7c630141d4f481705061b210b81c2ec861f2fdb7 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 11 Dec 2017 19:42:51 +0000 Subject: [PATCH 0686/1154] Makefile.include: Use LDLIBS & LIBDEPS --- Makefile.include | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile.include b/Makefile.include index d01ccbdda3..14d16a3252 100644 --- a/Makefile.include +++ b/Makefile.include @@ -82,13 +82,18 @@ LDFLAGS += --static \ -Wl,--end-group \ -L$(TOP_DIR) \ -L$(TOOLCHAIN_DIR)/lib \ - -L$(TOOLCHAIN_DIR)/lib/stm32/f2 \ -T$(LDSCRIPT) \ -nostartfiles \ -Wl,--gc-sections \ $(CPUFLAGS) \ $(FPUFLAGS) +LDLIBS += -ltrezor +LIBDEPS += $(TOP_DIR)/libtrezor.a + +LDLIBS += -lopencm3_stm32f2 +LIBDEPS += $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a + all: $(NAME).bin flash: $(NAME).bin @@ -127,8 +132,8 @@ $(NAME).srec: $(NAME).elf $(NAME).list: $(NAME).elf $(OBJDUMP) -S $(NAME).elf > $(NAME).list -$(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP_DIR)/libtrezor.a - $(LD) -o $(NAME).elf $(OBJS) -ltrezor -lopencm3_stm32f2 $(LDFLAGS) +$(NAME).elf: $(OBJS) $(LDSCRIPT) $(LIBDEPS) + $(LD) -o $(NAME).elf $(OBJS) $(LDLIBS) $(LDFLAGS) %.o: %.s Makefile $(AS) $(CPUFLAGS) -o $@ $< From ba5b44d0c569956297e7d1498854f0be8e487c88 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 13 Dec 2017 18:38:51 +0000 Subject: [PATCH 0687/1154] emulator: Initial commit --- .gitignore | 1 + Makefile | 11 +++++ Makefile.include | 60 ++++++++++++++++++----- buttons.c | 8 +++- buttons.h | 1 + emulator/Makefile | 15 ++++++ emulator/buttons.c | 40 ++++++++++++++++ emulator/emulator.h | 40 ++++++++++++++++ emulator/flash.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ emulator/oled.c | 90 ++++++++++++++++++++++++++++++++++ emulator/rng.c | 32 +++++++++++++ emulator/setup.c | 95 ++++++++++++++++++++++++++++++++++++ emulator/strl.c | 45 +++++++++++++++++ emulator/strl.h | 28 +++++++++++ emulator/timer.c | 32 +++++++++++++ emulator/udp.c | 85 +++++++++++++++++++++++++++++++++ firmware/Makefile | 5 ++ firmware/debug.c | 4 ++ firmware/fsm.c | 1 + firmware/layout2.c | 2 +- firmware/messages.c | 10 ++++ firmware/signing.c | 4 +- firmware/storage.c | 14 ++++++ firmware/trezor.c | 5 +- firmware/trezor.h | 5 ++ firmware/udp.c | 70 +++++++++++++++++++++++++++ firmware/usb.c | 4 +- memory.h | 4 ++ oled.c | 10 ++-- rng.c | 2 + timer.c | 3 -- timer.h | 17 ++++--- util.c | 6 --- util.h | 6 ++- 34 files changed, 831 insertions(+), 38 deletions(-) create mode 100644 emulator/Makefile create mode 100644 emulator/buttons.c create mode 100644 emulator/emulator.h create mode 100644 emulator/flash.c create mode 100644 emulator/oled.c create mode 100644 emulator/rng.c create mode 100644 emulator/setup.c create mode 100644 emulator/strl.c create mode 100644 emulator/strl.h create mode 100644 emulator/timer.c create mode 100644 emulator/udp.c create mode 100644 firmware/udp.c diff --git a/.gitignore b/.gitignore index 4490fece64..8a121b9628 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ build/ *.bin *.elf *.hex +*.img *.list *.srec *.log diff --git a/Makefile b/Makefile index 27d58a0f44..81d418d9d1 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,24 @@ +ifneq ($(EMULATOR),1) OBJS += startup.o +endif + OBJS += buttons.o OBJS += layout.o OBJS += oled.o OBJS += rng.o OBJS += serialno.o + +ifneq ($(EMULATOR),1) OBJS += setup.o +endif + OBJS += util.o OBJS += memory.o + +ifneq ($(EMULATOR),1) OBJS += timer.o +endif + OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/Makefile.include b/Makefile.include index 14d16a3252..5f1aa605a8 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,6 +1,18 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 +ifeq ($(EMULATOR),1) +CC = gcc +LD = gcc +OBJCOPY = objcopy +OBJDUMP = objdump +AR = ar +AS = as + +OPTFLAGS ?= -O3 +DBGFLAGS ?= -g3 +CPUFLAGS ?= -m32 +else PREFIX ?= arm-none-eabi- CC = $(PREFIX)gcc LD = $(PREFIX)gcc @@ -15,6 +27,7 @@ OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG CPUFLAGS ?= -mcpu=cortex-m3 -mthumb FPUFLAGS ?= -msoft-float +endif CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ @@ -55,6 +68,28 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc +ifeq ($(EMULATOR),1) +CFLAGS += -DEMULATOR=1 + +ifeq ($(HEADLESS),1) +CFLAGS += -DHEADLESS=1 +else +CFLAGS += -DHEADLESS=0 + +CFLAGS += $(shell pkg-config --cflags sdl2) +LDLIBS += $(shell pkg-config --libs sdl2) +endif + +CFLAGS += -include $(TOP_DIR)emulator/emulator.h +CFLAGS += -include stdio.h + +LDFLAGS += -L$(TOP_DIR) \ + -L$(TOP_DIR)emulator \ + $(CPUFLAGS) + +LDLIBS += -ltrezor -lemulator +LIBDEPS += $(TOP_DIR)/libtrezor.a $(TOP_DIR)emulator/libemulator.a +else ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) LDSCRIPT = $(TOP_DIR)/memory_app_$(APPVER).ld @@ -62,17 +97,7 @@ else LDSCRIPT = $(TOP_DIR)/memory.ld endif -ifeq ($(MEMORY_PROTECT), 0) -CFLAGS += -DMEMORY_PROTECT=0 -else -CFLAGS += -DMEMORY_PROTECT=1 -endif - -ifeq ($(DEBUG_RNG), 1) -CFLAGS += -DDEBUG_RNG=1 -else -CFLAGS += -DDEBUG_RNG=0 -endif +CFLAGS += -DEMULATOR=0 LDFLAGS += --static \ -Wl,--start-group \ @@ -93,6 +118,19 @@ LIBDEPS += $(TOP_DIR)/libtrezor.a LDLIBS += -lopencm3_stm32f2 LIBDEPS += $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a +endif + +ifeq ($(MEMORY_PROTECT), 0) +CFLAGS += -DMEMORY_PROTECT=0 +else +CFLAGS += -DMEMORY_PROTECT=1 +endif + +ifeq ($(DEBUG_RNG), 1) +CFLAGS += -DDEBUG_RNG=1 +else +CFLAGS += -DDEBUG_RNG=0 +endif all: $(NAME).bin diff --git a/buttons.c b/buttons.c index 9207eac00c..a6e64b5ad6 100644 --- a/buttons.c +++ b/buttons.c @@ -21,12 +21,18 @@ struct buttonState button; +#if !EMULATOR +uint16_t buttonRead(void) { + return gpio_port_read(BTN_PORT); +} +#endif + void buttonUpdate() { uint16_t state; static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; - state = gpio_port_read(BTN_PORT); + state = buttonRead(); if ((state & BTN_PIN_YES) == 0) { // Yes button is down if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down diff --git a/buttons.h b/buttons.h index 140e380c66..fb24d58dd7 100644 --- a/buttons.h +++ b/buttons.h @@ -32,6 +32,7 @@ struct buttonState { extern struct buttonState button; +uint16_t buttonRead(void); void buttonUpdate(void); #ifndef BTN_PORT diff --git a/emulator/Makefile b/emulator/Makefile new file mode 100644 index 0000000000..e733d45bfd --- /dev/null +++ b/emulator/Makefile @@ -0,0 +1,15 @@ +OBJS += setup.o + +OBJS += buttons.o +OBJS += flash.o +OBJS += oled.o +OBJS += rng.o +OBJS += timer.o +OBJS += udp.o + +OBJS += strl.o + +libemulator.a: $(OBJS) + $(AR) rcs $@ $(OBJS) + +include ../Makefile.include diff --git a/emulator/buttons.c b/emulator/buttons.c new file mode 100644 index 0000000000..71b94a4426 --- /dev/null +++ b/emulator/buttons.c @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "buttons.h" + +#if !HEADLESS +#include +#endif + +uint16_t buttonRead(void) { + uint16_t state = 0; + +#if !HEADLESS + const uint8_t *scancodes = SDL_GetKeyboardState(NULL); + if (scancodes[SDL_SCANCODE_LEFT]) { + state |= BTN_PIN_NO; + } + if (scancodes[SDL_SCANCODE_RIGHT]) { + state |= BTN_PIN_YES; + } +#endif + + return ~state; +} diff --git a/emulator/emulator.h b/emulator/emulator.h new file mode 100644 index 0000000000..deaa73dea4 --- /dev/null +++ b/emulator/emulator.h @@ -0,0 +1,40 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __EMULATOR_H__ +#define __EMULATOR_H__ + +#if EMULATOR + +#include "strl.h" + +#include + +extern void *emulator_flash_base; + +void emulatorPoll(void); +void emulatorRandom(void *buffer, size_t size); + +void emulatorSocketInit(void); +size_t emulatorSocketRead(void *buffer, size_t size); +size_t emulatorSocketWrite(const void *buffer, size_t size); + +#endif + +#endif diff --git a/emulator/flash.c b/emulator/flash.c new file mode 100644 index 0000000000..708dd25981 --- /dev/null +++ b/emulator/flash.c @@ -0,0 +1,114 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include + +#include "memory.h" + +void flash_lock(void) {} +void flash_unlock(void) {} + +void flash_clear_status_flags(void) {} + +void flash_lock_option_bytes(void) {} +void flash_unlock_option_bytes(void) {} + +void flash_program_option_bytes(uint32_t data) { + (void) data; +} + +static ssize_t sector_to_offset(uint8_t sector) { + switch (sector) { + case 0: + return 0x0; + case 1: + return 0x4000; + case 2: + return 0x8000; + case 3: + return 0xC000; + case 4: + return 0x10000; + case 5: + return 0x20000; + case 6: + return 0x40000; + case 7: + return 0x60000; + case 8: + return 0x80000; + default: + return -1; + } +} + +static void *sector_to_address(uint8_t sector) { + ssize_t offset = sector_to_offset(sector); + if (offset < 0) { + return NULL; + } + + return (void *) (FLASH_ORIGIN + offset); +} + +static ssize_t sector_to_size(uint8_t sector) { + ssize_t start = sector_to_offset(sector); + if (start < 0) { + return -1; + } + + ssize_t end = sector_to_offset(sector + 1); + if (end < 0) { + return -1; + } + + return end - start; +} + +void flash_erase_sector(uint8_t sector, uint32_t program_size) { + (void) program_size; + + void *address = sector_to_address(sector); + if (address == NULL) { + return; + } + + ssize_t size = sector_to_size(sector); + if (size < 0) { + return; + } + + memset(address, 0xFF, size); +} + +void flash_erase_all_sectors(uint32_t program_size) { + (void) program_size; + + memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE); +} + +void flash_program_word(uint32_t address, uint32_t data) { + MMIO32(address) = data; +} + +void flash_program_byte(uint32_t address, uint8_t data) { + MMIO8(address) = data; +} diff --git a/emulator/oled.c b/emulator/oled.c new file mode 100644 index 0000000000..242408af07 --- /dev/null +++ b/emulator/oled.c @@ -0,0 +1,90 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "oled.h" + +#if HEADLESS + +void oledInit(void) {} +void oledRefresh(void) {} +void emulatorPoll(void) {} + +#else + +#include + +static SDL_Renderer *renderer = NULL; +static SDL_Texture *texture = NULL; + +void oledInit(void) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH, OLED_HEIGHT, 0); + if (window == NULL) { + fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); + exit(1); + } + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) { + fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); + + oledClear(); + oledRefresh(); +} + +void oledRefresh(void) { + const uint8_t *buffer = oledGetBuffer(); + + static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; + + for (size_t i = 0; i < OLED_BUFSIZE; i++) { + int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH; + int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7; + + for (uint8_t shift = 0; shift < 8; shift++, y--) { + bool set = (buffer[i] >> shift) & 1; + data[y][x] = set ? 0xFFFFFFFF : 0xFF000000; + } + } + + SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); +} + +void emulatorPoll(void) { + SDL_Event event; + + if (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + exit(1); + } + } +} + +#endif diff --git a/emulator/rng.c b/emulator/rng.c new file mode 100644 index 0000000000..8d53de28d3 --- /dev/null +++ b/emulator/rng.c @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "rng.h" + +uint32_t random32(void) { + static uint32_t last = 0; + uint32_t new; + + do { + emulatorRandom(&new, sizeof(new)); + } while (last == new); + + last = new; + return new; +} diff --git a/emulator/setup.c b/emulator/setup.c new file mode 100644 index 0000000000..f994916d3e --- /dev/null +++ b/emulator/setup.c @@ -0,0 +1,95 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "memory.h" +#include "oled.h" +#include "rng.h" +#include "setup.h" +#include "timer.h" + +#define EMULATOR_FLASH_FILE "emulator.img" + +void *emulator_flash_base = NULL; + +uint32_t __stack_chk_guard; + +static int urandom = -1; + +static void setup_urandom(void); +static void setup_flash(void); + +void setup(void) { + setup_urandom(); + setup_flash(); +} + +void emulatorRandom(void *buffer, size_t size) { + ssize_t n = read(urandom, buffer, size); + if (n < 0 || ((size_t) n) != size) { + perror("Failed to read /dev/urandom"); + exit(1); + } +} + +static void setup_urandom(void) { + urandom = open("/dev/urandom", O_RDONLY); + if (urandom < 0) { + perror("Failed to open /dev/urandom"); + exit(1); + } +} + +static void setup_flash(void) { + int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); + if (fd < 0) { + perror("Failed to open flash emulation file"); + exit(1); + } + + off_t length = lseek(fd, 0, SEEK_END); + if (length < 0) { + perror("Failed to read length of flash emulation file"); + exit(1); + } + + emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (emulator_flash_base == MAP_FAILED) { + perror("Failed to map flash emulation file"); + exit(1); + } + + if (length < FLASH_TOTAL_SIZE) { + if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { + perror("Failed to initialize flash emulation file"); + exit(1); + } + + /* Initialize the flash */ + flash_erase_all_sectors(FLASH_CR_PROGRAM_X32); + } +} diff --git a/emulator/strl.c b/emulator/strl.c new file mode 100644 index 0000000000..42323a3ab2 --- /dev/null +++ b/emulator/strl.c @@ -0,0 +1,45 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "strl.h" + +#include + +size_t strlcpy(char *dst, const char *src, size_t size) { + if (size == 0) { + return 0; + } + + for (size_t i = 0; i < size - 1; i++) { + dst[i] = src[i]; + + if (src[i] == '\0') { + return i; + } + } + + dst[size - 1] = '\0'; + return size - 2; +} + +size_t strlcat(char *dst, const char *src, size_t size) { + size_t n = strnlen(dst, size); + + return n + strlcpy(&dst[n], src, size - n); +} diff --git a/emulator/strl.h b/emulator/strl.h new file mode 100644 index 0000000000..8b44e0454e --- /dev/null +++ b/emulator/strl.h @@ -0,0 +1,28 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __STRL_H__ +#define __STRL_H__ + +#include + +size_t strlcpy(char *dst, const char *src, size_t size); +size_t strlcat(char *dst, const char *src, size_t size); + +#endif diff --git a/emulator/timer.c b/emulator/timer.c new file mode 100644 index 0000000000..eadbf76cce --- /dev/null +++ b/emulator/timer.c @@ -0,0 +1,32 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "timer.h" + +void timer_init(void) {} + +uint32_t timer_ms(void) { + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + + uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); + return msec; +} diff --git a/emulator/udp.c b/emulator/udp.c new file mode 100644 index 0000000000..b01ec66b67 --- /dev/null +++ b/emulator/udp.c @@ -0,0 +1,85 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define TREZOR_UDP_PORT 21324 + +static int fd = -1; +static struct sockaddr_in from; +static socklen_t fromlen; + +void emulatorSocketInit(void) { + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + perror("Failed to create socket"); + exit(1); + } + + fromlen = 0; + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(TREZOR_UDP_PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { + perror("Failed to bind socket"); + exit(1); + } +} + +size_t emulatorSocketRead(void *buffer, size_t size) { + fromlen = sizeof(from); + ssize_t n = recvfrom(fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen); + + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("Failed to read socket"); + } + return 0; + } + + static const char msg_ping[] = { 'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G' }; + static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; + + if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { + emulatorSocketWrite(msg_pong, sizeof(msg_pong)); + return 0; + } + + return n; +} + +size_t emulatorSocketWrite(const void *buffer, size_t size) { + if (fromlen > 0) { + ssize_t n = sendto(fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &from, fromlen); + if (n < 0 || ((size_t) n) != size) { + perror("Failed to write socket"); + return 0; + } + } + + return size; +} diff --git a/firmware/Makefile b/firmware/Makefile index 7a5a16a3eb..577d20e34d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -7,7 +7,12 @@ endif NAME = trezor +ifeq ($(EMULATOR),1) +OBJS += udp.o +else OBJS += usb.o +endif + OBJS += u2f.o OBJS += messages.o OBJS += storage.o diff --git a/firmware/debug.c b/firmware/debug.c index b455f290c6..a8519fd948 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -47,7 +47,11 @@ void debugLog(int level, const char *bucket, const char *text) { (void)level; (void)bucket; +#if EMULATOR + puts(text); +#else oledDebug(text); +#endif } char *debugInt(const uint32_t i) diff --git a/firmware/fsm.c b/firmware/fsm.c index 34211bebe2..15359c8a33 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -234,6 +234,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) } _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); + resp->coins_count = COINS_COUNT; for (int i = 0; i < COINS_COUNT; i++) { if (coins[i].coin_name) { diff --git a/firmware/layout2.c b/firmware/layout2.c index 84a48bed2a..bb86b9aac0 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -121,7 +121,7 @@ void layoutHome(void) oledRefresh(); // Reset lock screen timeout - system_millis_lock_start = system_millis; + system_millis_lock_start = timer_ms(); } void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) diff --git a/firmware/messages.c b/firmware/messages.c index d8411bfa85..6db0d54dbd 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -48,7 +48,12 @@ const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { +#if EMULATOR + (void) type; + if (dir == m->dir && msg_id == m->msg_id) { +#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { +#endif return m->fields; } m++; @@ -60,7 +65,12 @@ void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { +#if EMULATOR + (void) type; + if (dir == m->dir && msg_id == m->msg_id) { +#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { +#endif m->process_func(ptr); return; } diff --git a/firmware/signing.c b/firmware/signing.c index e31078b65b..c449759741 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -505,7 +505,7 @@ static bool signing_check_input(TxInputType *txinput) { tx_sequence_hash(&hashers[1], txinput); // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hashers[2], txinput); - hasher_Update(&hashers[2], &txinput->script_type, sizeof(&txinput->script_type)); + hasher_Update(&hashers[2], (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -962,7 +962,7 @@ void signing_txack(TransactionType *tx) } // check prevouts and script type tx_prevout_hash(&hashers[0], tx->inputs); - hasher_Update(&hashers[0], &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + hasher_Update(&hashers[0], (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); diff --git a/firmware/storage.c b/firmware/storage.c index 1309196c9d..8b982ea1ac 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -55,7 +55,13 @@ _Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); _Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); #define STORAGE_ROM ((const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid))) + +#if EMULATOR +// TODO: Fix this for emulator +#define storageRom STORAGE_ROM +#else const Storage *storageRom = STORAGE_ROM; +#endif char storage_uuid_str[25]; @@ -92,7 +98,10 @@ be added to the storage u2f_counter to get the real counter value. #define FLASH_STORAGE_U2FAREA_LEN (0x100) #define FLASH_STORAGE_REALLEN (sizeof(storage_magic) + sizeof(storage_uuid) + sizeof(Storage)) +#if !EMULATOR +// TODO: Fix this for emulator _Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); +#endif /* Current u2f offset, i.e. u2f counter is * storage.u2f_counter + storage_u2f_offset. @@ -119,10 +128,12 @@ void storage_show_error(void) void storage_check_flash_errors(void) { +#if !EMULATOR // flash operation failed if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { storage_show_error(); } +#endif } bool storage_from_flash(void) @@ -197,7 +208,10 @@ bool storage_from_flash(void) flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts +#if !EMULATOR +// TODO: Fix this for emulator _Static_assert(((uint32_t)&STORAGE_ROM->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); +#endif flash_program_byte((uint32_t)&storageRom->has_pin_failed_attempts, 0); flash_program_word((uint32_t)&storageRom->pin_failed_attempts, 0); flash_lock(); diff --git a/firmware/trezor.c b/firmware/trezor.c index 861d7aff97..9bb013edcd 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -32,6 +32,9 @@ #include "gettext.h" #include "fastflash.h" +/* Screen timeout */ +uint32_t system_millis_lock_start; + void check_lock_screen(void) { buttonUpdate(); @@ -73,7 +76,7 @@ void check_lock_screen(void) // if homescreen is shown for longer than 10 minutes, lock too if (layoutLast == layoutHome) { - if ((system_millis - system_millis_lock_start) >= 600000) { + if ((timer_ms() - system_millis_lock_start) >= 600000) { // lock the screen session_clear(true); layoutScreensaver(); diff --git a/firmware/trezor.h b/firmware/trezor.h index c240cbc696..c47e38306b 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -20,6 +20,8 @@ #ifndef __TREZOR_H__ #define __TREZOR_H__ +#include + #define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_PATCH 0 @@ -35,4 +37,7 @@ #define DEBUG_LOG 0 #endif +/* Screen timeout */ +extern uint32_t system_millis_lock_start; + #endif diff --git a/firmware/udp.c b/firmware/udp.c new file mode 100644 index 0000000000..04959aede4 --- /dev/null +++ b/firmware/udp.c @@ -0,0 +1,70 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include + +#include "usb.h" + +#include "messages.h" +#include "timer.h" + +static volatile char tiny = 0; + +void usbInit(void) { + emulatorSocketInit(); +} + +void usbPoll(void) { + emulatorPoll(); + + static uint8_t buffer[64]; + if (emulatorSocketRead(buffer, sizeof(buffer)) > 0) { + if (!tiny) { + msg_read(buffer, sizeof(buffer)); + } else { + msg_read_tiny(buffer, sizeof(buffer)); + } + } + + const uint8_t *data = msg_out_data(); + +#if DEBUG_LINK + if (data == NULL) { + data = msg_debug_out_data(); + } +#endif + + if (data != NULL) { + emulatorSocketWrite(data, 64); + } +} + +char usbTiny(char set) { + char old = tiny; + tiny = set; + return old; +} + +void usbSleep(uint32_t millis) { + uint32_t start = timer_ms(); + + while ((timer_ms() - start) < millis) { + usbPoll(); + } +} diff --git a/firmware/usb.c b/firmware/usb.c index 55bd095178..7a59b6fa02 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -446,9 +446,9 @@ char usbTiny(char set) void usbSleep(uint32_t millis) { - uint32_t start = system_millis; + uint32_t start = timer_ms(); - while ((system_millis - start) < millis) { + while ((timer_ms() - start) < millis) { usbd_poll(usbd_dev); } } diff --git a/memory.h b/memory.h index fb5d8af5a9..f6c4a87050 100644 --- a/memory.h +++ b/memory.h @@ -62,7 +62,11 @@ */ +#if EMULATOR +#define FLASH_ORIGIN ((uint32_t) emulator_flash_base) +#else #define FLASH_ORIGIN (0x08000000) +#endif #define FLASH_TOTAL_SIZE (512 * 1024) diff --git a/oled.c b/oled.c index 0b73db557c..7b1d5fce0a 100644 --- a/oled.c +++ b/oled.c @@ -105,10 +105,11 @@ void oledInvertPixel(int x, int y) _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y); } +#if !EMULATOR /* * Send a block of data via the SPI bus. */ -inline void SPISend(uint32_t base, uint8_t *data, int len) +static inline void SPISend(uint32_t base, const uint8_t *data, int len) { delay(1); for (int i = 0; i < len; i++) { @@ -123,7 +124,7 @@ inline void SPISend(uint32_t base, uint8_t *data, int len) */ void oledInit() { - static uint8_t s[25] = { + static const uint8_t s[25] = { OLED_DISPLAYOFF, OLED_SETDISPLAYCLOCKDIV, 0x80, @@ -169,6 +170,7 @@ void oledInit() oledClear(); oledRefresh(); } +#endif /* * Clears the display buffer (sets all pixels to black) @@ -184,9 +186,10 @@ void oledClear() * make the change visible. All other operations only change the buffer * not the content of the display. */ +#if !EMULATOR void oledRefresh() { - static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; + static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; // draw triangle in upper right corner if (is_debug_link) { @@ -216,6 +219,7 @@ void oledRefresh() oledInvertPixel(OLED_WIDTH - 1, 4); } } +#endif const uint8_t *oledGetBuffer() { diff --git a/rng.c b/rng.c index 2220947642..145f51b4b5 100644 --- a/rng.c +++ b/rng.c @@ -23,6 +23,7 @@ #include "rng.h" +#if !EMULATOR uint32_t random32(void) { static uint32_t last = 0, new = 0; @@ -34,6 +35,7 @@ uint32_t random32(void) last = new; return new; } +#endif uint32_t random_uniform(uint32_t n) { diff --git a/timer.c b/timer.c index 7a3dfcfb36..d58855fefd 100644 --- a/timer.c +++ b/timer.c @@ -27,9 +27,6 @@ /* 1 tick = 1 ms */ volatile uint32_t system_millis; -/* Screen timeout */ -uint32_t system_millis_lock_start; - /* * Initialise the Cortex-M3 SysTick timer */ diff --git a/timer.h b/timer.h index 235ba5f317..ac76d07e5d 100644 --- a/timer.h +++ b/timer.h @@ -22,12 +22,17 @@ #include -/* 1 tick = 1 ms */ -extern volatile uint32_t system_millis; - -/* Screen timeout */ -extern uint32_t system_millis_lock_start; - void timer_init(void); +#if EMULATOR +uint32_t timer_ms(void); +#else +static inline uint32_t timer_ms(void) { + /* 1 tick = 1 ms */ + extern volatile uint32_t system_millis; + + return system_millis; +} +#endif + #endif diff --git a/util.c b/util.c index 09eba316eb..197c45445b 100644 --- a/util.c +++ b/util.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ -#include #include "util.h" inline void delay(uint32_t wait) @@ -72,8 +71,3 @@ void __attribute__((noreturn)) system_halt(void) { for (;;) {} // loop forever } - -void __attribute__((noreturn)) system_reset(void) -{ - scb_reset_system(); -} diff --git a/util.h b/util.h index 85961e64d7..05d9c9a739 100644 --- a/util.h +++ b/util.h @@ -22,8 +22,10 @@ #include +#if !EMULATOR #include #include +#endif // Statement expressions make these macros side-effect safe #define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) @@ -42,9 +44,8 @@ uint32_t readprotobufint(uint8_t **ptr); // halt execution (or do an endless loop) void __attribute__((noreturn)) system_halt(void); -// reset system -void __attribute__((noreturn)) system_reset(void); +#if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; @@ -65,5 +66,6 @@ static inline void __attribute__((noreturn)) load_vector_table(const vector_tabl // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) for (;;); } +#endif #endif From 644907e160e686e30f76fc556ed917fad0f7f65f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 16 Dec 2017 20:39:24 +0000 Subject: [PATCH 0688/1154] emulator: Add EMULATOR=1 to emulator/Makefile --- emulator/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/emulator/Makefile b/emulator/Makefile index e733d45bfd..1f2976dd01 100644 --- a/emulator/Makefile +++ b/emulator/Makefile @@ -1,3 +1,5 @@ +EMULATOR := 1 + OBJS += setup.o OBJS += buttons.o From 17340c239674f5381da873c06bc8f91ff43b60be Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 16 Dec 2017 20:39:43 +0000 Subject: [PATCH 0689/1154] emulator: Show DEBUG_LINK indicator --- emulator/oled.c | 6 ++++++ oled.c | 27 +++++++++++++-------------- oled.h | 2 ++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/emulator/oled.c b/emulator/oled.c index 242408af07..8f58759351 100644 --- a/emulator/oled.c +++ b/emulator/oled.c @@ -58,6 +58,9 @@ void oledInit(void) { } void oledRefresh(void) { + /* Draw triangle in upper right corner */ + oledInvertDebugLink(); + const uint8_t *buffer = oledGetBuffer(); static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; @@ -75,6 +78,9 @@ void oledRefresh(void) { SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); + + /* Return it back */ + oledInvertDebugLink(); } void emulatorPoll(void) { diff --git a/oled.c b/oled.c index 7b1d5fce0a..569b44864b 100644 --- a/oled.c +++ b/oled.c @@ -180,6 +180,17 @@ void oledClear() memset(_oledbuffer, 0, sizeof(_oledbuffer)); } +void oledInvertDebugLink() +{ + if (is_debug_link) { + oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); + oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); + oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); + oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); + oledInvertPixel(OLED_WIDTH - 1, 4); + } +} + /* * Refresh the display. This copies the buffer to the display to show the * contents. This must be called after every operation to the buffer to @@ -192,13 +203,7 @@ void oledRefresh() static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; // draw triangle in upper right corner - if (is_debug_link) { - oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); - oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); - oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); - oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); - oledInvertPixel(OLED_WIDTH - 1, 4); - } + oledInvertDebugLink(); gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select SPISend(SPI_BASE, s, 3); @@ -211,13 +216,7 @@ void oledRefresh() gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD // return it back - if (is_debug_link) { - oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); - oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); - oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); - oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); - oledInvertPixel(OLED_WIDTH - 1, 4); - } + oledInvertDebugLink(); } #endif diff --git a/oled.h b/oled.h index 9c5531a99d..845e1e2b27 100644 --- a/oled.h +++ b/oled.h @@ -35,6 +35,8 @@ void oledClear(void); void oledRefresh(void); void oledSetDebugLink(bool set); +void oledInvertDebugLink(void); + void oledSetBuffer(uint8_t *buf); const uint8_t *oledGetBuffer(void); void oledDrawPixel(int x, int y); From 923d5f7555c1f9a1b00dc89bcfc32068d1ada339 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 17 Dec 2017 16:00:32 +0000 Subject: [PATCH 0690/1154] script: Add Scripts To Rule Them All --- .gitmodules | 3 +++ .travis.yml | 7 +------ script/bootstrap | 10 ++++++++++ script/cibuild | 25 +++++++++++++++++++++++++ script/setup | 13 +++++++++++++ script/test | 20 ++++++++++++++++++++ vendor/python-trezor | 1 + 7 files changed, 73 insertions(+), 6 deletions(-) create mode 100755 script/bootstrap create mode 100755 script/cibuild create mode 100755 script/setup create mode 100755 script/test create mode 160000 vendor/python-trezor diff --git a/.gitmodules b/.gitmodules index 920894a059..7b3b203bcf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "vendor/nanopb"] path = vendor/nanopb url = https://github.com/nanopb/nanopb.git +[submodule "python-trezor"] + path = vendor/python-trezor + url = https://github.com/trezor/python-trezor.git diff --git a/.travis.yml b/.travis.yml index 1b354cfec4..4301fd031c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,13 +26,8 @@ install: - pip2 install --user "protobuf==${PROTOBUF_VERSION}" script: - - make -C vendor/libopencm3 lib/stm32/f2 - - make -C vendor/nanopb/generator/proto - - make + - script/cibuild - make -C bootloader - - make -C fastflash - - make -C firmware/protob - - make -C firmware - make -C demo notifications: diff --git a/script/bootstrap b/script/bootstrap new file mode 100755 index 0000000000..4f687bf0eb --- /dev/null +++ b/script/bootstrap @@ -0,0 +1,10 @@ +#!/bin/bash + +# script/bootstrap: Resolve all dependencies that the application requires to +# run. + +set -e + +cd "$(dirname "$0")/.." + +git submodule update --init diff --git a/script/cibuild b/script/cibuild new file mode 100755 index 0000000000..023969661f --- /dev/null +++ b/script/cibuild @@ -0,0 +1,25 @@ +#!/bin/bash + +# script/cibuild: Setup environment for CI to run tests. This is primarily +# designed to run on the continuous integration server. + +set -e + +cd "$(dirname "$0")/.." + +if [ "$EMULATOR" = 1 ]; then + make -C emulator +else + make -C vendor/libopencm3 lib/stm32/f2 +fi + +make + +if [ "$FASTFLASH" = 1 ]; then + make -C fastflash +fi + +make -C vendor/nanopb/generator/proto +make -C firmware/protob + +make -C firmware diff --git a/script/setup b/script/setup new file mode 100755 index 0000000000..704168ece6 --- /dev/null +++ b/script/setup @@ -0,0 +1,13 @@ +#!/bin/bash + +# script/setup: Set up application for the first time after cloning, or set it +# back to the initial first unused state. + +set -e + +cd "$(dirname "$0")/.." + +script/bootstrap + +git clean -fdX +git submodule foreach git clean -fdX diff --git a/script/test b/script/test new file mode 100755 index 0000000000..0c8e68d2b5 --- /dev/null +++ b/script/test @@ -0,0 +1,20 @@ +#!/bin/bash + +# script/test: Run test suite for application. + +set -e + +cd "$(dirname "$0")/.." + +# Kill jobs on exit +trap "exit" INT TERM +trap "kill 0" EXIT + +if [ "$EMULATOR" = 1 ]; then + firmware/trezor.elf & +fi + +TREZOR_TRANSPORT_V1=1 pytest "vendor/python-trezor/tests/device_tests" & + +# Wait for either job to exit and kill the other +wait -n diff --git a/vendor/python-trezor b/vendor/python-trezor new file mode 160000 index 0000000000..90c49e3386 --- /dev/null +++ b/vendor/python-trezor @@ -0,0 +1 @@ +Subproject commit 90c49e3386ee9391c2a57e2ca0a40f8a909a47cc From 226999d5b47d575c7940fc925a959dc02379d17d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 17 Dec 2017 16:04:02 +0000 Subject: [PATCH 0691/1154] Travis CI: Run tests on emulator --- .travis.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4301fd031c..5b124df90d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,23 @@ env: - DEBUG_LINK=0 FASTFLASH=1 - DEBUG_LINK=1 FASTFLASH=1 +matrix: + include: + - addons: + apt: + packages: + - gcc-multilib + env: + - EMULATOR=1 HEADLESS=1 + - DEBUG_LINK=1 + before_script: + - sed -i '/hidapi/d' "vendor/python-trezor/requirements.txt" + - pip install --user --requirement "vendor/python-trezor/requirements.txt" rlp pytest + - pip install --user --no-deps "vendor/python-trezor" + script: + - script/cibuild + - script/test + install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc From 1f2e5e2a9139adaa33f6480b8e70eb911c2b498d Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 17 Dec 2017 16:30:02 +0000 Subject: [PATCH 0692/1154] Travis CI: Fix InsecurePlatformWarning --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5b124df90d..94f1ce8387 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ matrix: - DEBUG_LINK=1 before_script: - sed -i '/hidapi/d' "vendor/python-trezor/requirements.txt" - - pip install --user --requirement "vendor/python-trezor/requirements.txt" rlp pytest + - pip install --user --requirement "vendor/python-trezor/requirements.txt" rlp pytest requests[security] - pip install --user --no-deps "vendor/python-trezor" script: - script/cibuild From becb31c4fc09c5ed8dcb1f1f8f642dde33c39613 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 17 Dec 2017 18:26:00 +0000 Subject: [PATCH 0693/1154] script: Do not start emulator if running --- script/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/test b/script/test index 0c8e68d2b5..9306b7d082 100755 --- a/script/test +++ b/script/test @@ -10,7 +10,7 @@ cd "$(dirname "$0")/.." trap "exit" INT TERM trap "kill 0" EXIT -if [ "$EMULATOR" = 1 ]; then +if [ "$EMULATOR" = 1 ] && [ -z "$(pidof trezor.elf)" ]; then firmware/trezor.elf & fi From 5b92680cfb232e5cb176db0c5f6912abc3d2e1cc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 18:38:34 +0000 Subject: [PATCH 0694/1154] README: Use Markdown syntax for links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2b84ad2b5f..e574eeb326 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ https://trezor.io/ ## How to build TREZOR firmware? -1. Install Docker +1. [Install Docker](https://docs.docker.com/engine/installation/) 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` 4. `./build-firmware.sh TAG` (where TAG is v1.5.0 for example, if left blank the script builds latest commit in master branch) @@ -15,7 +15,7 @@ This creates file `build/trezor-TAG.bin` and prints its fingerprint and size at ## How to build TREZOR bootloader? -1. Install Docker +1. [Install Docker](https://docs.docker.com/engine/installation/) 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` 4. `./build-bootloader.sh TAG` (where TAG is bl1.3.2 for example, if left blank the script builds latest commit in master branch) @@ -34,5 +34,5 @@ Step 3 should produce the same sha256 fingerprint like your local build (for the **WARNING: This will erase the recovery seed stored on the device! You should never do this on TREZOR that contains coins!** -1. Install python-trezor: `pip install trezor` (more info) +1. Install python-trezor: `pip install trezor` ([more info](https://github.com/trezor/python-trezor)) 2. `trezorctl firmware_update -f build/trezor-TAG.bin` From 8fceb961e4343bd1254400b4e16dd8e7dbf2f3bc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 18:38:42 +0000 Subject: [PATCH 0695/1154] README: Add development instructions --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index e574eeb326..6485ef0c1e 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,22 @@ Step 3 should produce the same sha256 fingerprint like your local build (for the 1. Install python-trezor: `pip install trezor` ([more info](https://github.com/trezor/python-trezor)) 2. `trezorctl firmware_update -f build/trezor-TAG.bin` + +## Building for development + +If you want to build device firmware, make sure you have the +[GNU ARM Embedded toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) installed. + +* If you want to build the emulator instead of the firmware, run `export EMULATOR=1 TREZOR_TRANSPORT_V1=1` +* If you want to build with the debug link, run `export DEBUG_LINK=1`. Use this if you want to run the device tests. +* When you change these variables, use `script/setup` to clean the repository + +1. To initialize the repository, run `script/setup` +2. To build the firmware or emulator, run `script/cibuild` + +If you are building device firmware, the firmware will be in `firmware/trezor.bin`. + +You can launch the emulator using `firmware/trezor.elf`. To use `trezorctl` with the emulator, use +`trezorctl -t udp` (for example, `trezorctl -t udp get_features`). + +If `trezorctl -t udp` appears to hang, make sure you have run `export TREZOR_TRANSPORT_V1=1`. From b92a0d24b0c3387b7ffb46a54f99f933d00eb6b9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 11 Dec 2017 18:15:31 +0000 Subject: [PATCH 0696/1154] fsm: Include file and line in fsm_sendFailure for DEBUG_LINK --- firmware/fsm.c | 12 ++++++++++++ firmware/fsm.h | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 15359c8a33..f88e3710a7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -106,7 +106,11 @@ void fsm_sendSuccess(const char *text) msg_write(MessageType_MessageType_Success, resp); } +#if DEBUG_LINK +void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) +#else void fsm_sendFailure(FailureType code, const char *text) +#endif { if (protectAbortedByInitialize) { fsm_msgInitialize((Initialize *)0); @@ -156,10 +160,18 @@ void fsm_sendFailure(FailureType code, const char *text) break; } } +#if DEBUG_LINK + resp->has_message = true; + strlcpy(resp->message, source, sizeof(resp->message)); + if (text) { + strlcat(resp->message, text, sizeof(resp->message)); + } +#else if (text) { resp->has_message = true; strlcpy(resp->message, text, sizeof(resp->message)); } +#endif msg_write(MessageType_MessageType_Failure, resp); } diff --git a/firmware/fsm.h b/firmware/fsm.h index b91129a34d..24861a2f07 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -25,7 +25,14 @@ // message functions void fsm_sendSuccess(const char *text); + +#if DEBUG_LINK +void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); + +#define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") +#else void fsm_sendFailure(FailureType code, const char *text); +#endif void fsm_msgInitialize(Initialize *msg); void fsm_msgGetFeatures(GetFeatures *msg); From bb1c42b16cb9a9a5c21f9dc86a0c019ded5d4d32 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Dec 2017 21:38:31 +0100 Subject: [PATCH 0697/1154] vendor: remove python-trezor submodule for now --- .gitmodules | 3 --- .travis.yml | 7 ++++--- script/test | 6 +++++- vendor/python-trezor | 1 - 4 files changed, 9 insertions(+), 8 deletions(-) delete mode 160000 vendor/python-trezor diff --git a/.gitmodules b/.gitmodules index 7b3b203bcf..920894a059 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,6 +13,3 @@ [submodule "vendor/nanopb"] path = vendor/nanopb url = https://github.com/nanopb/nanopb.git -[submodule "python-trezor"] - path = vendor/python-trezor - url = https://github.com/trezor/python-trezor.git diff --git a/.travis.yml b/.travis.yml index 94f1ce8387..34a15cd19c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,9 +29,10 @@ matrix: - EMULATOR=1 HEADLESS=1 - DEBUG_LINK=1 before_script: - - sed -i '/hidapi/d' "vendor/python-trezor/requirements.txt" - - pip install --user --requirement "vendor/python-trezor/requirements.txt" rlp pytest requests[security] - - pip install --user --no-deps "vendor/python-trezor" + - pip install --user pytest + - pip install --user ecdsa mnemonic + - pip install --user rlp requests[security] + - pip install --user --no-deps git+https://github.com/trezor/python-trezor@master script: - script/cibuild - script/test diff --git a/script/test b/script/test index 9306b7d082..460b711b85 100755 --- a/script/test +++ b/script/test @@ -6,6 +6,10 @@ set -e cd "$(dirname "$0")/.." +if [ \! -d device_tests ]; then + curl -s -L https://github.com/trezor/python-trezor/archive/master.tar.gz | tar -xvz --strip-components=2 python-trezor-master/tests/device_tests +fi + # Kill jobs on exit trap "exit" INT TERM trap "kill 0" EXIT @@ -14,7 +18,7 @@ if [ "$EMULATOR" = 1 ] && [ -z "$(pidof trezor.elf)" ]; then firmware/trezor.elf & fi -TREZOR_TRANSPORT_V1=1 pytest "vendor/python-trezor/tests/device_tests" & +TREZOR_TRANSPORT_V1=1 pytest "device_tests" & # Wait for either job to exit and kill the other wait -n diff --git a/vendor/python-trezor b/vendor/python-trezor deleted file mode 160000 index 90c49e3386..0000000000 --- a/vendor/python-trezor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 90c49e3386ee9391c2a57e2ca0a40f8a909a47cc From 045ef22d98e22a19971ad8f6787241a940c2463b Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 21:16:05 +0000 Subject: [PATCH 0698/1154] storage: Do not use Nanopb --- firmware/Makefile | 1 - firmware/fsm.c | 2 +- firmware/protob/Makefile | 2 +- firmware/protob/storage.options | 5 --- firmware/protob/storage.proto | 1 - firmware/storage.c | 55 +++++++++++++++++++++++++-------- firmware/storage.h | 55 +++++++++++++++++++++++++++++++-- 7 files changed, 97 insertions(+), 24 deletions(-) delete mode 100644 firmware/protob/storage.options delete mode 120000 firmware/protob/storage.proto diff --git a/firmware/Makefile b/firmware/Makefile index 577d20e34d..714a823d00 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -79,7 +79,6 @@ OBJS += ../vendor/trezor-qrenc/qr_encode.o OBJS += protob/pb_decode.o OBJS += protob/pb_encode.o OBJS += protob/messages.pb.o -OBJS += protob/storage.pb.o OBJS += protob/types.pb.o include ../Makefile.include diff --git a/firmware/fsm.c b/firmware/fsm.c index f88e3710a7..b57d4225f9 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1627,7 +1627,7 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) if (storage_hasNode()) { resp.has_node = true; - memcpy(&(resp.node), storage_getNode(), sizeof(HDNode)); + storage_dumpNode(&(resp.node)); } resp.has_passphrase_protection = true; diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 34a4739bb3..8dc4c38fd8 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,4 +1,4 @@ -all: messages.pb.c storage.pb.c types.pb.c messages_map.h +all: messages.pb.c types.pb.c messages_map.h %.pb.c: %.pb %.options ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T diff --git a/firmware/protob/storage.options b/firmware/protob/storage.options deleted file mode 100644 index b7b6db2e95..0000000000 --- a/firmware/protob/storage.options +++ /dev/null @@ -1,5 +0,0 @@ -Storage.mnemonic max_size:241 -Storage.pin max_size:10 -Storage.language max_size:17 -Storage.label max_size:33 -Storage.homescreen max_size:1024 diff --git a/firmware/protob/storage.proto b/firmware/protob/storage.proto deleted file mode 120000 index 7502e62f6d..0000000000 --- a/firmware/protob/storage.proto +++ /dev/null @@ -1 +0,0 @@ -../../vendor/trezor-common/protob/storage.proto \ No newline at end of file diff --git a/firmware/storage.c b/firmware/storage.c index 8b982ea1ac..04e705d2e4 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -23,7 +23,6 @@ #include #include "messages.pb.h" -#include "storage.pb.h" #include "trezor.h" #include "sha2.h" @@ -278,7 +277,7 @@ static void get_u2froot_callback(uint32_t iter, uint32_t total) layoutProgress(_("Updating"), 1000 * iter / total); } -static void storage_compute_u2froot(const char* mnemonic, HDNodeType *u2froot) { +static void storage_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { static CONFIDENTIAL HDNode node; char oldTiny = usbTiny(1); mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 @@ -312,11 +311,11 @@ static void storage_commit_locked(bool update) storageUpdate.version = STORAGE_VERSION; if (!storageUpdate.has_node && !storageUpdate.has_mnemonic) { storageUpdate.has_node = storageRom->has_node; - memcpy(&storageUpdate.node, &storageRom->node, sizeof(HDNodeType)); + memcpy(&storageUpdate.node, &storageRom->node, sizeof(StorageHDNode)); storageUpdate.has_mnemonic = storageRom->has_mnemonic; strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); storageUpdate.has_u2froot = storageRom->has_u2froot; - memcpy(&storageUpdate.u2froot, &storageRom->u2froot, sizeof(HDNodeType)); + memcpy(&storageUpdate.u2froot, &storageRom->u2froot, sizeof(StorageHDNode)); } else if (storageUpdate.has_mnemonic) { storageUpdate.has_u2froot = true; storage_compute_u2froot(storageUpdate.mnemonic, &storageUpdate.u2froot); @@ -406,6 +405,38 @@ void storage_update(void) storage_check_flash_errors(); } +static void storage_setNode(const HDNodeType *node) { + storageUpdate.node.depth = node->depth; + storageUpdate.node.fingerprint = node->fingerprint; + storageUpdate.node.child_num = node->child_num; + + storageUpdate.node.chain_code.size = 32; + memcpy(storageUpdate.node.chain_code.bytes, node->chain_code.bytes, 32); + + if (node->has_private_key) { + storageUpdate.node.has_private_key = true; + storageUpdate.node.private_key.size = 32; + memcpy(storageUpdate.node.private_key.bytes, node->private_key.bytes, 32); + } +} + +#if DEBUG_LINK +void storage_dumpNode(HDNodeType *node) { + node->depth = storageRom->node.depth; + node->fingerprint = storageRom->node.fingerprint; + node->child_num = storageRom->node.child_num; + + node->chain_code.size = 32; + memcpy(node->chain_code.bytes, storageRom->node.chain_code.bytes, 32); + + if (storageRom->node.has_private_key) { + node->has_private_key = true; + node->private_key.size = 32; + memcpy(node->private_key.bytes, storageRom->node.private_key.bytes, 32); + } +} +#endif + void storage_loadDevice(LoadDevice *msg) { session_clear(true); @@ -419,7 +450,7 @@ void storage_loadDevice(LoadDevice *msg) if (msg->has_node) { storageUpdate.has_node = true; storageUpdate.has_mnemonic = false; - memcpy(&storageUpdate.node, &(msg->node), sizeof(HDNodeType)); + storage_setNode(&(msg->node)); sessionSeedCached = false; memset(&sessionSeed, 0, sizeof(sessionSeed)); } else if (msg->has_mnemonic) { @@ -526,10 +557,13 @@ const uint8_t *storage_getSeed(bool usePassphrase) return NULL; } +static bool storage_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { + return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); +} + bool storage_getU2FRoot(HDNode *node) { - return storageRom->has_u2froot - && hdnode_from_xprv(storageRom->u2froot.depth, storageRom->u2froot.child_num, storageRom->u2froot.chain_code.bytes, storageRom->u2froot.private_key.bytes, NIST256P1_NAME, node); + return storageRom->has_u2froot && storage_loadNode(&storageRom->u2froot, NIST256P1_NAME, node); } bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) @@ -539,7 +573,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) if (!protectPassphrase()) { return false; } - if (hdnode_from_xprv(storageRom->node.depth, storageRom->node.child_num, storageRom->node.chain_code.bytes, storageRom->node.private_key.bytes, curve, node) == 0) { + if (!storage_loadNode(&storageRom->node, curve, node)) { return false; } if (storageRom->has_passphrase_protection && storageRom->passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { @@ -595,11 +629,6 @@ bool storage_hasNode(void) return storageRom->has_node; } -const HDNode *storage_getNode(void) -{ - return storageRom->has_node ? (const HDNode *)&storageRom->node : 0; -} - bool storage_hasMnemonic(void) { return storageRom->has_mnemonic; diff --git a/firmware/storage.h b/firmware/storage.h index 9d7935258f..a8a883299b 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -21,10 +21,59 @@ #define __STORAGE_H__ #include "types.pb.h" -#include "storage.pb.h" #include "messages.pb.h" #include "bip32.h" +#define STORAGE_FIELD(TYPE, NAME) \ + bool has_##NAME; \ + TYPE NAME; + +#define STORAGE_STRING(NAME, SIZE) \ + bool has_##NAME; \ + char NAME[SIZE]; + +#define STORAGE_BYTES(NAME, SIZE) \ + bool has_##NAME; \ + struct { \ + size_t size; \ + uint8_t bytes[SIZE]; \ + } NAME; + +#define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME) +#define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME) +#define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME) + +typedef struct { + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + struct { + size_t size; + uint8_t bytes[32]; + } chain_code; + + STORAGE_BYTES(private_key, 32); + STORAGE_BYTES(public_key, 33); +} StorageHDNode; + +typedef struct _Storage { + uint32_t version; + + STORAGE_NODE (node) + STORAGE_STRING (mnemonic, 241) + STORAGE_BOOL (passphrase_protection) + STORAGE_UINT32 (pin_failed_attempts) + STORAGE_STRING (pin, 10) + STORAGE_STRING (language, 17) + STORAGE_STRING (label, 33) + STORAGE_BOOL (imported) + STORAGE_BYTES (homescreen, 1024) + STORAGE_UINT32 (u2f_counter) + STORAGE_BOOL (needs_backup) + STORAGE_UINT32 (flags) + STORAGE_NODE (u2froot) +} Storage; + extern Storage storageUpdate; void storage_init(void); @@ -61,7 +110,9 @@ bool storage_hasMnemonic(void); const char *storage_getMnemonic(void); bool storage_hasNode(void); -const HDNode *storage_getNode(void); +#if DEBUG_LINK +void storage_dumpNode(HDNodeType *node); +#endif bool storage_containsPin(const char *pin); bool storage_hasPin(void); From bab8db91919e23acd12e394c35a78113e4754099 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 21:33:58 +0000 Subject: [PATCH 0699/1154] vendor: Update Nanopb to 0.3.9 --- firmware/Makefile | 9 +++++---- firmware/protob/pb.h | 1 - firmware/protob/pb_decode.c | 1 - firmware/protob/pb_decode.h | 1 - firmware/protob/pb_encode.c | 1 - firmware/protob/pb_encode.h | 1 - firmware/transaction.c | 14 ++++++++++++-- vendor/nanopb | 2 +- 8 files changed, 18 insertions(+), 12 deletions(-) delete mode 120000 firmware/protob/pb.h delete mode 120000 firmware/protob/pb_decode.c delete mode 120000 firmware/protob/pb_decode.h delete mode 120000 firmware/protob/pb_encode.c delete mode 120000 firmware/protob/pb_encode.h diff --git a/firmware/Makefile b/firmware/Makefile index 714a823d00..124f6556b0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -75,9 +75,10 @@ OBJS += ../vendor/trezor-crypto/nem.o OBJS += ../vendor/trezor-qrenc/qr_encode.o -# OBJS += protob/pb_common.o -OBJS += protob/pb_decode.o -OBJS += protob/pb_encode.o +OBJS += ../vendor/nanopb/pb_common.o +OBJS += ../vendor/nanopb/pb_decode.o +OBJS += ../vendor/nanopb/pb_encode.o + OBJS += protob/messages.pb.o OBJS += protob/types.pb.o @@ -93,7 +94,7 @@ DEBUG_LINK ?= 0 DEBUG_LOG ?= 0 CFLAGS += -Wno-sequence-point -CFLAGS += -Iprotob -DPB_FIELD_16BIT=1 +CFLAGS += -I../vendor/nanopb -Iprotob -DPB_FIELD_16BIT=1 CFLAGS += -DQR_MAX_VERSION=0 CFLAGS += -DDEBUG_LINK=$(DEBUG_LINK) CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) diff --git a/firmware/protob/pb.h b/firmware/protob/pb.h deleted file mode 120000 index 835188c421..0000000000 --- a/firmware/protob/pb.h +++ /dev/null @@ -1 +0,0 @@ -../../vendor/nanopb/pb.h \ No newline at end of file diff --git a/firmware/protob/pb_decode.c b/firmware/protob/pb_decode.c deleted file mode 120000 index 1114e7da0b..0000000000 --- a/firmware/protob/pb_decode.c +++ /dev/null @@ -1 +0,0 @@ -../../vendor/nanopb/pb_decode.c \ No newline at end of file diff --git a/firmware/protob/pb_decode.h b/firmware/protob/pb_decode.h deleted file mode 120000 index d25f0ac14e..0000000000 --- a/firmware/protob/pb_decode.h +++ /dev/null @@ -1 +0,0 @@ -../../vendor/nanopb/pb_decode.h \ No newline at end of file diff --git a/firmware/protob/pb_encode.c b/firmware/protob/pb_encode.c deleted file mode 120000 index aebfbfda3a..0000000000 --- a/firmware/protob/pb_encode.c +++ /dev/null @@ -1 +0,0 @@ -../../vendor/nanopb/pb_encode.c \ No newline at end of file diff --git a/firmware/protob/pb_encode.h b/firmware/protob/pb_encode.h deleted file mode 120000 index 04b7546e4a..0000000000 --- a/firmware/protob/pb_encode.h +++ /dev/null @@ -1 +0,0 @@ -../../vendor/nanopb/pb_encode.h \ No newline at end of file diff --git a/firmware/transaction.c b/firmware/transaction.c index 2e8f24664c..2e7bbbbaf8 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -56,8 +56,18 @@ static const uint8_t segwit_header[2] = {0,1}; -#define op_push_size(len) ((len) < 0x4c ? 1 : (len) < 0x100 ? 2 : \ - (len) < 0x10000 ? 3 : 5) +static inline uint32_t op_push_size(uint32_t i) { + if (i < 0x4C) { + return 1; + } + if (i < 0x100) { + return 2; + } + if (i < 0x10000) { + return 3; + } + return 5; +} uint32_t op_push(uint32_t i, uint8_t *out) { if (i < 0x4C) { diff --git a/vendor/nanopb b/vendor/nanopb index 54c34a9fda..71ba4e68da 160000 --- a/vendor/nanopb +++ b/vendor/nanopb @@ -1 +1 @@ -Subproject commit 54c34a9fda152937d4cd0c7fd85c067fca23af75 +Subproject commit 71ba4e68da4b3c986d454e34c4666a82fbdf4176 From 7aadc1eddaa2c442c90e8c00c0b0bfbd3bc93b48 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 21:44:50 +0000 Subject: [PATCH 0700/1154] script: Refactor test --- .gitignore | 1 + script/test | 15 +++------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 8a121b9628..c09223a1c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.cache/ _attic/ build/ *.o diff --git a/script/test b/script/test index 460b711b85..69e098d9b5 100755 --- a/script/test +++ b/script/test @@ -6,19 +6,10 @@ set -e cd "$(dirname "$0")/.." -if [ \! -d device_tests ]; then - curl -s -L https://github.com/trezor/python-trezor/archive/master.tar.gz | tar -xvz --strip-components=2 python-trezor-master/tests/device_tests -fi +if [ "$EMULATOR" = 1 ]; then + trap "kill %1" EXIT -# Kill jobs on exit -trap "exit" INT TERM -trap "kill 0" EXIT - -if [ "$EMULATOR" = 1 ] && [ -z "$(pidof trezor.elf)" ]; then firmware/trezor.elf & fi -TREZOR_TRANSPORT_V1=1 pytest "device_tests" & - -# Wait for either job to exit and kill the other -wait -n +TREZOR_TRANSPORT_V1=1 "${PYTHON:-python}" -m pytest --pyarg trezorlib.tests.device_tests "$@" From fd57b899020d5566727376bc943cac7041a3b08e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 21:48:52 +0000 Subject: [PATCH 0701/1154] Makefile: Use $PYTHON --- Makefile.include | 2 ++ firmware/Makefile | 6 +++--- firmware/nem_mosaics.py | 5 +++++ firmware/protob/Makefile | 6 ++++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Makefile.include b/Makefile.include index 5f1aa605a8..0759cf7267 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,6 +1,8 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 +PYTHON ?= python + ifeq ($(EMULATOR),1) CC = gcc LD = gcc diff --git a/firmware/Makefile b/firmware/Makefile index 124f6556b0..4ba08837c5 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -110,13 +110,13 @@ bootloader.o: ../fastflash/bootloader.bin $< $@ coins_count.h: coins-gen.py coins.json - ./$< count > $@ + $(PYTHON) $< count > $@ coins_array.h: coins-gen.py coins.json - ./$< array > $@ + $(PYTHON) $< array > $@ nem_mosaics.c nem_mosaics.h: nem_mosaics.py nem_mosaics.json - ./$< + $(PYTHON) $< clean:: rm -f coins_count.h coins_array.h diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index cb652067ba..c2bd6d0292 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -9,6 +9,11 @@ from itertools import chain sys.path.insert(0, os.path.join(os.path.dirname(__file__), "protob")) import types_pb2 as types +try: + basestring +except NameError: + basestring = (str, bytes) + HEADER_TEMPLATE = """ // This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 8dc4c38fd8..5a3327f96e 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,7 +1,9 @@ all: messages.pb.c types.pb.c messages_map.h +PYTHON ?= python + %.pb.c: %.pb %.options - ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T + $(PYTHON) ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T %.pb: %.proto protoc -I/usr/include -I. $< -o $@ @@ -10,7 +12,7 @@ all: messages.pb.c types.pb.c messages_map.h protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py types_pb2.py - ./$< > $@ + $(PYTHON) $< > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From 73c6cf22adc798412b1f3a85a9bbe3c26cefedc5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 21:48:52 +0000 Subject: [PATCH 0702/1154] Travis CI: Use Python 3 --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34a15cd19c..04eecc7c62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,12 @@ addons: - build-essential - gcc-arm-none-eabi - libnewlib-arm-none-eabi + - python3-pip env: global: - MAKEFLAGS=-j2 + - PYTHON=python3 - PROTOBUF_VERSION=3.4.0 matrix: - DEBUG_LINK=0 FASTFLASH=0 @@ -25,14 +27,15 @@ matrix: apt: packages: - gcc-multilib + - python3-pip env: - EMULATOR=1 HEADLESS=1 - DEBUG_LINK=1 before_script: - - pip install --user pytest - - pip install --user ecdsa mnemonic - - pip install --user rlp requests[security] - - pip install --user --no-deps git+https://github.com/trezor/python-trezor@master + - $PYTHON -m pip install --user pytest + - $PYTHON -m pip install --user ecdsa mnemonic + - $PYTHON -m pip install --user rlp + - $PYTHON -m pip install --user --no-deps git+https://github.com/trezor/python-trezor@master script: - script/cibuild - script/test @@ -41,7 +44,7 @@ install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc - export PATH="$(pwd)/protoc/bin:$PATH" - - pip2 install --user "protobuf==${PROTOBUF_VERSION}" + - $PYTHON -m pip install --user "protobuf==${PROTOBUF_VERSION}" script: - script/cibuild From 4f26db43e3f1df70f1957ced33e82ea02cf36f84 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Dec 2017 14:20:13 +0100 Subject: [PATCH 0703/1154] travis: skip decred test for now --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04eecc7c62..7db35caebb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ matrix: - $PYTHON -m pip install --user --no-deps git+https://github.com/trezor/python-trezor@master script: - script/cibuild - - script/test + - script/test -k 'not test_send_decred' install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 556add6a7466c984cb08289fd092bb88ff7ede07 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Dec 2017 19:35:23 +0100 Subject: [PATCH 0704/1154] tests: use marker, not function name --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7db35caebb..89fd55befa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ matrix: - $PYTHON -m pip install --user --no-deps git+https://github.com/trezor/python-trezor@master script: - script/cibuild - - script/test -k 'not test_send_decred' + - script/test -k 'not skip_t1' install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 58d2079b5680db978c94fb5e491bdd085d454648 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 13:24:37 +0000 Subject: [PATCH 0705/1154] transaction: Fix uninitialized read in compile_output --- firmware/transaction.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index 2e7bbbbaf8..8cbe21c53e 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -232,8 +232,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; if (coin->has_address_type // p2pkh - && address_check_prefix(addr_raw, coin->address_type) - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))) { + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) + && address_check_prefix(addr_raw, coin->address_type)) { out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes @@ -242,8 +242,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.size = 25; } else if (coin->has_address_type_p2sh // p2sh - && address_check_prefix(addr_raw, coin->address_type_p2sh) - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))) { + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh)) + && address_check_prefix(addr_raw, coin->address_type_p2sh)) { out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); From 78bc7377a00ca467ecb4cebb580524e70460617c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 13:46:17 +0000 Subject: [PATCH 0706/1154] Makefile.include: Refactor and support other compilers --- Makefile.include | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/Makefile.include b/Makefile.include index 0759cf7267..874e6caedb 100644 --- a/Makefile.include +++ b/Makefile.include @@ -4,26 +4,27 @@ TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 PYTHON ?= python ifeq ($(EMULATOR),1) -CC = gcc -LD = gcc -OBJCOPY = objcopy -OBJDUMP = objdump -AR = ar -AS = as +CC ?= gcc +LD := $(CC) +OBJCOPY := objcopy +OBJDUMP := objdump +AR := ar +AS := as OPTFLAGS ?= -O3 -DBGFLAGS ?= -g3 +DBGFLAGS ?= -g3 -ggdb3 CPUFLAGS ?= -m32 +FPUFLAGS ?= else -PREFIX ?= arm-none-eabi- -CC = $(PREFIX)gcc -LD = $(PREFIX)gcc -OBJCOPY = $(PREFIX)objcopy -OBJDUMP = $(PREFIX)objdump -AR = $(PREFIX)ar -AS = $(PREFIX)as -FLASH = st-flash -OPENOCD = openocd +PREFIX ?= arm-none-eabi- +CC := $(PREFIX)gcc +LD := $(PREFIX)gcc +OBJCOPY := $(PREFIX)objcopy +OBJDUMP := $(PREFIX)objdump +AR := $(PREFIX)ar +AS := $(PREFIX)as +FLASH := st-flash +OPENOCD := openocd OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG @@ -70,6 +71,11 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc +LDFLAGS += -L$(TOP_DIR) \ + $(DBGFLAGS) \ + $(CPUFLAGS) \ + $(FPUFLAGS) + ifeq ($(EMULATOR),1) CFLAGS += -DEMULATOR=1 @@ -85,9 +91,7 @@ endif CFLAGS += -include $(TOP_DIR)emulator/emulator.h CFLAGS += -include stdio.h -LDFLAGS += -L$(TOP_DIR) \ - -L$(TOP_DIR)emulator \ - $(CPUFLAGS) +LDFLAGS += -L$(TOP_DIR)emulator LDLIBS += -ltrezor -lemulator LIBDEPS += $(TOP_DIR)/libtrezor.a $(TOP_DIR)emulator/libemulator.a @@ -107,13 +111,10 @@ LDFLAGS += --static \ -lgcc \ -lnosys \ -Wl,--end-group \ - -L$(TOP_DIR) \ -L$(TOOLCHAIN_DIR)/lib \ -T$(LDSCRIPT) \ -nostartfiles \ - -Wl,--gc-sections \ - $(CPUFLAGS) \ - $(FPUFLAGS) + -Wl,--gc-sections LDLIBS += -ltrezor LIBDEPS += $(TOP_DIR)/libtrezor.a From 6a2b92c49e7ca04059640c268f1409f5257c916e Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 13:48:16 +0000 Subject: [PATCH 0707/1154] storage: Fix for Clang --- firmware/storage.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 04e705d2e4..1d33e48f7f 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -46,12 +46,18 @@ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t static uint32_t storage_uuid[12 / sizeof(uint32_t)]; +#ifndef __clang__ +// TODO: Fix this for Clang _Static_assert(((uint32_t)storage_uuid & 3) == 0, "uuid unaligned"); _Static_assert((sizeof(storage_uuid) & 3) == 0, "uuid unaligned"); +#endif Storage CONFIDENTIAL storageUpdate; +#ifndef __clang__ +// TODO: Fix this for Clang _Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); _Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); +#endif #define STORAGE_ROM ((const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid))) @@ -461,7 +467,7 @@ void storage_loadDevice(LoadDevice *msg) memset(&sessionSeed, 0, sizeof(sessionSeed)); } - if (msg->has_language && msg->language) { + if (msg->has_language) { storageUpdate.has_language = true; strlcpy(storageUpdate.language, msg->language, sizeof(storageUpdate.language)); } From 94fcc8c9a49d0320868271cc9ea5de93af8579a9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 Jan 2018 22:30:03 +0100 Subject: [PATCH 0708/1154] add bip84 (native segwit) --- firmware/fsm.c | 24 +++++++++++++++++++----- firmware/layout2.c | 18 +++++++++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index b57d4225f9..d385787790 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -686,7 +686,7 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) // m / purpose' / coin_type' / account' / change / address_index if (msg->address_n[0] == (0x80000000 + 44)) { mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); - mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; @@ -698,18 +698,18 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) // m / purpose' / cosigner_index / change / address_index if (msg->address_n[0] == (0x80000000 + 45)) { mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count == 4); + mismatch |= (msg->address_n_count != 4); mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; return mismatch; } - // m/45' - BIP48 Copay Multisig P2SH + // m/48' - BIP48 Copay Multisig P2SH // m / purpose' / coin_type' / account' / change / address_index if (msg->address_n[0] == (0x80000000 + 48)) { mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; @@ -723,7 +723,21 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); mismatch |= !coin->has_segwit; mismatch |= !coin->has_address_type_p2sh; - mismatch |= (msg->address_n_count == 5); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/84' : BIP84 Native SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 84)) { + mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->bech32_prefix; + mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; diff --git a/firmware/layout2.c b/firmware/layout2.c index bb86b9aac0..d2d6649809 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -356,16 +356,22 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou // known BIP44/49 path static char path[100]; if (address_n_count == 5 && - (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49)) && + (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) && (address_n[1] & 0x80000000) && (address_n[2] & 0x80000000) && (address_n[3] <= 1) && (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { - bool segwit = (address_n[0] == (0x80000000 + 49)); + bool native_segwit = (address_n[0] == (0x80000000 + 84)); + bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); bool legacy = false; const CoinInfo *coin = coinByCoinType(address_n[1]); const char *abbr = 0; - if (segwit) { + if (native_segwit) { + if (coin && coin->has_segwit && coin->bech32_prefix) { + abbr = coin->coin_shortcut + 1; + } + } else + if (p2sh_segwit) { if (coin && coin->has_segwit && coin->has_address_type_p2sh) { abbr = coin->coin_shortcut + 1; } @@ -383,9 +389,15 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou if (abbr && accnum < 100) { memset(path, 0, sizeof(path)); strlcpy(path, abbr, sizeof(path)); + // TODO: how to name accounts? + // currently we have "legacy account", "account" and "segwit account" + // for BIP44/P2PKH, BIP49/P2SH-P2WPKH and BIP84/P2WPKH respectivelly if (legacy) { strlcat(path, " legacy", sizeof(path)); } + if (native_segwit) { + strlcat(path, " segwit", sizeof(path)); + } strlcat(path, " account #", sizeof(path)); char acc[3]; memset(acc, 0, sizeof(acc)); From 7e382fb790cefa8dd19d21538d7251dedbbcd271 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 12 Jan 2018 00:03:55 +0100 Subject: [PATCH 0709/1154] update to python3 --- Dockerfile | 7 ++++--- firmware/coins-gen.py | 2 +- firmware/nem_mosaics.py | 2 +- firmware/protob/messages_map.py | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index c92ec89f51..ac3df0d507 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,11 @@ FROM debian:9 # install build tools and dependencies RUN apt-get update && apt-get install -y \ - build-essential git python python-ecdsa gcc-arm-none-eabi curl -RUN apt-get install -y unzip python-pip + build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" RUN unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d /usr -RUN pip2 install "protobuf==${PROTOBUF_VERSION}" +RUN pip3 install "protobuf==${PROTOBUF_VERSION}" ecdsa + +RUN ln -s python3 /usr/bin/python diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index af5a3a8de1..a184ccd96a 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python from __future__ import print_function import json, sys diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index c2bd6d0292..096d453941 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python import json, os, sys import collections, numbers diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index 78c778b594..6499cfb6aa 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python from collections import defaultdict from messages_pb2 import MessageType from types_pb2 import wire_in, wire_out, wire_debug_in, wire_debug_out, wire_tiny, wire_bootloader From c4e359680301b3a6cf2d75bcd8ea354110e33a3a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Jan 2018 15:20:10 +0100 Subject: [PATCH 0710/1154] update trezor-crypto, adapt firmware to to changes --- Makefile.include | 3 +-- firmware/Makefile | 1 + firmware/crypto.c | 2 +- firmware/fsm.c | 2 +- firmware/nem2.c | 2 +- firmware/storage.c | 2 +- rng.c | 28 ---------------------------- rng.h | 8 +------- vendor/trezor-crypto | 2 +- 9 files changed, 8 insertions(+), 42 deletions(-) diff --git a/Makefile.include b/Makefile.include index 874e6caedb..37f9985b60 100644 --- a/Makefile.include +++ b/Makefile.include @@ -63,12 +63,11 @@ CFLAGS += $(OPTFLAGS) \ $(FPUFLAGS) \ -DSTM32F2 \ -DCONFIDENTIAL='__attribute__((section("confidential")))' \ + -DRAND_PLATFORM_INDEPENDENT=1 \ -I$(TOOLCHAIN_DIR)/include \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ - -I$(TOP_DIR)vendor/trezor-crypto/aes \ - -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \ -I$(TOP_DIR)vendor/trezor-qrenc LDFLAGS += -L$(TOP_DIR) \ diff --git a/firmware/Makefile b/firmware/Makefile index 4ba08837c5..85620caf82 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -40,6 +40,7 @@ OBJS += ../vendor/trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o +OBJS += ../vendor/trezor-crypto/rand.o OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.o OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.o diff --git a/firmware/crypto.c b/firmware/crypto.c index 2d12d9b5d6..cdae90e74f 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -22,7 +22,7 @@ #include "sha2.h" #include "ripemd160.h" #include "pbkdf2.h" -#include "aes.h" +#include "aes/aes.h" #include "hmac.h" #include "bip32.h" #include "layout.h" diff --git a/firmware/fsm.c b/firmware/fsm.c index d385787790..46b0f9f5a5 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -42,7 +42,7 @@ #include "usb.h" #include "util.h" #include "signing.h" -#include "aes.h" +#include "aes/aes.h" #include "hmac.h" #include "crypto.h" #include "base58.h" diff --git a/firmware/nem2.c b/firmware/nem2.c index a2be49c00c..ebe90731f9 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -19,7 +19,7 @@ #include "nem2.h" -#include "aes.h" +#include "aes/aes.h" #include "fsm.h" #include "gettext.h" #include "layout2.h" diff --git a/firmware/storage.c b/firmware/storage.c index 1d33e48f7f..6ccc91d03a 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -26,7 +26,7 @@ #include "trezor.h" #include "sha2.h" -#include "aes.h" +#include "aes/aes.h" #include "pbkdf2.h" #include "bip32.h" #include "bip39.h" diff --git a/rng.c b/rng.c index 145f51b4b5..6576d8bb47 100644 --- a/rng.c +++ b/rng.c @@ -36,31 +36,3 @@ uint32_t random32(void) return new; } #endif - -uint32_t random_uniform(uint32_t n) -{ - uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n); - while ((x = random32()) >= max); - return x / (max / n); -} - -void random_buffer(uint8_t *buf, size_t len) -{ - uint32_t r = 0; - for (size_t i = 0; i < len; i++) { - if (i % 4 == 0) { - r = random32(); - } - buf[i] = (r >> ((i % 4) * 8)) & 0xFF; - } -} - -void random_permute(char *str, size_t len) -{ - for (int i = len - 1; i >= 1; i--) { - int j = random_uniform(i + 1); - char t = str[j]; - str[j] = str[i]; - str[i] = t; - } -} diff --git a/rng.h b/rng.h index f3fa07323a..c28ef22f3a 100644 --- a/rng.h +++ b/rng.h @@ -20,12 +20,6 @@ #ifndef __RNG_H__ #define __RNG_H__ -#include -#include - -uint32_t random32(void); -uint32_t random_uniform(uint32_t n); -void random_buffer(uint8_t *buf, size_t len); -void random_permute(char *buf, size_t len); +#include "rand.h" #endif diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 74e74f5eed..0d8a3beeaf 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 74e74f5eed886ff871dc1fb36088e4b465917689 +Subproject commit 0d8a3beeaf22af837f558a5b5e9ae98cdd47a767 From 59e204fe2b0e4be53c1cb002b48026cf1caf4f9a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 14 Jan 2018 14:55:30 +0100 Subject: [PATCH 0711/1154] fix small bug in oledDrawChar --- oled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oled.c b/oled.c index 569b44864b..0467690aa5 100644 --- a/oled.c +++ b/oled.c @@ -245,7 +245,7 @@ void oledDrawChar(int x, int y, char c, int zoom) int char_width = fontCharWidth(c); const uint8_t *char_data = fontCharData(c); - if (x <= -char_width) { + if (x <= -char_width * zoom) { return; } From f70772fb58126cdca155d2d5a335c605c47b93a6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Jan 2018 18:40:54 +0100 Subject: [PATCH 0712/1154] rework ConfirmOutput layout (fixes #289) --- firmware/coins-gen.py | 2 +- firmware/layout2.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index a184ccd96a..dfd1f8be16 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -14,7 +14,7 @@ if len(sys.argv) != 2 or sys.argv[1] not in ("count", "array"): def get_fields(coin): return [ '"%s"' % coin['coin_name'] if coin['coin_name'] is not None else 'NULL', - '" %s"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', + '" %s to"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', '%d' % coin['maxfee_kb'] if coin['maxfee_kb'] is not None else '0', '"\\x%02x" "%s"' % (len(coin['signed_message_header']), coin['signed_message_header'].replace('\n', '\\n')) if coin['signed_message_header'] is not None else 'NULL', 'true' if coin['address_type'] is not None else 'false', diff --git a/firmware/layout2.c b/firmware/layout2.c index d2d6649809..2d2952f54e 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -132,13 +132,13 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) const char *addr = out->address; int addrlen = strlen(addr); int numlines = addrlen <= 34 ? 2 : 3; - strcpy(lines[0], _("to ")); - int linelen = (addrlen + (numlines == 3 ? 3 : 0) - 1) / numlines + 1; - if (linelen > 27) + int linelen = (addrlen + 3) / numlines + 1; + if (linelen > 27) { linelen = 27; + } if (numlines == 3) { - strlcpy(lines[0] + 3, addr, linelen - 3 + 1); - addr += linelen - 3; + strlcpy(lines[0], addr, linelen + 1); + addr += linelen; } strlcpy(lines[1], addr, linelen + 1); addr += linelen; From cd763b979b0001d4e23fffaf68fa59cfe483a6ba Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Jan 2018 18:56:57 +0100 Subject: [PATCH 0713/1154] layout: fix last commit --- firmware/coins-gen.py | 2 +- firmware/layout2.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py index dfd1f8be16..a184ccd96a 100755 --- a/firmware/coins-gen.py +++ b/firmware/coins-gen.py @@ -14,7 +14,7 @@ if len(sys.argv) != 2 or sys.argv[1] not in ("count", "array"): def get_fields(coin): return [ '"%s"' % coin['coin_name'] if coin['coin_name'] is not None else 'NULL', - '" %s to"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', + '" %s"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', '%d' % coin['maxfee_kb'] if coin['maxfee_kb'] is not None else '0', '"\\x%02x" "%s"' % (len(coin['signed_message_header']), coin['signed_message_header'].replace('\n', '\\n')) if coin['signed_message_header'] is not None else 'NULL', 'true' if coin['address_type'] is not None else 'false', diff --git a/firmware/layout2.c b/firmware/layout2.c index 2d2952f54e..7852460ede 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -126,8 +126,9 @@ void layoutHome(void) void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { - char str_out[32]; - bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); + char str_out[32 + 3]; + bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); + strlcat(str_out, " to", sizeof(str_out)); static char lines[2][28]; const char *addr = out->address; int addrlen = strlen(addr); From 4a2d68acb99f57660230d2e509f01c44db85be10 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Jan 2018 19:49:47 +0100 Subject: [PATCH 0714/1154] use explicit_bzero where possible; update trezor-crypto --- bootloader/usb.c | 8 ++++---- firmware/crypto.c | 1 - firmware/ethereum.c | 4 ++-- firmware/protect.c | 2 +- firmware/recovery.c | 6 +++--- firmware/storage.c | 8 ++++---- vendor/trezor-crypto | 2 +- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index e6d17789dd..db1380685b 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -402,7 +402,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // restore metadata from backup erase_metadata_sectors(); restore_metadata(meta_backup); - memset(meta_backup, 0, sizeof(meta_backup)); + explicit_bzero(meta_backup, sizeof(meta_backup)); // compare against known hash computed via the following Python3 script: // hashlib.sha256(binascii.unhexlify('0F5A693C' * 8192)).hexdigest() @@ -599,7 +599,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // 2) firmware restore flag isn't set // 3) signatures are not ok if (old_was_unsigned || (flags & 0x01) == 0 || !signatures_ok(NULL)) { - memset(meta_backup, 0, sizeof(meta_backup)); + explicit_bzero(meta_backup, sizeof(meta_backup)); } // copy new firmware header memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); @@ -607,12 +607,12 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (hash_check_ok) { memcpy(meta_backup, FIRMWARE_MAGIC, 4); } else { - memset(meta_backup, 0, 4); + explicit_bzero(meta_backup, 4); } // no need to erase, because we are not changing any already flashed byte. restore_metadata(meta_backup); - memset(meta_backup, 0, sizeof(meta_backup)); + explicit_bzero(meta_backup, sizeof(meta_backup)); flash_state = STATE_END; if (hash_check_ok) { diff --git a/firmware/crypto.c b/firmware/crypto.c index cdae90e74f..dae6c4fef4 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -29,7 +29,6 @@ #include "curves.h" #include "secp256k1.h" #include "address.h" -#include "macros.h" #include "coins.h" #include "base58.h" #include "segwit_addr.h" diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 48a8496625..2baf61c6d9 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -193,7 +193,7 @@ static void send_signature(void) return; } - memset(privkey, 0, sizeof(privkey)); + explicit_bzero(privkey, sizeof(privkey)); /* Send back the result */ msg_tx_request.has_data_length = false; @@ -592,7 +592,7 @@ void ethereum_signing_txack(EthereumTxAck *tx) void ethereum_signing_abort(void) { if (ethereum_signing) { - memset(privkey, 0, sizeof(privkey)); + explicit_bzero(privkey, sizeof(privkey)); layoutHome(); ethereum_signing = false; } diff --git a/firmware/protect.c b/firmware/protect.c index 852e0d8b22..019fcf09e7 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -231,7 +231,7 @@ bool protectChangePin(void) storage_update(); } - memset(pin_compare, 0, sizeof(pin_compare)); + explicit_bzero(pin_compare, sizeof(pin_compare)); return result; } diff --git a/firmware/recovery.c b/firmware/recovery.c index ed09deeacc..06014979b0 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -142,7 +142,7 @@ static void recovery_done(void) { if (!dry_run) { // Update mnemonic on storage. storage_setMnemonic(new_mnemonic); - memset(new_mnemonic, 0, sizeof(new_mnemonic)); + explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); if (!enforce_wordlist) { // not enforcing => mark storage as imported storage_setImported(true); @@ -152,7 +152,7 @@ static void recovery_done(void) { } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). bool match = (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)); - memset(new_mnemonic, 0, sizeof(new_mnemonic)); + explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); if (match) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, _("The seed is valid"), @@ -172,7 +172,7 @@ static void recovery_done(void) { } } else { // New mnemonic is invalid. - memset(new_mnemonic, 0, sizeof(new_mnemonic)); + explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); if (!dry_run) { session_clear(true); } else { diff --git a/firmware/storage.c b/firmware/storage.c index 6ccc91d03a..8b9eba92b9 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -262,9 +262,9 @@ void storage_generate_uuid(void) void session_clear(bool clear_pin) { sessionSeedCached = false; - memset(&sessionSeed, 0, sizeof(sessionSeed)); + explicit_bzero(&sessionSeed, sizeof(sessionSeed)); sessionPassphraseCached = false; - memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); + explicit_bzero(&sessionPassphrase, sizeof(sessionPassphrase)); if (clear_pin) { sessionPinCached = false; } @@ -297,7 +297,7 @@ static void storage_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot u2froot->has_private_key = true; u2froot->private_key.size = sizeof(node.private_key); memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - memset(&node, 0, sizeof(node)); + explicit_bzero(&node, sizeof(node)); session_clear(false); // invalidate seed cache } @@ -399,7 +399,7 @@ static void storage_commit_locked(bool update) void storage_clear_update(void) { - memset(&storageUpdate, 0, sizeof(storageUpdate)); + explicit_bzero(&storageUpdate, sizeof(storageUpdate)); } void storage_update(void) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 0d8a3beeaf..b7f73ee3ff 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 0d8a3beeaf22af837f558a5b5e9ae98cdd47a767 +Subproject commit b7f73ee3ff78e09c266a30dbc31407558d471615 From bd660655ee26711bcba8d25d6555cc8246e7e2df Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 18 Jan 2018 15:21:48 +0100 Subject: [PATCH 0715/1154] introduce and use memzero instead of explicit_bzero --- bootloader/Makefile | 1 + bootloader/usb.c | 9 +++++---- firmware/Makefile | 1 + firmware/ethereum.c | 5 +++-- firmware/protect.c | 3 ++- firmware/recovery.c | 7 ++++--- firmware/storage.c | 9 +++++---- vendor/trezor-crypto | 2 +- 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/bootloader/Makefile b/bootloader/Makefile index 6a2dc5f847..72b251ae17 100644 --- a/bootloader/Makefile +++ b/bootloader/Makefile @@ -8,6 +8,7 @@ OBJS += ../vendor/trezor-crypto/bignum.small.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/sha2.small.o +OBJS += ../vendor/trezor-crypto/memzero.small.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 diff --git a/bootloader/usb.c b/bootloader/usb.c index db1380685b..6442ab229d 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -35,6 +35,7 @@ #include "sha2.h" #include "ecdsa.h" #include "secp256k1.h" +#include "memzero.h" #define FIRMWARE_MAGIC "TRZR" @@ -402,7 +403,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // restore metadata from backup erase_metadata_sectors(); restore_metadata(meta_backup); - explicit_bzero(meta_backup, sizeof(meta_backup)); + memzero(meta_backup, sizeof(meta_backup)); // compare against known hash computed via the following Python3 script: // hashlib.sha256(binascii.unhexlify('0F5A693C' * 8192)).hexdigest() @@ -599,7 +600,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // 2) firmware restore flag isn't set // 3) signatures are not ok if (old_was_unsigned || (flags & 0x01) == 0 || !signatures_ok(NULL)) { - explicit_bzero(meta_backup, sizeof(meta_backup)); + memzero(meta_backup, sizeof(meta_backup)); } // copy new firmware header memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); @@ -607,12 +608,12 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) if (hash_check_ok) { memcpy(meta_backup, FIRMWARE_MAGIC, 4); } else { - explicit_bzero(meta_backup, 4); + memzero(meta_backup, 4); } // no need to erase, because we are not changing any already flashed byte. restore_metadata(meta_backup); - explicit_bzero(meta_backup, sizeof(meta_backup)); + memzero(meta_backup, sizeof(meta_backup)); flash_state = STATE_END; if (hash_check_ok) { diff --git a/firmware/Makefile b/firmware/Makefile index 85620caf82..c49eb33fb5 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -41,6 +41,7 @@ OBJS += ../vendor/trezor-crypto/curves.o OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/rand.o +OBJS += ../vendor/trezor-crypto/memzero.o OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.o OBJS += ../vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.o diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 2baf61c6d9..d2aff49dde 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -33,6 +33,7 @@ #include "util.h" #include "gettext.h" #include "ethereum_tokens.h" +#include "memzero.h" /* maximum supported chain id. v must fit in an uint32_t. */ #define MAX_CHAIN_ID 2147483630 @@ -193,7 +194,7 @@ static void send_signature(void) return; } - explicit_bzero(privkey, sizeof(privkey)); + memzero(privkey, sizeof(privkey)); /* Send back the result */ msg_tx_request.has_data_length = false; @@ -592,7 +593,7 @@ void ethereum_signing_txack(EthereumTxAck *tx) void ethereum_signing_abort(void) { if (ethereum_signing) { - explicit_bzero(privkey, sizeof(privkey)); + memzero(privkey, sizeof(privkey)); layoutHome(); ethereum_signing = false; } diff --git a/firmware/protect.c b/firmware/protect.c index 019fcf09e7..c81509f23f 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -29,6 +29,7 @@ #include "util.h" #include "debug.h" #include "gettext.h" +#include "memzero.h" #define MAX_WRONG_PINS 15 @@ -231,7 +232,7 @@ bool protectChangePin(void) storage_update(); } - explicit_bzero(pin_compare, sizeof(pin_compare)); + memzero(pin_compare, sizeof(pin_compare)); return result; } diff --git a/firmware/recovery.c b/firmware/recovery.c index 06014979b0..e2f955647b 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -33,6 +33,7 @@ #include "gettext.h" #include "types.pb.h" #include "recovery-table.h" +#include "memzero.h" /* number of words expected in the new seed */ static uint32_t word_count; @@ -142,7 +143,7 @@ static void recovery_done(void) { if (!dry_run) { // Update mnemonic on storage. storage_setMnemonic(new_mnemonic); - explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); + memzero(new_mnemonic, sizeof(new_mnemonic)); if (!enforce_wordlist) { // not enforcing => mark storage as imported storage_setImported(true); @@ -152,7 +153,7 @@ static void recovery_done(void) { } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). bool match = (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)); - explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); + memzero(new_mnemonic, sizeof(new_mnemonic)); if (match) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, _("The seed is valid"), @@ -172,7 +173,7 @@ static void recovery_done(void) { } } else { // New mnemonic is invalid. - explicit_bzero(new_mnemonic, sizeof(new_mnemonic)); + memzero(new_mnemonic, sizeof(new_mnemonic)); if (!dry_run) { session_clear(true); } else { diff --git a/firmware/storage.c b/firmware/storage.c index 8b9eba92b9..926aed6bfb 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -41,6 +41,7 @@ #include "usb.h" #include "gettext.h" #include "u2f.h" +#include "memzero.h" /* magic constant to check validity of storage block */ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t @@ -262,9 +263,9 @@ void storage_generate_uuid(void) void session_clear(bool clear_pin) { sessionSeedCached = false; - explicit_bzero(&sessionSeed, sizeof(sessionSeed)); + memzero(&sessionSeed, sizeof(sessionSeed)); sessionPassphraseCached = false; - explicit_bzero(&sessionPassphrase, sizeof(sessionPassphrase)); + memzero(&sessionPassphrase, sizeof(sessionPassphrase)); if (clear_pin) { sessionPinCached = false; } @@ -297,7 +298,7 @@ static void storage_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot u2froot->has_private_key = true; u2froot->private_key.size = sizeof(node.private_key); memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - explicit_bzero(&node, sizeof(node)); + memzero(&node, sizeof(node)); session_clear(false); // invalidate seed cache } @@ -399,7 +400,7 @@ static void storage_commit_locked(bool update) void storage_clear_update(void) { - explicit_bzero(&storageUpdate, sizeof(storageUpdate)); + memzero(&storageUpdate, sizeof(storageUpdate)); } void storage_update(void) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b7f73ee3ff..bb4c3d0525 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b7f73ee3ff78e09c266a30dbc31407558d471615 +Subproject commit bb4c3d052561bd31856a03d975ca226571f6a893 From a64d5bddb88fa0c81aab55d40743da103a12dc3c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 18 Jan 2018 18:40:43 +0100 Subject: [PATCH 0716/1154] fix demo --- demo/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/Makefile b/demo/Makefile index 57dcb068e3..306597b7ea 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -13,5 +13,6 @@ OBJS += ../vendor/trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/bip39.o OBJS += ../vendor/trezor-crypto/pbkdf2.o +OBJS += ../vendor/trezor-crypto/memzero.o include ../Makefile.include From f853047f53b3a1e42fc20598ad1913b277edb8b9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 20 Jan 2018 22:59:29 +0100 Subject: [PATCH 0717/1154] fix fastflash --- fastflash/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/fastflash/Makefile b/fastflash/Makefile index 24ca20a615..5b768eb49c 100644 --- a/fastflash/Makefile +++ b/fastflash/Makefile @@ -10,6 +10,7 @@ OBJS += ../vendor/trezor-crypto/bignum.small.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/sha2.small.o +OBJS += ../vendor/trezor-crypto/memzero.small.o CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0 From 2391beb6f43f90bcb78e1a8689334c30137da43f Mon Sep 17 00:00:00 2001 From: Wampum Date: Wed, 31 Jan 2018 16:12:52 +0000 Subject: [PATCH 0718/1154] expand description of multisig label (#294) --- firmware/fsm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 46b0f9f5a5..9ff220539d 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -771,15 +771,15 @@ void fsm_msgGetAddress(GetAddress *msg) } if (msg->has_show_display && msg->show_display) { - char desc[16]; + char desc[20]; if (msg->has_multisig) { - strlcpy(desc, "Msig __ of __:", sizeof(desc)); + strlcpy(desc, "Multisig __ of __:", sizeof(desc)); const uint32_t m = msg->multisig.m; const uint32_t n = msg->multisig.pubkeys_count; - desc[5] = (m < 10) ? ' ': ('0' + (m / 10)); - desc[6] = '0' + (m % 10); - desc[11] = (n < 10) ? ' ': ('0' + (n / 10)); - desc[12] = '0' + (n % 10); + desc[9] = (m < 10) ? ' ': ('0' + (m / 10)); + desc[10] = '0' + (m % 10); + desc[15] = (n < 10) ? ' ': ('0' + (n / 10)); + desc[16] = '0' + (n % 10); } else { strlcpy(desc, _("Address:"), sizeof(desc)); } From 3000a4ac8d2921025c6b310960b26edad0276629 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 12 Feb 2018 15:56:01 +0000 Subject: [PATCH 0719/1154] Fix emulator strlcpy implementation (#298) --- emulator/strl.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/emulator/strl.c b/emulator/strl.c index 42323a3ab2..b729892d9b 100644 --- a/emulator/strl.c +++ b/emulator/strl.c @@ -23,19 +23,22 @@ size_t strlcpy(char *dst, const char *src, size_t size) { if (size == 0) { - return 0; + return strlen(src); } - for (size_t i = 0; i < size - 1; i++) { + size_t i; + for (i = 0; i < size - 1; i++) { dst[i] = src[i]; if (src[i] == '\0') { - return i; + return i - 1; } } dst[size - 1] = '\0'; - return size - 2; + + while (src[i++] != '\0'); + return i - 1; } size_t strlcat(char *dst, const char *src, size_t size) { From 1209e48dffc5d0fec493b9f765028e8de1f56f41 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Feb 2018 15:15:52 +0100 Subject: [PATCH 0720/1154] make: update flash command to use openocd --- Makefile.include | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Makefile.include b/Makefile.include index 37f9985b60..f666c66268 100644 --- a/Makefile.include +++ b/Makefile.include @@ -23,8 +23,7 @@ OBJCOPY := $(PREFIX)objcopy OBJDUMP := $(PREFIX)objdump AR := $(PREFIX)ar AS := $(PREFIX)as -FLASH := st-flash -OPENOCD := openocd +OPENOCD := openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f target/stm32f2x.cfg OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG @@ -137,16 +136,7 @@ endif all: $(NAME).bin flash: $(NAME).bin - $(FLASH) write $(NAME).bin 0x8000000 - -flash2: $(NAME).hex - $(OPENOCD) -f board/stm32f4discovery.cfg \ - -c "init" \ - -c "reset init" \ - -c "stm32f2x mass_erase 0" \ - -c "flash write_image $(NAME).hex" \ - -c "reset" \ - -c "shutdown" + $(OPENOCD) -c "init; reset halt; flash write_image erase $(NAME).bin 0x8000000; exit" upload: sign trezorctl firmware_update -f $(NAME).bin From 00c4b8e1e8ce96fbdf019e935f879a3cc251ecbc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Feb 2018 15:16:18 +0100 Subject: [PATCH 0721/1154] add vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c09223a1c9..ddd05a1951 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .cache/ +.vscode/ _attic/ build/ *.o From f0255661ed6a980b9d5ba54eb0a93bfaaa096118 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 11 Feb 2018 22:09:36 +0000 Subject: [PATCH 0722/1154] setup: Change fault handler wording --- setup.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/setup.c b/setup.c index 5adff947e9..28a9fc6004 100644 --- a/setup.c +++ b/setup.c @@ -29,18 +29,20 @@ uint32_t __stack_chk_guard; -void __attribute__((noreturn)) __stack_chk_fail(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL); +static inline void __attribute__((noreturn)) fault_handler(const char *line1) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Unplug your TREZOR", "contact our support.", NULL); for (;;) {} // loop forever } +void __attribute__((noreturn)) __stack_chk_fail(void) { + fault_handler("Stack smashing"); +} + void nmi_handler(void) { // Clock Security System triggered NMI if ((RCC_CIR & RCC_CIR_CSSF) != 0) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Clock instability", "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever + fault_handler("Clock instability"); } } From 1f8f08d48a903f85871d1bac3b62cb12c6128459 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 11 Feb 2018 22:10:12 +0000 Subject: [PATCH 0723/1154] setup: Enable MPU Disable code execution from SRAM and reconfiguration of the MPU. Prevents almost all code execution attacks. --- firmware/trezor.c | 5 ++++ setup.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++- setup.h | 2 ++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index 9bb013edcd..e7e011fdcc 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -102,6 +102,11 @@ int main(void) } #endif +#ifdef APPVER + // enable MPU (Memory Protection Unit) + mpu_config(); +#endif + timer_init(); #if DEBUG_LINK diff --git a/setup.c b/setup.c index 28a9fc6004..4fb75c5c8d 100644 --- a/setup.c +++ b/setup.c @@ -17,16 +17,32 @@ * along with this library. If not, see . */ +#include +#include #include #include #include #include -#include +#include #include "rng.h" #include "layout.h" +#include "memory.h" #include "util.h" +#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) + +// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html +#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_S | MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_S | MPU_RASR_ATTR_B) + uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { @@ -46,6 +62,14 @@ void nmi_handler(void) } } +void hard_fault_handler(void) { + fault_handler("Hard fault"); +} + +void mem_manage_handler(void) { + fault_handler("Memory fault"); +} + void setup(void) { // set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect. @@ -130,3 +154,43 @@ void setupApp(void) gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } + +// Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) +void mpu_config(void) +{ + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + + // Disable MPU + MPU_CTRL = 0; + + // Bootloader (read-only, execute never) + MPU_RBAR = 0x08000000 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; + + // Metadata (read-write, execute never) + MPU_RBAR = 0x08008000 | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // Firmware (read-only) + MPU_RBAR = 0x08010000 | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_64KB | MPU_RASR_ATTR_AP_PRO_URO; + MPU_RBAR = 0x08020000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRO_URO; + MPU_RBAR = 0x08040000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_256KB | MPU_RASR_ATTR_AP_PRO_URO; + + // SRAM (read-write, execute never) + MPU_RBAR = 0x20000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // Peripherals (read-write, execute never) + MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512MB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // Enable MPU + MPU_CTRL = MPU_CTRL_ENABLE; + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +} diff --git a/setup.h b/setup.h index c5236fc341..34b88aae55 100644 --- a/setup.h +++ b/setup.h @@ -27,4 +27,6 @@ extern uint32_t __stack_chk_guard; void setup(void); void setupApp(void); +void mpu_config(void); + #endif From 3cba075e4f1652c0d8e9602e2f0f4aade4709fff Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Feb 2018 15:51:27 +0100 Subject: [PATCH 0724/1154] setup: revert string in fault_handler --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index 4fb75c5c8d..5e986e53fc 100644 --- a/setup.c +++ b/setup.c @@ -46,7 +46,7 @@ uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Unplug your TREZOR", "contact our support.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever } From a00ac050e582e266fc10d0ae162054d68f09be44 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Feb 2018 16:16:31 +0100 Subject: [PATCH 0725/1154] setup: typo changes in mpu setup --- setup.c | 68 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/setup.c b/setup.c index 5e986e53fc..8329b42362 100644 --- a/setup.c +++ b/setup.c @@ -27,22 +27,8 @@ #include "rng.h" #include "layout.h" -#include "memory.h" #include "util.h" -#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) - -// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html -#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) -#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_S | MPU_RASR_ATTR_C) -#define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_S | MPU_RASR_ATTR_B) - uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { @@ -155,42 +141,56 @@ void setupApp(void) gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } +#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) + +// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html +#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) +#define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_B | MPU_RASR_ATTR_S) + +#define FLASH_BASE (0x08000000U) +#define SRAM_BASE (0x20000000U) + // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) void mpu_config(void) { - // Enable memory fault handler - SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; - // Disable MPU MPU_CTRL = 0; - // Bootloader (read-only, execute never) - MPU_RBAR = 0x08000000 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; + // Bootloader (0x08000000 - 0x08007FFF, 32 KiB, read-only, execute never) + MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; - // Metadata (read-write, execute never) - MPU_RBAR = 0x08008000 | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Metadata (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) + MPU_RBAR = FLASH_BASE | 0x8000 | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Firmware (read-only) - MPU_RBAR = 0x08010000 | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_64KB | MPU_RASR_ATTR_AP_PRO_URO; - MPU_RBAR = 0x08020000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRO_URO; - MPU_RBAR = 0x08040000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_256KB | MPU_RASR_ATTR_AP_PRO_URO; + // Firmware (0x08010000 - 0x0807FFFF, 64 + 3 * 128 KiB = 64 + 128 + 256 KiB = 448 KiB, read-only) + MPU_RBAR = FLASH_BASE | 0x10000 | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_64KB | MPU_RASR_ATTR_AP_PRO_URO; + MPU_RBAR = FLASH_BASE | 0x20000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRO_URO; + MPU_RBAR = FLASH_BASE | 0x40000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_256KB | MPU_RASR_ATTR_AP_PRO_URO; - // SRAM (read-write, execute never) - MPU_RBAR = 0x20000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (read-write, execute never) + // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512MB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; // Enable MPU MPU_CTRL = MPU_CTRL_ENABLE; + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + __asm__ volatile("dsb"); __asm__ volatile("isb"); } From e3a0b6e7b4bc244e43f47e06682c1c420e6c6fa2 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 13 Feb 2018 18:18:19 +0000 Subject: [PATCH 0726/1154] setup: Switch to unprivileged execution --- firmware/trezor.c | 4 ++-- setup.c | 3 +++ util.h | 6 ++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index e7e011fdcc..8c5d55a9a7 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -102,13 +102,13 @@ int main(void) } #endif + timer_init(); + #ifdef APPVER // enable MPU (Memory Protection Unit) mpu_config(); #endif - timer_init(); - #if DEBUG_LINK oledSetDebugLink(1); storage_wipe(); diff --git a/setup.c b/setup.c index 8329b42362..0cd7f43d78 100644 --- a/setup.c +++ b/setup.c @@ -193,4 +193,7 @@ void mpu_config(void) __asm__ volatile("dsb"); __asm__ volatile("isb"); + + // Switch to unprivileged software execution to prevent access to MPU + set_mode_unprivileged(); } diff --git a/util.h b/util.h index 05d9c9a739..de3f9d5e0b 100644 --- a/util.h +++ b/util.h @@ -66,6 +66,12 @@ static inline void __attribute__((noreturn)) load_vector_table(const vector_tabl // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) for (;;); } + +static inline void set_mode_unprivileged(void) +{ + // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html + __asm__ volatile("msr control, %0" :: "r" (0x1)); +} #endif #endif From b4e3cd3e0c959a851bf7d9764dabf7dda873ba89 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 14 Feb 2018 10:48:47 +0000 Subject: [PATCH 0727/1154] emulator: Refactor strlcpy Performance is unimportant and this implementation makes it easier to fuzz. --- emulator/strl.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/emulator/strl.c b/emulator/strl.c index b729892d9b..6c87be9320 100644 --- a/emulator/strl.c +++ b/emulator/strl.c @@ -18,27 +18,20 @@ */ #include "strl.h" +#include "util.h" #include size_t strlcpy(char *dst, const char *src, size_t size) { - if (size == 0) { - return strlen(src); + size_t ret = strlen(src); + + if (size) { + size_t len = MIN(ret, size - 1); + memcpy(dst, src, len); + dst[len] = '\0'; } - size_t i; - for (i = 0; i < size - 1; i++) { - dst[i] = src[i]; - - if (src[i] == '\0') { - return i - 1; - } - } - - dst[size - 1] = '\0'; - - while (src[i++] != '\0'); - return i - 1; + return ret; } size_t strlcat(char *dst, const char *src, size_t size) { From 7376b97ee69394fece22b52c598baf020669908c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 18 Feb 2018 19:34:56 +0000 Subject: [PATCH 0728/1154] emulator: Add TREZOR_OLED_SCALE variable --- emulator/oled.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/emulator/oled.c b/emulator/oled.c index 8f58759351..26babdb51d 100644 --- a/emulator/oled.c +++ b/emulator/oled.c @@ -32,6 +32,20 @@ void emulatorPoll(void) {} static SDL_Renderer *renderer = NULL; static SDL_Texture *texture = NULL; +#define ENV_OLED_SCALE "TREZOR_OLED_SCALE" + +static int emulatorScale(void) { + const char *variable = getenv(ENV_OLED_SCALE); + if (!variable) { + return 1; + } + int scale = atoi(variable); + if (scale >= 1 && scale <= 16) { + return scale; + } + return 1; +} + void oledInit(void) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); @@ -39,7 +53,15 @@ void oledInit(void) { } atexit(SDL_Quit); - SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH, OLED_HEIGHT, 0); + int scale = emulatorScale(); + + SDL_Window *window = SDL_CreateWindow("TREZOR", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + OLED_WIDTH * scale, + OLED_HEIGHT * scale, + 0); + if (window == NULL) { fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); exit(1); @@ -51,6 +73,9 @@ void oledInit(void) { exit(1); } + /* Use unscaled coordinate system */ + SDL_RenderSetLogicalSize(renderer, OLED_WIDTH, OLED_HEIGHT); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); oledClear(); From 4b8a963938ed4648cb70d09fae8663818a9feee8 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Mon, 19 Feb 2018 00:41:34 +0100 Subject: [PATCH 0729/1154] emulator: add docker build --- Dockerfile.emulator | 17 +++++++++++++++++ build-emulator.sh | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Dockerfile.emulator create mode 100755 build-emulator.sh diff --git a/Dockerfile.emulator b/Dockerfile.emulator new file mode 100644 index 0000000000..f8c3dad632 --- /dev/null +++ b/Dockerfile.emulator @@ -0,0 +1,17 @@ +# initialize from the image + +FROM debian:9 + +# install build tools and dependencies + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y \ + build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi libsdl2-dev:i386 libsdl2-image-dev:i386 gcc-multilib + +ENV PROTOBUF_VERSION=3.4.0 +RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" +RUN unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d /usr +RUN pip3 install "protobuf==${PROTOBUF_VERSION}" ecdsa + +RUN ln -s python3 /usr/bin/python diff --git a/build-emulator.sh b/build-emulator.sh new file mode 100755 index 0000000000..8946969295 --- /dev/null +++ b/build-emulator.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +IMAGE=trezor-mcu-build-emulator +TAG=${1:-master} +ELFFILE=build/trezor-emulator-$TAG + +docker build -f Dockerfile.emulator -t $IMAGE . +docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ + git clone https://github.com/trezor/trezor-mcu && \ + cd trezor-mcu && \ + git checkout $TAG && \ + git submodule update --init && \ + make -C vendor/libopencm3 && \ + make -C vendor/nanopb/generator/proto && \ + make -C firmware/protob && \ + EMULATOR=1 make && \ + EMULATOR=1 make -C emulator && \ + EMULATOR=1 make -C firmware && \ + cp firmware/trezor.elf /$ELFFILE" From 28f7bf2a5dc8c453907d82bbb9343785367dc0b4 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 18 Feb 2018 23:13:40 +0100 Subject: [PATCH 0730/1154] emulator: Add instructions --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6485ef0c1e..bc8d47ea53 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,15 @@ https://trezor.io/ This creates file `build/trezor-TAG.bin` and prints its fingerprint and size at the end of the build log. +## How to build TREZOR emulator for Linux? + +1. [Install Docker](https://docs.docker.com/engine/installation/) +2. `git clone https://github.com/trezor/trezor-mcu.git` +3. `cd trezor-mcu` +4. `./build-emulator.sh TAG` (where TAG is v1.5.0 for example, if left blank the script builds latest commit in master branch) + +This creates binary file `build/trezor-emulator-TAG`, which can be run and works as a trezor emulator. (Use `TREZOR_OLED_SCALE` env. variable to make screen bigger.) + ## How to build TREZOR bootloader? 1. [Install Docker](https://docs.docker.com/engine/installation/) From 48998e5e5f1b743faea7250e745fdd45c1e0f022 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 19 Feb 2018 01:03:40 +0100 Subject: [PATCH 0731/1154] dockerfile: small typos to make them two Dockerfiles more similar --- Dockerfile | 3 ++- Dockerfile.emulator | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ac3df0d507..4debc36f53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,8 @@ FROM debian:9 # install build tools and dependencies -RUN apt-get update && apt-get install -y \ +RUN apt-get update && \ + apt-get install -y \ build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi ENV PROTOBUF_VERSION=3.4.0 diff --git a/Dockerfile.emulator b/Dockerfile.emulator index f8c3dad632..7f0a24925e 100644 --- a/Dockerfile.emulator +++ b/Dockerfile.emulator @@ -7,7 +7,8 @@ FROM debian:9 RUN dpkg --add-architecture i386 && \ apt-get update && \ apt-get install -y \ - build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi libsdl2-dev:i386 libsdl2-image-dev:i386 gcc-multilib + build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi \ + libsdl2-dev:i386 libsdl2-image-dev:i386 gcc-multilib ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 998690fe41bbff921ee4cfff667f37eda25a8461 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 18 Feb 2018 18:44:36 +0100 Subject: [PATCH 0732/1154] emulator: fix Makefile --- Makefile.include | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Makefile.include b/Makefile.include index f666c66268..59d0115bd7 100644 --- a/Makefile.include +++ b/Makefile.include @@ -77,6 +77,14 @@ LDFLAGS += -L$(TOP_DIR) \ ifeq ($(EMULATOR),1) CFLAGS += -DEMULATOR=1 +CFLAGS += -include $(TOP_DIR)emulator/emulator.h +CFLAGS += -include stdio.h + +LDFLAGS += -L$(TOP_DIR)emulator + +LDLIBS += -ltrezor -lemulator +LIBDEPS += $(TOP_DIR)/libtrezor.a $(TOP_DIR)emulator/libemulator.a + ifeq ($(HEADLESS),1) CFLAGS += -DHEADLESS=1 else @@ -86,13 +94,6 @@ CFLAGS += $(shell pkg-config --cflags sdl2) LDLIBS += $(shell pkg-config --libs sdl2) endif -CFLAGS += -include $(TOP_DIR)emulator/emulator.h -CFLAGS += -include stdio.h - -LDFLAGS += -L$(TOP_DIR)emulator - -LDLIBS += -ltrezor -lemulator -LIBDEPS += $(TOP_DIR)/libtrezor.a $(TOP_DIR)emulator/libemulator.a else ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) From a48dcac07d9fc33d9201ef5fc3ae68d2f1c0f7a2 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 18 Feb 2018 20:00:40 +0100 Subject: [PATCH 0733/1154] emulator: use SDL2 directly --- Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index 59d0115bd7..c9e8fd578f 100644 --- a/Makefile.include +++ b/Makefile.include @@ -90,8 +90,8 @@ CFLAGS += -DHEADLESS=1 else CFLAGS += -DHEADLESS=0 -CFLAGS += $(shell pkg-config --cflags sdl2) -LDLIBS += $(shell pkg-config --libs sdl2) +CFLAGS += -I/usr/include/SDL2 -D_REENTRANT +LDLIBS += -lSDL2 endif else From 9b093757131c9037b0fee86b34f18c66c08112e8 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Mon, 19 Feb 2018 02:31:41 +0100 Subject: [PATCH 0734/1154] emulator: Removing useless build and install --- Dockerfile.emulator | 2 +- build-emulator.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile.emulator b/Dockerfile.emulator index 7f0a24925e..90fe68175c 100644 --- a/Dockerfile.emulator +++ b/Dockerfile.emulator @@ -7,7 +7,7 @@ FROM debian:9 RUN dpkg --add-architecture i386 && \ apt-get update && \ apt-get install -y \ - build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi \ + build-essential curl unzip git python3 python3-pip \ libsdl2-dev:i386 libsdl2-image-dev:i386 gcc-multilib ENV PROTOBUF_VERSION=3.4.0 diff --git a/build-emulator.sh b/build-emulator.sh index 8946969295..37b16952a3 100755 --- a/build-emulator.sh +++ b/build-emulator.sh @@ -11,7 +11,6 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cd trezor-mcu && \ git checkout $TAG && \ git submodule update --init && \ - make -C vendor/libopencm3 && \ make -C vendor/nanopb/generator/proto && \ make -C firmware/protob && \ EMULATOR=1 make && \ From 1bc1bb1e774e210c9d43c9c60ea1dbab272e47d6 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 20 Feb 2018 15:27:24 +0100 Subject: [PATCH 0735/1154] Less paranoid change outputs. - Allow change to be on the main chain (see spesmilo/electrum#3920). - Allow more than one output to the Trezor, but don't treat it as change. --- firmware/signing.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index c449759741..3c7003408a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -389,7 +389,7 @@ bool check_change_bip32_path(const TxOutputType *toutput) && count == in_address_n_count && 0 == memcmp(in_address_n, toutput->address_n, (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) - && toutput->address_n[count - 2] == BIP32_CHANGE_CHAIN + && toutput->address_n[count - 2] <= BIP32_CHANGE_CHAIN && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } @@ -565,9 +565,8 @@ static bool signing_check_output(TxOutputType *txoutput) { if (change_spend == 0) { // not set change_spend = txoutput->amount; } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Only one change output allowed")); - signing_abort(); - return false; + /* We only skip confirmation for the first change output */ + is_change = false; } } From e019ab5557fbc96df497d16354a9be24793caad4 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 6 Jan 2018 15:47:32 +0000 Subject: [PATCH 0736/1154] fsm: Abort layoutAddress on Initialize or Cancel Fixes #247 --- firmware/fsm.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9ff220539d..9d1422f850 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -210,6 +210,23 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } +static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, const uint32_t *address_n, size_t address_n_count) +{ + bool qrcode = false; + for (;;) { + layoutAddress(address, desc, qrcode, ignorecase, address_n, address_n_count); + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + return true; + } + if (protectAbortedByInitialize) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return false; + } + qrcode = !qrcode; + } +} + void fsm_msgInitialize(Initialize *msg) { (void)msg; @@ -795,13 +812,8 @@ void fsm_msgGetAddress(GetAddress *msg) } } - bool qrcode = false; - for (;;) { - layoutAddress(address, desc, qrcode, msg->script_type == InputScriptType_SPENDWITNESS, msg->address_n, msg->address_n_count); - if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { - break; - } - qrcode = !qrcode; + if (!fsm_layoutAddress(address, desc, msg->script_type == InputScriptType_SPENDWITNESS, msg->address_n, msg->address_n_count)) { + return; } } @@ -833,13 +845,8 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) char address[43] = { '0', 'x' }; ethereum_address_checksum(resp->address.bytes, address + 2); - bool qrcode = false; - for (;;) { - layoutAddress(address, desc, qrcode, false, msg->address_n, msg->address_n_count); - if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { - break; - } - qrcode = !qrcode; + if (!fsm_layoutAddress(address, desc, false, msg->address_n, msg->address_n_count)) { + return; } } @@ -1256,13 +1263,8 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) strlcpy(desc, network, sizeof(desc)); strlcat(desc, ":", sizeof(desc)); - bool qrcode = false; - for (;;) { - layoutAddress(resp->address, desc, qrcode, true, msg->address_n, msg->address_n_count); - if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { - break; - } - qrcode = !qrcode; + if (!fsm_layoutAddress(resp->address, desc, true, msg->address_n, msg->address_n_count)) { + return; } } From 909f158c842e4f56cbc7a9edb7473e6cdaab2690 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 20 Feb 2018 17:31:45 +0100 Subject: [PATCH 0737/1154] vendor: update trezor-common --- firmware/protob/messages.options | 6 ++++++ vendor/trezor-common | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 294aff73b8..90329e7d50 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -1,3 +1,5 @@ +Initialize.state max_size:32 + Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 @@ -6,6 +8,9 @@ Features.coins max_count:16 Features.revision max_size:20 Features.bootloader_hash max_size:32 Features.model max_size:17 +Features.fw_vendor max_size:256 +Features.fw_vendor_keys max_size:32 +Features.state max_size:32 ApplySettings.language max_size:17 ApplySettings.label max_size:33 @@ -22,6 +27,7 @@ ButtonRequest.data max_size:256 PinMatrixAck.pin max_size:10 PassphraseAck.passphrase max_size:51 +PassphraseAck.state max_size:32 Entropy.entropy max_size:1024 diff --git a/vendor/trezor-common b/vendor/trezor-common index 13499e256a..43b6464883 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 13499e256acfdde662b98ea402146ca105fb03b3 +Subproject commit 43b64648832028efbb93079a1bd17794ed4044cb From fc7189f801f8457cc49bafbacbe546dc3f72d460 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 20 Feb 2018 17:48:19 +0100 Subject: [PATCH 0738/1154] use Failure_PinMismatch where it makes sense (ChangePin, ResetDevice, RecoveryDevice) --- firmware/fsm.c | 5 ++++- firmware/recovery.c | 2 +- firmware/reset.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9d1422f850..f05d80fba6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -155,6 +155,9 @@ void fsm_sendFailure(FailureType code, const char *text) case FailureType_Failure_NotInitialized: text = _("Device not initialized"); break; + case FailureType_Failure_PinMismatch: + text = _("PIN mismatch"); + break; case FailureType_Failure_FirmwareError: text = _("Firmware error"); break; @@ -366,7 +369,7 @@ void fsm_msgChangePin(ChangePin *msg) if (protectChangePin()) { fsm_sendSuccess(_("PIN changed")); } else { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); } } layoutHome(); diff --git a/firmware/recovery.c b/firmware/recovery.c index e2f955647b..7348748527 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -415,7 +415,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr if (!dry_run) { if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } diff --git a/firmware/reset.c b/firmware/reset.c index 797837818f..e44370ee78 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -60,7 +60,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect } if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } From 83a69a03349c3a6c37d9c84577b394d2ae1c3589 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 6 Feb 2018 22:29:33 +0100 Subject: [PATCH 0739/1154] Added fixed-width font and multi-font support --- bootloader/bootloader.c | 16 +-- firmware/debug.c | 4 +- firmware/layout2.c | 32 ++--- firmware/pinmatrix.c | 2 +- firmware/recovery.c | 2 +- gen/font.inc | 128 +++++++++++++++++++ gen/fontfixed.inc | 128 +++++++++++++++++++ gen/fonts.c | 272 ++-------------------------------------- gen/fonts.h | 9 +- gen/fonts/fontfixed.png | Bin 0 -> 1761 bytes gen/fonts/generate.py | 29 +++-- gen/strwidth.c | 3 +- layout.c | 28 ++--- oled.c | 31 ++--- oled.h | 10 +- 15 files changed, 355 insertions(+), 339 deletions(-) create mode 100644 gen/font.inc create mode 100644 gen/fontfixed.inc create mode 100644 gen/fonts/fontfixed.png diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 6a9e71f528..2cf8988aeb 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -105,18 +105,18 @@ void bootloader_loop(void) oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); if (firmware_present()) { - oledDrawString(52, 0, "TREZOR"); + oledDrawString(52, 0, "TREZOR", FONT_STANDARD); static char serial[25]; fill_serialno_fixed(serial); - oledDrawString(52, 20, "Serial No."); - oledDrawString(52, 40, serial + 12); // second part of serial + oledDrawString(52, 20, "Serial No.", FONT_STANDARD); + oledDrawString(52, 40, serial + 12, FONT_STANDARD); // second part of serial serial[12] = 0; - oledDrawString(52, 30, serial); // first part of serial - oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH)); + oledDrawString(52, 30, serial, FONT_STANDARD); // first part of serial + oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); } else { - oledDrawString(52, 10, "Welcome!"); - oledDrawString(52, 30, "Please visit"); - oledDrawString(52, 50, "trezor.io/start"); + oledDrawString(52, 10, "Welcome!", FONT_STANDARD); + oledDrawString(52, 30, "Please visit", FONT_STANDARD); + oledDrawString(52, 50, "trezor.io/start", FONT_STANDARD); } oledRefresh(); diff --git a/firmware/debug.c b/firmware/debug.c index a8519fd948..eb27314921 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -35,8 +35,8 @@ void oledDebug(const char *line) oledClear(); for (int i = 0; i < 8; i++) { if (lines[i]) { - oledDrawChar(0, i * 8, '0' + (id + i) % 10, 1); - oledDrawString(8, i * 8, lines[i]); + oledDrawChar(0, i * 8, '0' + (id + i) % 10, FONT_STANDARD); + oledDrawString(8, i * 8, lines[i], FONT_STANDARD); } } oledRefresh(); diff --git a/firmware/layout2.c b/firmware/layout2.c index 7852460ede..528205b1a2 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -109,14 +109,14 @@ void layoutHome(void) } else { if (label && strlen(label) > 0) { oledDrawBitmap(44, 4, &bmp_logo48); - oledDrawStringCenter(OLED_HEIGHT - 8, label); + oledDrawStringCenter(OLED_HEIGHT - 8, label, FONT_STANDARD); } else { oledDrawBitmap(40, 0, &bmp_logo64); } } if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "NEEDS BACKUP!"); + oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); } oledRefresh(); @@ -316,13 +316,13 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledDrawBitmap(0, 0, &bmp_icon_info); left = bmp_icon_info.width + 4; - oledDrawString(left, 0 * 9, action); - oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str); - oledDrawStringDouble(left, 3 * 9, word); + oledDrawString(left, 0 * 9, action, FONT_STANDARD); + oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, FONT_STANDARD); + oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); oledHLine(OLED_HEIGHT - 13); - oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); - oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledRefresh(); } @@ -491,24 +491,24 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno uint32_t rowlen = (addrlen - 1) / (addrlen <= 40 ? 2 : addrlen <= 60 ? 3 : 4) + 1; const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { - oledDrawString(0, 0 * 9, desc); + oledDrawString(0, 0 * 9, desc, FONT_STANDARD); } for (int i = 0; i < 4; i++) { - oledDrawString(0, (i + 1) * 9 + 4, str[i]); + oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); } - oledDrawString(0, 42, address_n_str(address_n, address_n_count)); + oledDrawString(0, 42, address_n_str(address_n, address_n_count), FONT_STANDARD); } if (!qrcode) { static const char *btnNo = _("QR Code"); - oledDrawString(2, OLED_HEIGHT - 8, btnNo); - oledInvert(0, OLED_HEIGHT - 9, oledStringWidth(btnNo) + 3, OLED_HEIGHT - 1); + oledDrawString(2, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, oledStringWidth(btnNo, FONT_STANDARD) + 3, OLED_HEIGHT - 1); } static const char *btnYes = _("Continue"); - oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); - oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledRefresh(); } diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 39f60fc874..c3a5aac99c 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -39,7 +39,7 @@ void pinmatrix_draw(const char *text) // use (2 - j) instead of j to achieve 789456123 layout int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; if (text) { - oledDrawStringCenter(0, text); + oledDrawStringCenter(0, text, FONT_STANDARD); } oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); } diff --git a/firmware/recovery.c b/firmware/recovery.c index 7348748527..b01e510c7d 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -260,7 +260,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) int x = twoColumn ? 64 * col + 32 : 42 * col + 22; int choice = word_matrix[nColumns*row + col]; const char *text = choice < num ? choices[choice] : "-"; - oledDrawString(x - oledStringWidth(text)/2, y, text); + oledDrawString(x - oledStringWidth(text, FONT_STANDARD)/2, y, text, FONT_STANDARD); if (twoColumn) { oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); } else { diff --git a/gen/font.inc b/gen/font.inc new file mode 100644 index 0000000000..e14089597b --- /dev/null +++ b/gen/font.inc @@ -0,0 +1,128 @@ + /* 0x00 _ */ (uint8_t *)"\x01\x00", + /* 0x01 _ */ (uint8_t *)"\x01\x00", + /* 0x02 _ */ (uint8_t *)"\x01\x00", + /* 0x03 _ */ (uint8_t *)"\x01\x00", + /* 0x04 _ */ (uint8_t *)"\x01\x00", + /* 0x05 _ */ (uint8_t *)"\x01\x00", + /* 0x06 _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", + /* 0x07 _ */ (uint8_t *)"\x01\x00", + /* 0x08 _ */ (uint8_t *)"\x01\x00", + /* 0x09 _ */ (uint8_t *)"\x01\x00", + /* 0x0a _ */ (uint8_t *)"\x01\x00", + /* 0x0b _ */ (uint8_t *)"\x01\x00", + /* 0x0c _ */ (uint8_t *)"\x01\x00", + /* 0x0d _ */ (uint8_t *)"\x01\x00", + /* 0x0e _ */ (uint8_t *)"\x01\x00", + /* 0x0f _ */ (uint8_t *)"\x01\x00", + /* 0x10 _ */ (uint8_t *)"\x01\x00", + /* 0x11 _ */ (uint8_t *)"\x01\x00", + /* 0x12 _ */ (uint8_t *)"\x01\x00", + /* 0x13 _ */ (uint8_t *)"\x01\x00", + /* 0x14 _ */ (uint8_t *)"\x01\x00", + /* 0x15 _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", + /* 0x16 _ */ (uint8_t *)"\x01\x00", + /* 0x17 _ */ (uint8_t *)"\x01\x00", + /* 0x18 _ */ (uint8_t *)"\x01\x00", + /* 0x19 _ */ (uint8_t *)"\x01\x00", + /* 0x1a _ */ (uint8_t *)"\x01\x00", + /* 0x1b _ */ (uint8_t *)"\x01\x00", + /* 0x1c _ */ (uint8_t *)"\x01\x00", + /* 0x1d _ */ (uint8_t *)"\x01\x00", + /* 0x1e _ */ (uint8_t *)"\x01\x00", + /* 0x1f _ */ (uint8_t *)"\x01\x00", + /* 0x20 */ (uint8_t *)"\x01\x00", + /* 0x21 ! */ (uint8_t *)"\x02\xfa\xfa", + /* 0x22 " */ (uint8_t *)"\x03\xc0\x00\xc0", + /* 0x23 # */ (uint8_t *)"\x05\x6c\xfe\x6c\xfe\x6c", + /* 0x24 $ */ (uint8_t *)"\x05\x32\xff\x5a\xff\x4c", + /* 0x25 % */ (uint8_t *)"\x06\xc0\xc6\x1c\x70\xc6\x06", + /* 0x26 & */ (uint8_t *)"\x06\x5c\xfe\xb2\xfe\x4c\x1e", + /* 0x27 ' */ (uint8_t *)"\x01\xc0", + /* 0x28 ( */ (uint8_t *)"\x03\x38\x7c\x82", + /* 0x29 ) */ (uint8_t *)"\x03\x82\x7c\x38", + /* 0x2a * */ (uint8_t *)"\x05\x6c\x38\xfe\x38\x6c", + /* 0x2b + */ (uint8_t *)"\x05\x10\x10\x7c\x10\x10", + /* 0x2c , */ (uint8_t *)"\x02\x03\x06", + /* 0x2d - */ (uint8_t *)"\x04\x10\x10\x10\x10", + /* 0x2e . */ (uint8_t *)"\x02\x06\x06", + /* 0x2f / */ (uint8_t *)"\x03\x0e\x38\xe0", + /* 0x30 0 */ (uint8_t *)"\x05\x7c\xfe\x82\xfe\x7c", + /* 0x31 1 */ (uint8_t *)"\x03\x40\xfe\xfe", + /* 0x32 2 */ (uint8_t *)"\x05\x8e\x9e\x92\xf2\x62", + /* 0x33 3 */ (uint8_t *)"\x05\x82\x92\x92\xfe\x6c", + /* 0x34 4 */ (uint8_t *)"\x05\x18\x28\x48\xfe\xfe", + /* 0x35 5 */ (uint8_t *)"\x05\xe2\xa2\xa2\xbe\x1c", + /* 0x36 6 */ (uint8_t *)"\x05\x7c\xfe\xa2\xbe\x1c", + /* 0x37 7 */ (uint8_t *)"\x05\x80\x8e\xbe\xf0\xc0", + /* 0x38 8 */ (uint8_t *)"\x05\x6c\xfe\x92\xfe\x6c", + /* 0x39 9 */ (uint8_t *)"\x05\x70\xfa\x8a\xfe\x7c", + /* 0x3a : */ (uint8_t *)"\x02\x36\x36", + /* 0x3b ; */ (uint8_t *)"\x02\x33\x36", + /* 0x3c < */ (uint8_t *)"\x04\x10\x38\x6c\xc6", + /* 0x3d = */ (uint8_t *)"\x04\x28\x28\x28\x28", + /* 0x3e > */ (uint8_t *)"\x04\xc6\x6c\x38\x10", + /* 0x3f ? */ (uint8_t *)"\x05\x80\x9a\xba\xe0\x40", + /* 0x40 @ */ (uint8_t *)"\x06\x7c\xfe\xaa\xba\xfa\x78", + /* 0x41 A */ (uint8_t *)"\x05\x7e\xfe\x88\xfe\x7e", + /* 0x42 B */ (uint8_t *)"\x05\xfe\xfe\xa2\xfe\x5c", + /* 0x43 C */ (uint8_t *)"\x05\x7c\xfe\x82\x82\x82", + /* 0x44 D */ (uint8_t *)"\x05\xfe\xfe\x82\xfe\x7c", + /* 0x45 E */ (uint8_t *)"\x05\xfe\xfe\xa2\xa2\x82", + /* 0x46 F */ (uint8_t *)"\x05\xfe\xfe\xa0\xa0\x80", + /* 0x47 G */ (uint8_t *)"\x05\x7c\xfe\x82\x9e\x1e", + /* 0x48 H */ (uint8_t *)"\x05\xfe\xfe\x20\xfe\xfe", + /* 0x49 I */ (uint8_t *)"\x02\xfe\xfe", + /* 0x4a J */ (uint8_t *)"\x04\x02\x02\xfe\xfc", + /* 0x4b K */ (uint8_t *)"\x06\xfe\xfe\x38\x6c\xc6\x82", + /* 0x4c L */ (uint8_t *)"\x04\xfe\xfe\x02\x02", + /* 0x4d M */ (uint8_t *)"\x07\xfe\x7e\x30\x18\x30\x7e\xfe", + /* 0x4e N */ (uint8_t *)"\x06\xfe\x7e\x30\x18\xfc\xfe", + /* 0x4f O */ (uint8_t *)"\x06\x7c\xfe\x82\x82\xfe\x7c", + /* 0x50 P */ (uint8_t *)"\x05\xfe\xfe\x88\xf8\x70", + /* 0x51 Q */ (uint8_t *)"\x06\x7c\xfe\x82\x86\xff\x7d", + /* 0x52 R */ (uint8_t *)"\x05\xfe\xfe\x88\xfe\x72", + /* 0x53 S */ (uint8_t *)"\x04\x62\xf2\x9e\x8c", + /* 0x54 T */ (uint8_t *)"\x06\x80\x80\xfe\xfe\x80\x80", + /* 0x55 U */ (uint8_t *)"\x05\xfc\xfe\x02\xfe\xfc", + /* 0x56 V */ (uint8_t *)"\x06\xe0\xf8\x1e\x1e\xf8\xe0", + /* 0x57 W */ (uint8_t *)"\x07\xf0\xfe\x1e\x3c\x1e\xfe\xf0", + /* 0x58 X */ (uint8_t *)"\x06\xc6\xee\x38\x38\xee\xc6", + /* 0x59 Y */ (uint8_t *)"\x06\xc0\xe0\x3e\x3e\xe0\xc0", + /* 0x5a Z */ (uint8_t *)"\x05\x8e\x9e\xba\xf2\xe2", + /* 0x5b [ */ (uint8_t *)"\x03\xfe\xfe\x82", + /* 0x5c \ */ (uint8_t *)"\x03\xe0\x38\x0e", + /* 0x5d ] */ (uint8_t *)"\x03\x82\xfe\xfe", + /* 0x5e ^ */ (uint8_t *)"\x03\x60\xc0\x60", + /* 0x5f _ */ (uint8_t *)"\x06\x02\x02\x02\x02\x02\x02", + /* 0x60 ` */ (uint8_t *)"\x02\x80\x40", + /* 0x61 a */ (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", + /* 0x62 b */ (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", + /* 0x63 c */ (uint8_t *)"\x05\x1c\x3e\x22\x36\x14", + /* 0x64 d */ (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", + /* 0x65 e */ (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", + /* 0x66 f */ (uint8_t *)"\x03\x7e\xfe\xa0", + /* 0x67 g */ (uint8_t *)"\x05\x18\x3d\x25\x3f\x3e", + /* 0x68 h */ (uint8_t *)"\x05\xfe\xfe\x20\x3e\x1e", + /* 0x69 i */ (uint8_t *)"\x02\xbe\xbe", + /* 0x6a j */ (uint8_t *)"\x03\x01\xbf\xbe", + /* 0x6b k */ (uint8_t *)"\x05\xfe\xfe\x1c\x36\x22", + /* 0x6c l */ (uint8_t *)"\x02\xfe\xfe", + /* 0x6d m */ (uint8_t *)"\x08\x3e\x3e\x20\x3e\x3e\x20\x3e\x1e", + /* 0x6e n */ (uint8_t *)"\x05\x3e\x3e\x20\x3e\x1e", + /* 0x6f o */ (uint8_t *)"\x05\x1c\x3e\x22\x3e\x1c", + /* 0x70 p */ (uint8_t *)"\x05\x3f\x3f\x24\x3c\x18", + /* 0x71 q */ (uint8_t *)"\x05\x18\x3c\x24\x3f\x3f", + /* 0x72 r */ (uint8_t *)"\x04\x3e\x3e\x10\x30", + /* 0x73 s */ (uint8_t *)"\x04\x1a\x3a\x2e\x2c", + /* 0x74 t */ (uint8_t *)"\x03\xfc\xfe\x22", + /* 0x75 u */ (uint8_t *)"\x05\x3c\x3e\x02\x3e\x3e", + /* 0x76 v */ (uint8_t *)"\x05\x30\x3c\x0e\x3c\x30", + /* 0x77 w */ (uint8_t *)"\x07\x38\x3e\x06\x1c\x06\x3e\x38", + /* 0x78 x */ (uint8_t *)"\x05\x36\x3e\x08\x3e\x36", + /* 0x79 y */ (uint8_t *)"\x05\x38\x3d\x05\x3f\x3e", + /* 0x7a z */ (uint8_t *)"\x05\x26\x2e\x3a\x32\x22", + /* 0x7b { */ (uint8_t *)"\x04\x10\x7c\xee\x82", + /* 0x7c | */ (uint8_t *)"\x02\xff\xff", + /* 0x7d } */ (uint8_t *)"\x04\x82\xee\x7c\x10", + /* 0x7e ~ */ (uint8_t *)"\x04\x08\x10\x08\x10", + /* 0x7f _ */ (uint8_t *)"\x01\x00", diff --git a/gen/fontfixed.inc b/gen/fontfixed.inc new file mode 100644 index 0000000000..747f190bc9 --- /dev/null +++ b/gen/fontfixed.inc @@ -0,0 +1,128 @@ + /* 0x00 _ */ (uint8_t *)"\x01\x00", + /* 0x01 _ */ (uint8_t *)"\x01\x00", + /* 0x02 _ */ (uint8_t *)"\x01\x00", + /* 0x03 _ */ (uint8_t *)"\x01\x00", + /* 0x04 _ */ (uint8_t *)"\x01\x00", + /* 0x05 _ */ (uint8_t *)"\x01\x00", + /* 0x06 _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", + /* 0x07 _ */ (uint8_t *)"\x01\x00", + /* 0x08 _ */ (uint8_t *)"\x01\x00", + /* 0x09 _ */ (uint8_t *)"\x01\x00", + /* 0x0a _ */ (uint8_t *)"\x01\x00", + /* 0x0b _ */ (uint8_t *)"\x01\x00", + /* 0x0c _ */ (uint8_t *)"\x01\x00", + /* 0x0d _ */ (uint8_t *)"\x01\x00", + /* 0x0e _ */ (uint8_t *)"\x01\x00", + /* 0x0f _ */ (uint8_t *)"\x01\x00", + /* 0x10 _ */ (uint8_t *)"\x01\x00", + /* 0x11 _ */ (uint8_t *)"\x01\x00", + /* 0x12 _ */ (uint8_t *)"\x01\x00", + /* 0x13 _ */ (uint8_t *)"\x01\x00", + /* 0x14 _ */ (uint8_t *)"\x01\x00", + /* 0x15 _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", + /* 0x16 _ */ (uint8_t *)"\x01\x00", + /* 0x17 _ */ (uint8_t *)"\x01\x00", + /* 0x18 _ */ (uint8_t *)"\x01\x00", + /* 0x19 _ */ (uint8_t *)"\x01\x00", + /* 0x1a _ */ (uint8_t *)"\x01\x00", + /* 0x1b _ */ (uint8_t *)"\x01\x00", + /* 0x1c _ */ (uint8_t *)"\x01\x00", + /* 0x1d _ */ (uint8_t *)"\x01\x00", + /* 0x1e _ */ (uint8_t *)"\x01\x00", + /* 0x1f _ */ (uint8_t *)"\x01\x00", + /* 0x20 */ (uint8_t *)"\x01\x00", + /* 0x21 ! */ (uint8_t *)"\x03\x60\xfa\x60", + /* 0x22 " */ (uint8_t *)"\x05\x00\xe0\x00\xe0\x00", + /* 0x23 # */ (uint8_t *)"\x05\x6c\xfe\x6c\xfe\x6c", + /* 0x24 $ */ (uint8_t *)"\x05\x32\xff\x5a\xff\x4c", + /* 0x25 % */ (uint8_t *)"\x05\xc2\xcc\x10\x66\x86", + /* 0x26 & */ (uint8_t *)"\x05\x5c\xa2\xb2\x4c\x1a", + /* 0x27 ' */ (uint8_t *)"\x05\x00\x00\xe0\x00\x00", + /* 0x28 ( */ (uint8_t *)"\x03\x38\x44\x82", + /* 0x29 ) */ (uint8_t *)"\x03\x82\x44\x38", + /* 0x2a * */ (uint8_t *)"\x05\x44\x28\xfe\x28\x44", + /* 0x2b + */ (uint8_t *)"\x05\x10\x10\x7c\x10\x10", + /* 0x2c , */ (uint8_t *)"\x03\x01\x06\x00", + /* 0x2d - */ (uint8_t *)"\x04\x10\x10\x10\x10", + /* 0x2e . */ (uint8_t *)"\x03\x00\x02\x00", + /* 0x2f / */ (uint8_t *)"\x03\x06\x38\xc0", + /* 0x30 0 */ (uint8_t *)"\x05\x7c\x82\x92\x82\x7c", + /* 0x31 1 */ (uint8_t *)"\x05\x00\x42\xfe\x02\x00", + /* 0x32 2 */ (uint8_t *)"\x05\x42\x86\x8a\x92\x62", + /* 0x33 3 */ (uint8_t *)"\x05\x44\x82\x92\x92\x6c", + /* 0x34 4 */ (uint8_t *)"\x05\x18\x28\x48\x88\xfe", + /* 0x35 5 */ (uint8_t *)"\x05\xf4\x92\x92\x92\x8c", + /* 0x36 6 */ (uint8_t *)"\x05\x7c\x92\x92\x92\x4c", + /* 0x37 7 */ (uint8_t *)"\x05\x80\x80\x8e\xb0\xc0", + /* 0x38 8 */ (uint8_t *)"\x05\x6c\x92\x92\x92\x6c", + /* 0x39 9 */ (uint8_t *)"\x05\x64\x92\x92\x92\x7c", + /* 0x3a : */ (uint8_t *)"\x03\x00\x24\x00", + /* 0x3b ; */ (uint8_t *)"\x03\x01\x26\x00", + /* 0x3c < */ (uint8_t *)"\x04\x10\x28\x44\x82", + /* 0x3d = */ (uint8_t *)"\x04\x28\x28\x28\x28", + /* 0x3e > */ (uint8_t *)"\x04\x82\x44\x28\x10", + /* 0x3f ? */ (uint8_t *)"\x05\x40\x80\x9a\xa0\x40", + /* 0x40 @ */ (uint8_t *)"\x05\x7c\x82\x9a\xaa\x72", + /* 0x41 A */ (uint8_t *)"\x05\x7e\x90\x90\x90\x7e", + /* 0x42 B */ (uint8_t *)"\x05\xfe\x92\x92\x92\x6c", + /* 0x43 C */ (uint8_t *)"\x05\x7c\x82\x82\x82\x44", + /* 0x44 D */ (uint8_t *)"\x05\xfe\x82\x82\x82\x7c", + /* 0x45 E */ (uint8_t *)"\x05\xfe\x92\x92\x92\x82", + /* 0x46 F */ (uint8_t *)"\x05\xfe\x90\x90\x90\x80", + /* 0x47 G */ (uint8_t *)"\x05\x7c\x82\x82\x92\x5c", + /* 0x48 H */ (uint8_t *)"\x05\xfe\x10\x10\x10\xfe", + /* 0x49 I */ (uint8_t *)"\x03\x82\xfe\x82", + /* 0x4a J */ (uint8_t *)"\x05\x04\x02\x02\x82\xfc", + /* 0x4b K */ (uint8_t *)"\x05\xfe\x10\x28\x44\x82", + /* 0x4c L */ (uint8_t *)"\x05\xfe\x02\x02\x02\x02", + /* 0x4d M */ (uint8_t *)"\x05\xfe\x40\x30\x40\xfe", + /* 0x4e N */ (uint8_t *)"\x05\xfe\x40\x38\x04\xfe", + /* 0x4f O */ (uint8_t *)"\x05\x7c\x82\x82\x82\x7c", + /* 0x50 P */ (uint8_t *)"\x05\xfe\x90\x90\x90\x60", + /* 0x51 Q */ (uint8_t *)"\x05\x7c\x82\x8a\x84\x7a", + /* 0x52 R */ (uint8_t *)"\x05\xfe\x90\x98\x94\x62", + /* 0x53 S */ (uint8_t *)"\x05\x64\x92\x92\x92\x4c", + /* 0x54 T */ (uint8_t *)"\x05\x80\x80\xfe\x80\x80", + /* 0x55 U */ (uint8_t *)"\x05\xfc\x02\x02\x02\xfc", + /* 0x56 V */ (uint8_t *)"\x05\xe0\x18\x06\x18\xe0", + /* 0x57 W */ (uint8_t *)"\x05\xfc\x02\x1c\x02\xfc", + /* 0x58 X */ (uint8_t *)"\x05\xc6\x28\x10\x28\xc6", + /* 0x59 Y */ (uint8_t *)"\x05\xc0\x20\x1e\x20\xc0", + /* 0x5a Z */ (uint8_t *)"\x05\x86\x8a\x92\xa2\xc2", + /* 0x5b [ */ (uint8_t *)"\x03\xfe\x82\x82", + /* 0x5c \ */ (uint8_t *)"\x03\xe0\x38\x0e", + /* 0x5d ] */ (uint8_t *)"\x03\x82\x82\xfe", + /* 0x5e ^ */ (uint8_t *)"\x03\x60\xc0\x60", + /* 0x5f _ */ (uint8_t *)"\x05\x02\x02\x02\x02\x02", + /* 0x60 ` */ (uint8_t *)"\x05\x00\x80\x40\x20\x00", + /* 0x61 a */ (uint8_t *)"\x05\x04\x2a\x2a\x2a\x1e", + /* 0x62 b */ (uint8_t *)"\x05\xfe\x22\x22\x22\x1c", + /* 0x63 c */ (uint8_t *)"\x05\x1c\x22\x22\x22\x14", + /* 0x64 d */ (uint8_t *)"\x05\x1c\x22\x22\x22\xfe", + /* 0x65 e */ (uint8_t *)"\x05\x1c\x2a\x2a\x2a\x1a", + /* 0x66 f */ (uint8_t *)"\x05\x00\x10\x7e\x90\x40", + /* 0x67 g */ (uint8_t *)"\x05\x18\x25\x25\x25\x3e", + /* 0x68 h */ (uint8_t *)"\x05\xfe\x20\x20\x20\x1e", + /* 0x69 i */ (uint8_t *)"\x05\x00\x22\xbe\x02\x00", + /* 0x6a j */ (uint8_t *)"\x05\x02\x21\xbe\x00\x00", + /* 0x6b k */ (uint8_t *)"\x05\xfe\x08\x14\x22\x00", + /* 0x6c l */ (uint8_t *)"\x05\x00\x82\xfe\x02\x00", + /* 0x6d m */ (uint8_t *)"\x05\x3e\x20\x1e\x20\x1e", + /* 0x6e n */ (uint8_t *)"\x05\x3e\x20\x20\x20\x1e", + /* 0x6f o */ (uint8_t *)"\x05\x1c\x22\x22\x22\x1c", + /* 0x70 p */ (uint8_t *)"\x05\x3f\x24\x24\x24\x18", + /* 0x71 q */ (uint8_t *)"\x05\x18\x24\x24\x24\x3f", + /* 0x72 r */ (uint8_t *)"\x05\x3e\x10\x20\x20\x10", + /* 0x73 s */ (uint8_t *)"\x05\x12\x2a\x2a\x2a\x24", + /* 0x74 t */ (uint8_t *)"\x05\x00\x20\xfc\x22\x02", + /* 0x75 u */ (uint8_t *)"\x05\x3c\x02\x02\x02\x3e", + /* 0x76 v */ (uint8_t *)"\x05\x30\x0c\x02\x0c\x30", + /* 0x77 w */ (uint8_t *)"\x05\x3c\x02\x0c\x02\x3c", + /* 0x78 x */ (uint8_t *)"\x05\x22\x36\x08\x36\x22", + /* 0x79 y */ (uint8_t *)"\x05\x38\x05\x05\x05\x3e", + /* 0x7a z */ (uint8_t *)"\x05\x22\x26\x2a\x32\x22", + /* 0x7b { */ (uint8_t *)"\x04\x10\x7c\xee\x82", + /* 0x7c | */ (uint8_t *)"\x03\x00\xfe\x00", + /* 0x7d } */ (uint8_t *)"\x04\x82\xee\x7c\x10", + /* 0x7e ~ */ (uint8_t *)"\x05\x18\x20\x10\x08\x30", + /* 0x7f _ */ (uint8_t *)"\x01\x00", diff --git a/gen/fonts.c b/gen/fonts.c index a9f23df755..68deb549bc 100644 --- a/gen/fonts.c +++ b/gen/fonts.c @@ -1,268 +1,18 @@ #include "fonts.h" -const uint8_t * const font_data[256] = { - /* 0x00 _ */ (uint8_t *)"\x01\x00", - /* 0x01 _ */ (uint8_t *)"\x01\x00", - /* 0x02 _ */ (uint8_t *)"\x01\x00", - /* 0x03 _ */ (uint8_t *)"\x01\x00", - /* 0x04 _ */ (uint8_t *)"\x01\x00", - /* 0x05 _ */ (uint8_t *)"\x01\x00", - /* 0x06 _ */ (uint8_t *)"\x07\x18\x1c\x0e\x18\x30\x40\x80", - /* 0x07 _ */ (uint8_t *)"\x01\x00", - /* 0x08 _ */ (uint8_t *)"\x01\x00", - /* 0x09 _ */ (uint8_t *)"\x01\x00", - /* 0x0a _ */ (uint8_t *)"\x01\x00", - /* 0x0b _ */ (uint8_t *)"\x01\x00", - /* 0x0c _ */ (uint8_t *)"\x01\x00", - /* 0x0d _ */ (uint8_t *)"\x01\x00", - /* 0x0e _ */ (uint8_t *)"\x01\x00", - /* 0x0f _ */ (uint8_t *)"\x01\x00", - /* 0x10 _ */ (uint8_t *)"\x01\x00", - /* 0x11 _ */ (uint8_t *)"\x01\x00", - /* 0x12 _ */ (uint8_t *)"\x01\x00", - /* 0x13 _ */ (uint8_t *)"\x01\x00", - /* 0x14 _ */ (uint8_t *)"\x01\x00", - /* 0x15 _ */ (uint8_t *)"\x07\x44\xee\x7c\x38\x7c\xee\x44", - /* 0x16 _ */ (uint8_t *)"\x01\x00", - /* 0x17 _ */ (uint8_t *)"\x01\x00", - /* 0x18 _ */ (uint8_t *)"\x01\x00", - /* 0x19 _ */ (uint8_t *)"\x01\x00", - /* 0x1a _ */ (uint8_t *)"\x01\x00", - /* 0x1b _ */ (uint8_t *)"\x01\x00", - /* 0x1c _ */ (uint8_t *)"\x01\x00", - /* 0x1d _ */ (uint8_t *)"\x01\x00", - /* 0x1e _ */ (uint8_t *)"\x01\x00", - /* 0x1f _ */ (uint8_t *)"\x01\x00", - /* 0x20 */ (uint8_t *)"\x01\x00", - /* 0x21 ! */ (uint8_t *)"\x02\xfa\xfa", - /* 0x22 " */ (uint8_t *)"\x03\xc0\x00\xc0", - /* 0x23 # */ (uint8_t *)"\x05\x6c\xfe\x6c\xfe\x6c", - /* 0x24 $ */ (uint8_t *)"\x05\x32\xff\x5a\xff\x4c", - /* 0x25 % */ (uint8_t *)"\x06\xc0\xc6\x1c\x70\xc6\x06", - /* 0x26 & */ (uint8_t *)"\x06\x5c\xfe\xb2\xfe\x4c\x1e", - /* 0x27 ' */ (uint8_t *)"\x01\xc0", - /* 0x28 ( */ (uint8_t *)"\x03\x38\x7c\x82", - /* 0x29 ) */ (uint8_t *)"\x03\x82\x7c\x38", - /* 0x2a * */ (uint8_t *)"\x05\x6c\x38\xfe\x38\x6c", - /* 0x2b + */ (uint8_t *)"\x05\x10\x10\x7c\x10\x10", - /* 0x2c , */ (uint8_t *)"\x02\x03\x06", - /* 0x2d - */ (uint8_t *)"\x04\x10\x10\x10\x10", - /* 0x2e . */ (uint8_t *)"\x02\x06\x06", - /* 0x2f / */ (uint8_t *)"\x03\x0e\x38\xe0", - /* 0x30 0 */ (uint8_t *)"\x05\x7c\xfe\x82\xfe\x7c", - /* 0x31 1 */ (uint8_t *)"\x03\x40\xfe\xfe", - /* 0x32 2 */ (uint8_t *)"\x05\x8e\x9e\x92\xf2\x62", - /* 0x33 3 */ (uint8_t *)"\x05\x82\x92\x92\xfe\x6c", - /* 0x34 4 */ (uint8_t *)"\x05\x18\x28\x48\xfe\xfe", - /* 0x35 5 */ (uint8_t *)"\x05\xe2\xa2\xa2\xbe\x1c", - /* 0x36 6 */ (uint8_t *)"\x05\x7c\xfe\xa2\xbe\x1c", - /* 0x37 7 */ (uint8_t *)"\x05\x80\x8e\xbe\xf0\xc0", - /* 0x38 8 */ (uint8_t *)"\x05\x6c\xfe\x92\xfe\x6c", - /* 0x39 9 */ (uint8_t *)"\x05\x70\xfa\x8a\xfe\x7c", - /* 0x3a : */ (uint8_t *)"\x02\x36\x36", - /* 0x3b ; */ (uint8_t *)"\x02\x33\x36", - /* 0x3c < */ (uint8_t *)"\x04\x10\x38\x6c\xc6", - /* 0x3d = */ (uint8_t *)"\x04\x28\x28\x28\x28", - /* 0x3e > */ (uint8_t *)"\x04\xc6\x6c\x38\x10", - /* 0x3f ? */ (uint8_t *)"\x05\x80\x9a\xba\xe0\x40", - /* 0x40 @ */ (uint8_t *)"\x06\x7c\xfe\xaa\xba\xfa\x78", - /* 0x41 A */ (uint8_t *)"\x05\x7e\xfe\x88\xfe\x7e", - /* 0x42 B */ (uint8_t *)"\x05\xfe\xfe\xa2\xfe\x5c", - /* 0x43 C */ (uint8_t *)"\x05\x7c\xfe\x82\x82\x82", - /* 0x44 D */ (uint8_t *)"\x05\xfe\xfe\x82\xfe\x7c", - /* 0x45 E */ (uint8_t *)"\x05\xfe\xfe\xa2\xa2\x82", - /* 0x46 F */ (uint8_t *)"\x05\xfe\xfe\xa0\xa0\x80", - /* 0x47 G */ (uint8_t *)"\x05\x7c\xfe\x82\x9e\x1e", - /* 0x48 H */ (uint8_t *)"\x05\xfe\xfe\x20\xfe\xfe", - /* 0x49 I */ (uint8_t *)"\x02\xfe\xfe", - /* 0x4a J */ (uint8_t *)"\x04\x02\x02\xfe\xfc", - /* 0x4b K */ (uint8_t *)"\x06\xfe\xfe\x38\x6c\xc6\x82", - /* 0x4c L */ (uint8_t *)"\x04\xfe\xfe\x02\x02", - /* 0x4d M */ (uint8_t *)"\x07\xfe\x7e\x30\x18\x30\x7e\xfe", - /* 0x4e N */ (uint8_t *)"\x06\xfe\x7e\x30\x18\xfc\xfe", - /* 0x4f O */ (uint8_t *)"\x06\x7c\xfe\x82\x82\xfe\x7c", - /* 0x50 P */ (uint8_t *)"\x05\xfe\xfe\x88\xf8\x70", - /* 0x51 Q */ (uint8_t *)"\x06\x7c\xfe\x82\x86\xff\x7d", - /* 0x52 R */ (uint8_t *)"\x05\xfe\xfe\x88\xfe\x72", - /* 0x53 S */ (uint8_t *)"\x04\x62\xf2\x9e\x8c", - /* 0x54 T */ (uint8_t *)"\x06\x80\x80\xfe\xfe\x80\x80", - /* 0x55 U */ (uint8_t *)"\x05\xfc\xfe\x02\xfe\xfc", - /* 0x56 V */ (uint8_t *)"\x06\xe0\xf8\x1e\x1e\xf8\xe0", - /* 0x57 W */ (uint8_t *)"\x07\xf0\xfe\x1e\x3c\x1e\xfe\xf0", - /* 0x58 X */ (uint8_t *)"\x06\xc6\xee\x38\x38\xee\xc6", - /* 0x59 Y */ (uint8_t *)"\x06\xc0\xe0\x3e\x3e\xe0\xc0", - /* 0x5a Z */ (uint8_t *)"\x05\x8e\x9e\xba\xf2\xe2", - /* 0x5b [ */ (uint8_t *)"\x03\xfe\xfe\x82", - /* 0x5c \ */ (uint8_t *)"\x03\xe0\x38\x0e", - /* 0x5d ] */ (uint8_t *)"\x03\x82\xfe\xfe", - /* 0x5e ^ */ (uint8_t *)"\x03\x60\xc0\x60", - /* 0x5f _ */ (uint8_t *)"\x06\x02\x02\x02\x02\x02\x02", - /* 0x60 ` */ (uint8_t *)"\x02\x80\x40", - /* 0x61 a */ (uint8_t *)"\x05\x04\x2e\x2a\x3e\x1e", - /* 0x62 b */ (uint8_t *)"\x05\xfe\xfe\x22\x3e\x1c", - /* 0x63 c */ (uint8_t *)"\x05\x1c\x3e\x22\x36\x14", - /* 0x64 d */ (uint8_t *)"\x05\x1c\x3e\x22\xfe\xfe", - /* 0x65 e */ (uint8_t *)"\x05\x1c\x3e\x2a\x3a\x1a", - /* 0x66 f */ (uint8_t *)"\x03\x7e\xfe\xa0", - /* 0x67 g */ (uint8_t *)"\x05\x18\x3d\x25\x3f\x3e", - /* 0x68 h */ (uint8_t *)"\x05\xfe\xfe\x20\x3e\x1e", - /* 0x69 i */ (uint8_t *)"\x02\xbe\xbe", - /* 0x6a j */ (uint8_t *)"\x03\x01\xbf\xbe", - /* 0x6b k */ (uint8_t *)"\x05\xfe\xfe\x1c\x36\x22", - /* 0x6c l */ (uint8_t *)"\x02\xfe\xfe", - /* 0x6d m */ (uint8_t *)"\x08\x3e\x3e\x20\x3e\x3e\x20\x3e\x1e", - /* 0x6e n */ (uint8_t *)"\x05\x3e\x3e\x20\x3e\x1e", - /* 0x6f o */ (uint8_t *)"\x05\x1c\x3e\x22\x3e\x1c", - /* 0x70 p */ (uint8_t *)"\x05\x3f\x3f\x24\x3c\x18", - /* 0x71 q */ (uint8_t *)"\x05\x18\x3c\x24\x3f\x3f", - /* 0x72 r */ (uint8_t *)"\x04\x3e\x3e\x10\x30", - /* 0x73 s */ (uint8_t *)"\x04\x1a\x3a\x2e\x2c", - /* 0x74 t */ (uint8_t *)"\x03\xfc\xfe\x22", - /* 0x75 u */ (uint8_t *)"\x05\x3c\x3e\x02\x3e\x3e", - /* 0x76 v */ (uint8_t *)"\x05\x30\x3c\x0e\x3c\x30", - /* 0x77 w */ (uint8_t *)"\x07\x38\x3e\x06\x1c\x06\x3e\x38", - /* 0x78 x */ (uint8_t *)"\x05\x36\x3e\x08\x3e\x36", - /* 0x79 y */ (uint8_t *)"\x05\x38\x3d\x05\x3f\x3e", - /* 0x7a z */ (uint8_t *)"\x05\x26\x2e\x3a\x32\x22", - /* 0x7b { */ (uint8_t *)"\x04\x10\x7c\xee\x82", - /* 0x7c | */ (uint8_t *)"\x02\xff\xff", - /* 0x7d } */ (uint8_t *)"\x04\x82\xee\x7c\x10", - /* 0x7e ~ */ (uint8_t *)"\x04\x08\x10\x08\x10", - /* 0x7f _ */ (uint8_t *)"\x01\x00", - /* 0x80 _ */ (uint8_t *)"\x01\x00", - /* 0x81 _ */ (uint8_t *)"\x01\x00", - /* 0x82 _ */ (uint8_t *)"\x01\x00", - /* 0x83 _ */ (uint8_t *)"\x01\x00", - /* 0x84 _ */ (uint8_t *)"\x01\x00", - /* 0x85 _ */ (uint8_t *)"\x01\x00", - /* 0x86 _ */ (uint8_t *)"\x01\x00", - /* 0x87 _ */ (uint8_t *)"\x01\x00", - /* 0x88 _ */ (uint8_t *)"\x01\x00", - /* 0x89 _ */ (uint8_t *)"\x01\x00", - /* 0x8a _ */ (uint8_t *)"\x01\x00", - /* 0x8b _ */ (uint8_t *)"\x01\x00", - /* 0x8c _ */ (uint8_t *)"\x01\x00", - /* 0x8d _ */ (uint8_t *)"\x01\x00", - /* 0x8e _ */ (uint8_t *)"\x01\x00", - /* 0x8f _ */ (uint8_t *)"\x01\x00", - /* 0x90 _ */ (uint8_t *)"\x01\x00", - /* 0x91 _ */ (uint8_t *)"\x01\x00", - /* 0x92 _ */ (uint8_t *)"\x01\x00", - /* 0x93 _ */ (uint8_t *)"\x01\x00", - /* 0x94 _ */ (uint8_t *)"\x01\x00", - /* 0x95 _ */ (uint8_t *)"\x01\x00", - /* 0x96 _ */ (uint8_t *)"\x01\x00", - /* 0x97 _ */ (uint8_t *)"\x01\x00", - /* 0x98 _ */ (uint8_t *)"\x01\x00", - /* 0x99 _ */ (uint8_t *)"\x01\x00", - /* 0x9a _ */ (uint8_t *)"\x01\x00", - /* 0x9b _ */ (uint8_t *)"\x01\x00", - /* 0x9c _ */ (uint8_t *)"\x01\x00", - /* 0x9d _ */ (uint8_t *)"\x01\x00", - /* 0x9e _ */ (uint8_t *)"\x01\x00", - /* 0x9f _ */ (uint8_t *)"\x01\x00", - /* 0xa0 _ */ (uint8_t *)"\x01\x00", - /* 0xa1 _ */ (uint8_t *)"\x01\x00", - /* 0xa2 _ */ (uint8_t *)"\x01\x00", - /* 0xa3 _ */ (uint8_t *)"\x01\x00", - /* 0xa4 _ */ (uint8_t *)"\x01\x00", - /* 0xa5 _ */ (uint8_t *)"\x01\x00", - /* 0xa6 _ */ (uint8_t *)"\x01\x00", - /* 0xa7 _ */ (uint8_t *)"\x01\x00", - /* 0xa8 _ */ (uint8_t *)"\x01\x00", - /* 0xa9 _ */ (uint8_t *)"\x01\x00", - /* 0xaa _ */ (uint8_t *)"\x01\x00", - /* 0xab _ */ (uint8_t *)"\x01\x00", - /* 0xac _ */ (uint8_t *)"\x01\x00", - /* 0xad _ */ (uint8_t *)"\x01\x00", - /* 0xae _ */ (uint8_t *)"\x01\x00", - /* 0xaf _ */ (uint8_t *)"\x01\x00", - /* 0xb0 _ */ (uint8_t *)"\x01\x00", - /* 0xb1 _ */ (uint8_t *)"\x01\x00", - /* 0xb2 _ */ (uint8_t *)"\x01\x00", - /* 0xb3 _ */ (uint8_t *)"\x01\x00", - /* 0xb4 _ */ (uint8_t *)"\x01\x00", - /* 0xb5 _ */ (uint8_t *)"\x01\x00", - /* 0xb6 _ */ (uint8_t *)"\x01\x00", - /* 0xb7 _ */ (uint8_t *)"\x01\x00", - /* 0xb8 _ */ (uint8_t *)"\x01\x00", - /* 0xb9 _ */ (uint8_t *)"\x01\x00", - /* 0xba _ */ (uint8_t *)"\x01\x00", - /* 0xbb _ */ (uint8_t *)"\x01\x00", - /* 0xbc _ */ (uint8_t *)"\x01\x00", - /* 0xbd _ */ (uint8_t *)"\x01\x00", - /* 0xbe _ */ (uint8_t *)"\x01\x00", - /* 0xbf _ */ (uint8_t *)"\x01\x00", - /* 0xc0 _ */ (uint8_t *)"\x01\x00", - /* 0xc1 _ */ (uint8_t *)"\x01\x00", - /* 0xc2 _ */ (uint8_t *)"\x01\x00", - /* 0xc3 _ */ (uint8_t *)"\x01\x00", - /* 0xc4 _ */ (uint8_t *)"\x01\x00", - /* 0xc5 _ */ (uint8_t *)"\x01\x00", - /* 0xc6 _ */ (uint8_t *)"\x01\x00", - /* 0xc7 _ */ (uint8_t *)"\x01\x00", - /* 0xc8 _ */ (uint8_t *)"\x01\x00", - /* 0xc9 _ */ (uint8_t *)"\x01\x00", - /* 0xca _ */ (uint8_t *)"\x01\x00", - /* 0xcb _ */ (uint8_t *)"\x01\x00", - /* 0xcc _ */ (uint8_t *)"\x01\x00", - /* 0xcd _ */ (uint8_t *)"\x01\x00", - /* 0xce _ */ (uint8_t *)"\x01\x00", - /* 0xcf _ */ (uint8_t *)"\x01\x00", - /* 0xd0 _ */ (uint8_t *)"\x01\x00", - /* 0xd1 _ */ (uint8_t *)"\x01\x00", - /* 0xd2 _ */ (uint8_t *)"\x01\x00", - /* 0xd3 _ */ (uint8_t *)"\x01\x00", - /* 0xd4 _ */ (uint8_t *)"\x01\x00", - /* 0xd5 _ */ (uint8_t *)"\x01\x00", - /* 0xd6 _ */ (uint8_t *)"\x01\x00", - /* 0xd7 _ */ (uint8_t *)"\x01\x00", - /* 0xd8 _ */ (uint8_t *)"\x01\x00", - /* 0xd9 _ */ (uint8_t *)"\x01\x00", - /* 0xda _ */ (uint8_t *)"\x01\x00", - /* 0xdb _ */ (uint8_t *)"\x01\x00", - /* 0xdc _ */ (uint8_t *)"\x01\x00", - /* 0xdd _ */ (uint8_t *)"\x01\x00", - /* 0xde _ */ (uint8_t *)"\x01\x00", - /* 0xdf _ */ (uint8_t *)"\x01\x00", - /* 0xe0 _ */ (uint8_t *)"\x01\x00", - /* 0xe1 _ */ (uint8_t *)"\x01\x00", - /* 0xe2 _ */ (uint8_t *)"\x01\x00", - /* 0xe3 _ */ (uint8_t *)"\x01\x00", - /* 0xe4 _ */ (uint8_t *)"\x01\x00", - /* 0xe5 _ */ (uint8_t *)"\x01\x00", - /* 0xe6 _ */ (uint8_t *)"\x01\x00", - /* 0xe7 _ */ (uint8_t *)"\x01\x00", - /* 0xe8 _ */ (uint8_t *)"\x01\x00", - /* 0xe9 _ */ (uint8_t *)"\x01\x00", - /* 0xea _ */ (uint8_t *)"\x01\x00", - /* 0xeb _ */ (uint8_t *)"\x01\x00", - /* 0xec _ */ (uint8_t *)"\x01\x00", - /* 0xed _ */ (uint8_t *)"\x01\x00", - /* 0xee _ */ (uint8_t *)"\x01\x00", - /* 0xef _ */ (uint8_t *)"\x01\x00", - /* 0xf0 _ */ (uint8_t *)"\x01\x00", - /* 0xf1 _ */ (uint8_t *)"\x01\x00", - /* 0xf2 _ */ (uint8_t *)"\x01\x00", - /* 0xf3 _ */ (uint8_t *)"\x01\x00", - /* 0xf4 _ */ (uint8_t *)"\x01\x00", - /* 0xf5 _ */ (uint8_t *)"\x01\x00", - /* 0xf6 _ */ (uint8_t *)"\x01\x00", - /* 0xf7 _ */ (uint8_t *)"\x01\x00", - /* 0xf8 _ */ (uint8_t *)"\x01\x00", - /* 0xf9 _ */ (uint8_t *)"\x01\x00", - /* 0xfa _ */ (uint8_t *)"\x01\x00", - /* 0xfb _ */ (uint8_t *)"\x01\x00", - /* 0xfc _ */ (uint8_t *)"\x01\x00", - /* 0xfd _ */ (uint8_t *)"\x01\x00", - /* 0xfe _ */ (uint8_t *)"\x01\x00", - /* 0xff _ */ (uint8_t *)"\x01\x00", +const uint8_t * const font_data[2][128] = { + { +#include"font.inc" + }, + { +#include"fontfixed.inc" + }, }; -int fontCharWidth(char c) { - return font_data[(int)(c)][0]; +int fontCharWidth(int font, char c) { + return font_data[font][c & 0x7f][0]; } -const uint8_t *fontCharData(char c) { - return font_data[(int)(c)] + 1; +const uint8_t *fontCharData(int font, char c) { + return font_data[font][c & 0x7f] + 1; } diff --git a/gen/fonts.h b/gen/fonts.h index 43ca21a6fb..dbbbef1303 100644 --- a/gen/fonts.h +++ b/gen/fonts.h @@ -4,10 +4,13 @@ #include #define FONT_HEIGHT 8 +#define FONT_STANDARD 0 +#define FONT_FIXED 1 +#define FONT_DOUBLE 0x80 -extern const uint8_t * const font_data[256]; +extern const uint8_t * const font_data[2][128]; -int fontCharWidth(char c); -const uint8_t *fontCharData(char c); +int fontCharWidth(int font, char c); +const uint8_t *fontCharData(int font, char c); #endif diff --git a/gen/fonts/fontfixed.png b/gen/fonts/fontfixed.png new file mode 100644 index 0000000000000000000000000000000000000000..13f8d90727b23e21752de0ddbf56ae2a6fb03f5c GIT binary patch literal 1761 zcmdUw`#Tc~7{})lHMg9xB}L9-N4CjilOtKpC7XM-v7}UHjwP2hB$0?yq}psW$0gzv zGw004S#AeM<#wi!h+#uLCBs}=SVw=x`QiJ1p6C1i@_nB7dA{#$f8XPJz}-Lq0HBBS zbUU%d((l@?zBMLvBGBgT_N0|0bD-=zlN{I+Y$)V_lAao3irYZ?7$vU8hq1OU*w zfpa@{Dsl94(G=tHKHZGArOk6A>vjn+n1y9o`}L6Ez~I8PV;s%b>X3Z$4!f{FGwz)} z`OmKWmD-Xhh3OmX<$Jqie1w`V4mqdq8Ixo8{LA__VAjf{dE;O58=AF`+voo<(-q3H zA{>c6VP2($3!(jXZG4SZ%3X_0=thc4rAi~xDVtBUU%MFurdt;m@_av(zNbPhKxGZd{t(1C`b%znrtjg)w?RtjAO_an6EX^H* zK^6!~vu=dw#79m;$#3X$v{j8ee32CgRZV&aB$m4xe`+0jpjh8ZJ)1f66J6x%GrKAr zQc*3ETFqr+;}})O%5d~>?)gOm0vglAX{k5#ju1cg3yj2+;^L+ki>YfWxw=V>qJdUT z{7T()obSJ@-D8n7aXjB|CRRu>gF)!i3(RY5V?WRs3TzCw)sJ)y9BqFt2{R48n^``$ z<78uamqn5sC?e;D>pP(Q_7gTF(!V384Z^_}lpnfVHL?7&DV1R%CeI?$Yr|P+m#UX3oN^(-5UK;!(alssU=2zcZ0?f%0HMIR8%&i{PNDAax$^L0fgyD@k5E4Xk}%Wn zKik=SYt0(~8Fe;~>sBPd$(6K`3w@s`airt%E+8r!giI}r4q7B0D5z)QkLd7FPYZr` za)(mNhOp7F%Ai?IZ?IF?b)P4xEfuyIX(A~0Pu|+h=lI#a#PwpQhN^;uhc5&!YCX!e za~ORu!e$-j+5oEA;fs0uoQQky%dnQ9{}R*Rt~VT_*RtTEbY=Tc*qx#VNtaRUFsN(> z3HM^{o?1;Zw#ni)Pg_<8ynhtPRkDwMjp_Rr7ouNR-09|UVehxEO=W}SD{;cuY~qZd z*j_&mk%vGE7!`v#^EUA60N*07ADpmxY(8|wheu*u9wggV#@u5NSf|E<>I-&r=m(+> zf`o8kAs>JM&s*fu*M=ebH7=G9j0g0G_zvD3cH-}I#roby0lTM43#PNIvyT+atHM^t$3e& z8O193d0M>EhrA#-A|Dxgm{>=a^=r9})#)Eh1DJmI*+R&>d z4_wAV=IvkSq4$^#3rLPW)vobgcJO#XE0FU%YeAxL>n)m{)d-+fhgN_{GL+ ze_So0#p{g#?{e>?vqNAHnNfw1W>0sg6lcq-AAoHp=oQXF#8|pj&Lb(Pt36kl6X718 za1J9D|7vSyxP11JER7_)n2n%k7j-2@xm5mqkV@kle5A_Zq^gJfa6cl!5@n#Tpp!c% zqbL7*btM0rtQaxm4tv9ivW8yc1MuKKtVy<7V3PgESn10a{~y)}o2y~ugbkzCL((?C z3Y1Gg0tU;9yGhI1g_T!0tKgQ5?wk zcu%}J{YrXdzA-w;x88njXj)#Y6Y^tJY`JT4TheVNEp(>aspC>?@>|Z4Pn|%6O`G}a z%NdPlC_*O3^lCuJuPuSbPAwX@8MeT6QDjzKlhr3=4{`j8)r8JZStB0Rb#Z;ih}Y$b zHs3H+p|ip7= 32 and i <= 126 else '_' - print('\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur)) + with open(outfile, 'w') as f: + for i in range(128): + x = (i % 16) * 10 + y = (i // 16) * 10 + cur = '' + while img.pixel(x, y) != None: + val = ''.join(img.pixel(x, y + j) for j in range(8)) + x += 1 + cur += '\\x%02x' % int(val, 2) + cur = '\\x%02x' % (len(cur) // 4) + cur + ch = chr(i) if i >= 32 and i <= 126 else '_' + f.write('\t/* 0x%02x %c */ (uint8_t *)"%s",\n' % (i, ch , cur)) + +convert('fonts/fontfixed.png', 'fontfixed.inc') +convert('fonts/font.png', 'font.inc') diff --git a/gen/strwidth.c b/gen/strwidth.c index c12f7b0b0d..8ba3f1c367 100644 --- a/gen/strwidth.c +++ b/gen/strwidth.c @@ -17,6 +17,7 @@ static inline char convert(char c) { int main(int argc, char **argv) { char *line; + int font = FONT_STANDARD; while ((line = readline(NULL)) != NULL) { size_t length = strlen(line); if (length) { @@ -25,7 +26,7 @@ int main(int argc, char **argv) { size_t width = 0; for (size_t i = 0; i < length; i++) { - width += fontCharWidth(convert(line[i])) + 1; + width += fontCharWidth(font, convert(line[i])) + 1; } printf("%zu\n", width); diff --git a/layout.c b/layout.c index 98e6e59960..f29aadbb19 100644 --- a/layout.c +++ b/layout.c @@ -30,31 +30,31 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con oledDrawBitmap(0, 0, icon); left = icon->width + 4; } - if (line1) oledDrawString(left, 0 * 9, line1); - if (line2) oledDrawString(left, 1 * 9, line2); - if (line3) oledDrawString(left, 2 * 9, line3); - if (line4) oledDrawString(left, 3 * 9, line4); + if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD); + if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD); + if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); + if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); if (desc) { - oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc); + oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 21); } } else { - if (line5) oledDrawString(left, 4 * 9, line5); - if (line6) oledDrawString(left, 5 * 9, line6); + if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD); + if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 13); } } if (btnNo) { - oledDrawString(1, OLED_HEIGHT - 8, "\x15"); - oledDrawString(fontCharWidth('\x15') + 3, OLED_HEIGHT - 8, btnNo); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth('\x15') + oledStringWidth(btnNo) + 2, OLED_HEIGHT - 1); + oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); + oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); } if (btnYes) { - oledDrawString(OLED_WIDTH - fontCharWidth('\x06') - 1, OLED_HEIGHT - 8, "\x06"); - oledDrawString(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 3, OLED_HEIGHT - 8, btnYes); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes) - fontCharWidth('\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } oledRefresh(); } @@ -100,7 +100,7 @@ void layoutProgress(const char *desc, int permil) // text oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); if (desc) { - oledDrawStringCenter(OLED_HEIGHT - 16, desc); + oledDrawStringCenter(OLED_HEIGHT - 16, desc, FONT_STANDARD); } oledRefresh(); } diff --git a/oled.c b/oled.c index 0467690aa5..54a15b643c 100644 --- a/oled.c +++ b/oled.c @@ -236,14 +236,15 @@ void oledSetBuffer(uint8_t *buf) memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); } -void oledDrawChar(int x, int y, char c, int zoom) +void oledDrawChar(int x, int y, char c, int font) { if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { return; } - int char_width = fontCharWidth(c); - const uint8_t *char_data = fontCharData(c); + int zoom = (font & FONT_DOUBLE ? 2 : 1); + int char_width = fontCharWidth(font & 0x7f, c); + const uint8_t *char_data = fontCharData(font & 0x7f, c); if (x <= -char_width * zoom) { return; @@ -272,41 +273,43 @@ char oledConvertChar(const char c) { return 0; } -int oledStringWidth(const char *text) { +int oledStringWidth(const char *text, int font) { if (!text) return 0; + int size = (font & FONT_DOUBLE ? 2 : 1); int l = 0; for (; *text; text++) { char c = oledConvertChar(*text); if (c) { - l += fontCharWidth(c) + 1; + l += size * (fontCharWidth(font & 0x7f, c) + 1); } } return l; } -void oledDrawStringSize(int x, int y, const char* text, int size) +void oledDrawString(int x, int y, const char* text, int font) { if (!text) return; int l = 0; + int size = (font & FONT_DOUBLE ? 2 : 1); for (; *text; text++) { char c = oledConvertChar(*text); if (c) { - oledDrawChar(x + l, y, c, size); - l += size * (fontCharWidth(c) + 1); + oledDrawChar(x + l, y, c, font); + l += size * (fontCharWidth(font & 0x7f, c) + 1); } } } -void oledDrawStringCenter(int y, const char* text) +void oledDrawStringCenter(int y, const char* text, int font) { - int x = ( OLED_WIDTH - oledStringWidth(text) ) / 2; - oledDrawString(x, y, text); + int x = ( OLED_WIDTH - oledStringWidth(text, font) ) / 2; + oledDrawString(x, y, text, font); } -void oledDrawStringRight(int x, int y, const char* text) +void oledDrawStringRight(int x, int y, const char* text, int font) { - x -= oledStringWidth(text); - oledDrawString(x, y, text); + x -= oledStringWidth(text, font); + oledDrawString(x, y, text, font); } void oledDrawBitmap(int x, int y, const BITMAP *bmp) diff --git a/oled.h b/oled.h index 845e1e2b27..fcd7cc7d1b 100644 --- a/oled.h +++ b/oled.h @@ -43,13 +43,11 @@ void oledDrawPixel(int x, int y); void oledClearPixel(int x, int y); void oledInvertPixel(int x, int y); void oledDrawChar(int x, int y, char c, int zoom); -int oledStringWidth(const char *text); +int oledStringWidth(const char *text, int font); -#define oledDrawString(x, y, text) oledDrawStringSize((x), (y), (text), 1) -#define oledDrawStringDouble(x, y, text) oledDrawStringSize((x), (y), (text), 2) -void oledDrawStringSize(int x, int y, const char* text, int size); -void oledDrawStringCenter(int y, const char* text); -void oledDrawStringRight(int x, int y, const char* text); +void oledDrawString(int x, int y, const char* text, int font); +void oledDrawStringCenter(int y, const char* text, int font); +void oledDrawStringRight(int x, int y, const char* text, int font); void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledInvert(int x1, int y1, int x2, int y2); void oledBox(int x1, int y1, int x2, int y2, bool set); From b9b36e0768466640d4a8f33ef09aeba91530f771 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 6 Feb 2018 22:34:31 +0100 Subject: [PATCH 0740/1154] Remove duplicated code --- firmware/layout2.c | 14 +++----------- layout.c | 22 ++++++++++++++++------ layout.h | 2 ++ 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 528205b1a2..fe6c920eac 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -320,9 +320,7 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, FONT_STANDARD); oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); oledHLine(OLED_HEIGHT - 13); - oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); - oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + layoutButtonYes(btnYes); oledRefresh(); } @@ -500,16 +498,10 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno } if (!qrcode) { - static const char *btnNo = _("QR Code"); - oledDrawString(2, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); - oledInvert(0, OLED_HEIGHT - 9, oledStringWidth(btnNo, FONT_STANDARD) + 3, OLED_HEIGHT - 1); + layoutButtonNo(_("QR Code")); } - static const char *btnYes = _("Continue"); - oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); - oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); - + layoutButtonYes(_("Continue")); oledRefresh(); } diff --git a/layout.c b/layout.c index f29aadbb19..cb8302b904 100644 --- a/layout.c +++ b/layout.c @@ -22,6 +22,20 @@ #include "layout.h" #include "oled.h" +void layoutButtonNo(const char *btnNo) +{ + oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); + oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); +} + +void layoutButtonYes(const char *btnYes) +{ + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); +} + void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { int left = 0; @@ -47,14 +61,10 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con } } if (btnNo) { - oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); - oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); + layoutButtonNo(btnNo); } if (btnYes) { - oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); - oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + layoutButtonYes(btnYes); } oledRefresh(); } diff --git a/layout.h b/layout.h index 5ea34ec335..eea0432777 100644 --- a/layout.h +++ b/layout.h @@ -24,6 +24,8 @@ #include #include "bitmaps.h" +void layoutButtonNo(const char *btnNo); +void layoutButtonYes(const char *btnYes); void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutProgressUpdate(bool refresh); void layoutProgress(const char *desc, int permil); From 63c6f9540068016d1f993cc54e6836549d97bde9 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 6 Feb 2018 22:57:02 +0100 Subject: [PATCH 0741/1154] Fit 21 characters per line --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index fe6c920eac..3f593dc44c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -486,7 +486,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno } } } else { - uint32_t rowlen = (addrlen - 1) / (addrlen <= 40 ? 2 : addrlen <= 60 ? 3 : 4) + 1; + uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { oledDrawString(0, 0 * 9, desc, FONT_STANDARD); From f95d8381ccb0661d489c37dbb06a416d6cd6bfed Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 6 Feb 2018 23:40:55 +0100 Subject: [PATCH 0742/1154] Tweaked fixed font --- gen/fontfixed.inc | 14 +++++++------- gen/fonts/fontfixed.png | Bin 1761 -> 1786 bytes 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/gen/fontfixed.inc b/gen/fontfixed.inc index 747f190bc9..f372ac27ec 100644 --- a/gen/fontfixed.inc +++ b/gen/fontfixed.inc @@ -71,7 +71,7 @@ /* 0x46 F */ (uint8_t *)"\x05\xfe\x90\x90\x90\x80", /* 0x47 G */ (uint8_t *)"\x05\x7c\x82\x82\x92\x5c", /* 0x48 H */ (uint8_t *)"\x05\xfe\x10\x10\x10\xfe", - /* 0x49 I */ (uint8_t *)"\x03\x82\xfe\x82", + /* 0x49 I */ (uint8_t *)"\x05\x82\x82\xfe\x82\x82", /* 0x4a J */ (uint8_t *)"\x05\x04\x02\x02\x82\xfc", /* 0x4b K */ (uint8_t *)"\x05\xfe\x10\x28\x44\x82", /* 0x4c L */ (uint8_t *)"\x05\xfe\x02\x02\x02\x02", @@ -100,21 +100,21 @@ /* 0x63 c */ (uint8_t *)"\x05\x1c\x22\x22\x22\x14", /* 0x64 d */ (uint8_t *)"\x05\x1c\x22\x22\x22\xfe", /* 0x65 e */ (uint8_t *)"\x05\x1c\x2a\x2a\x2a\x1a", - /* 0x66 f */ (uint8_t *)"\x05\x00\x10\x7e\x90\x40", + /* 0x66 f */ (uint8_t *)"\x05\x10\x7e\x90\x80\x40", /* 0x67 g */ (uint8_t *)"\x05\x18\x25\x25\x25\x3e", - /* 0x68 h */ (uint8_t *)"\x05\xfe\x20\x20\x20\x1e", + /* 0x68 h */ (uint8_t *)"\x05\xfe\x10\x20\x20\x1e", /* 0x69 i */ (uint8_t *)"\x05\x00\x22\xbe\x02\x00", - /* 0x6a j */ (uint8_t *)"\x05\x02\x21\xbe\x00\x00", + /* 0x6a j */ (uint8_t *)"\x05\x02\x01\x21\xbe\x00", /* 0x6b k */ (uint8_t *)"\x05\xfe\x08\x14\x22\x00", - /* 0x6c l */ (uint8_t *)"\x05\x00\x82\xfe\x02\x00", + /* 0x6c l */ (uint8_t *)"\x05\x82\x82\xfe\x02\x02", /* 0x6d m */ (uint8_t *)"\x05\x3e\x20\x1e\x20\x1e", - /* 0x6e n */ (uint8_t *)"\x05\x3e\x20\x20\x20\x1e", + /* 0x6e n */ (uint8_t *)"\x05\x3e\x10\x20\x20\x1e", /* 0x6f o */ (uint8_t *)"\x05\x1c\x22\x22\x22\x1c", /* 0x70 p */ (uint8_t *)"\x05\x3f\x24\x24\x24\x18", /* 0x71 q */ (uint8_t *)"\x05\x18\x24\x24\x24\x3f", /* 0x72 r */ (uint8_t *)"\x05\x3e\x10\x20\x20\x10", /* 0x73 s */ (uint8_t *)"\x05\x12\x2a\x2a\x2a\x24", - /* 0x74 t */ (uint8_t *)"\x05\x00\x20\xfc\x22\x02", + /* 0x74 t */ (uint8_t *)"\x05\x20\x20\xfc\x22\x22", /* 0x75 u */ (uint8_t *)"\x05\x3c\x02\x02\x02\x3e", /* 0x76 v */ (uint8_t *)"\x05\x30\x0c\x02\x0c\x30", /* 0x77 w */ (uint8_t *)"\x05\x3c\x02\x0c\x02\x3c", diff --git a/gen/fonts/fontfixed.png b/gen/fonts/fontfixed.png index 13f8d90727b23e21752de0ddbf56ae2a6fb03f5c..ad263ab5b995425e05bb57a7148d0995103874d3 100644 GIT binary patch delta 1719 zcmV;o21xng4f+j`LVp$~51JxuqW}N~nMp)JRCwC$o$HdNAPj`T^8H`g{c(1^LI{bd zuwU2K*3{&{L7N291}84d5@N_=2_Ll{5o27|-+p$?Z&;_$KVpo_vIH?Bc!y61@6R6? zRd?2pdhkBYCFLD3M6VmDl~=Y@qpiVvMqzhAg7-0*_&gfH*T@XV1Fpf>{{d?-IL1Ph zEIb%=O|Vi?60PaaIIJ_(ffLg>+SyWC+xp|RXc{wSFx4A z@oM^7A($|pNuRFNen6At$n!ln?)~otGFsBlWlG_nvSw3On>c$C5Py}E9ACOnl;!kJfT(b zdy5mRkw2JOh~=Xz{}Kqvn*2=3x-yg)gRf_mH9mU1G5ni4#h#;eR1qZ$B?}CO`4=j; z^&=H_wv{OrW`(xJp0{QA7)VaK%sI@6J$u?J$LtC3hl7y15WR)>OaK?gJfCvP>vt<< zrfb_`&wuM@a#=@qJrjGD6EOdnZ`koxZkV>6N<9m%G^v=UIz=UCqSZogDyCTG1WXn> zWPMHOf4=2j2orNlgks&@m&@(U#d!NWbsbeP?=sJ6eFB#A@4tQ=ma6_|fA*#sdTsDO zh1qLcW$>>JXrWn=P%+GAHx0h(ndud`lpGxM%00E{9pqW+EH0&cA(LQR>l}+-=;VRXMHKi~}VLB?}C#WGOYH zd)vxtlvC%DgpN|rvic_XEJ-)&wuvR&qhwVj6*smmriNynOCy_PrCD9NY|Cflr=K?{ zS$|D4lea3Ep8sC6WF#lb=JJ)fIDM3vpJC1_GfuOTl?&Olljfa5 zw=nD59cYui@RfKo?Uj@l6{0Snxr%nBfVQ6JQ!|6eVpfHe*4j~dbgs2wGQ2B$&dF7t z`z&xQj|wGga4Sj{N*3sP-*Dc=y`f}zRDYp|tr~qT{d`({6d|`=ONN>e#i z)Qmob;&B`EwXAnT*!tNL(dqeH^Eyew6K>`CLG!`J=WpQbRHG`=qy~C|Tni@4em1L_ zT~B_z9sjBCU<$i>5yRAzPlv8Oe@f^uA8HDBR40CM7j4tQTR**U9soCR>}2gI#;&hr}(`Q4}MBtGwWQT%@g$buvsnXP018nqp&2~3cE_rp;nDZ zvJJbwt$A;MONL#WaMo2-R(%|HW{Vm@6=nQvq*=#Mlt)q^xhE{~=dsU(H>K-Lu z6zaKZr?Xs>b^6mdRd2eJ-wP&(*+#pwa?e3lecg}c|5Fvr{MPon(`LEi+U`wVTxg9*_9f&l~r2nG-gAQ&8gl7$C@z6nP68QO{m6QThG0|*8X z3?LXlFgO4u3l9c;6O8UNv=t8~L<0y05DXv~Krnz{Z~#gc9t?WMA6j#FmCSrYA^-pi N002ovPDHLkV1lb!NCyA_ literal 1761 zcmdUw`#Tc~7{})lHMg9xB}L9-N4CjilOtKpC7XM-v7}UHjwP2hB$0?yq}psW$0gzv zGw004S#AeM<#wi!h+#uLCBs}=SVw=x`QiJ1p6C1i@_nB7dA{#$f8XPJz}-Lq0HBBS zbUU%d((l@?zBMLvBGBgT_N0|0bD-=zlN{I+Y$)V_lAao3irYZ?7$vU8hq1OU*w zfpa@{Dsl94(G=tHKHZGArOk6A>vjn+n1y9o`}L6Ez~I8PV;s%b>X3Z$4!f{FGwz)} z`OmKWmD-Xhh3OmX<$Jqie1w`V4mqdq8Ixo8{LA__VAjf{dE;O58=AF`+voo<(-q3H zA{>c6VP2($3!(jXZG4SZ%3X_0=thc4rAi~xDVtBUU%MFurdt;m@_av(zNbPhKxGZd{t(1C`b%znrtjg)w?RtjAO_an6EX^H* zK^6!~vu=dw#79m;$#3X$v{j8ee32CgRZV&aB$m4xe`+0jpjh8ZJ)1f66J6x%GrKAr zQc*3ETFqr+;}})O%5d~>?)gOm0vglAX{k5#ju1cg3yj2+;^L+ki>YfWxw=V>qJdUT z{7T()obSJ@-D8n7aXjB|CRRu>gF)!i3(RY5V?WRs3TzCw)sJ)y9BqFt2{R48n^``$ z<78uamqn5sC?e;D>pP(Q_7gTF(!V384Z^_}lpnfVHL?7&DV1R%CeI?$Yr|P+m#UX3oN^(-5UK;!(alssU=2zcZ0?f%0HMIR8%&i{PNDAax$^L0fgyD@k5E4Xk}%Wn zKik=SYt0(~8Fe;~>sBPd$(6K`3w@s`airt%E+8r!giI}r4q7B0D5z)QkLd7FPYZr` za)(mNhOp7F%Ai?IZ?IF?b)P4xEfuyIX(A~0Pu|+h=lI#a#PwpQhN^;uhc5&!YCX!e za~ORu!e$-j+5oEA;fs0uoQQky%dnQ9{}R*Rt~VT_*RtTEbY=Tc*qx#VNtaRUFsN(> z3HM^{o?1;Zw#ni)Pg_<8ynhtPRkDwMjp_Rr7ouNR-09|UVehxEO=W}SD{;cuY~qZd z*j_&mk%vGE7!`v#^EUA60N*07ADpmxY(8|wheu*u9wggV#@u5NSf|E<>I-&r=m(+> zf`o8kAs>JM&s*fu*M=ebH7=G9j0g0G_zvD3cH-}I#roby0lTM43#PNIvyT+atHM^t$3e& z8O193d0M>EhrA#-A|Dxgm{>=a^=r9})#)Eh1DJmI*+R&>d z4_wAV=IvkSq4$^#3rLPW)vobgcJO#XE0FU%YeAxL>n)m{)d-+fhgN_{GL+ ze_So0#p{g#?{e>?vqNAHnNfw1W>0sg6lcq-AAoHp=oQXF#8|pj&Lb(Pt36kl6X718 za1J9D|7vSyxP11JER7_)n2n%k7j-2@xm5mqkV@kle5A_Zq^gJfa6cl!5@n#Tpp!c% zqbL7*btM0rtQaxm4tv9ivW8yc1MuKKtVy<7V3PgESn10a{~y)}o2y~ugbkzCL((?C z3Y1Gg0tU;9yGhI1g_T!0tKgQ5?wk zcu%}J{YrXdzA-w;x88njXj)#Y6Y^tJY`JT4TheVNEp(>aspC>?@>|Z4Pn|%6O`G}a z%NdPlC_*O3^lCuJuPuSbPAwX@8MeT6QDjzKlhr3=4{`j8)r8JZStB0Rb#Z;ih}Y$b zHs3H+p|ip7 Date: Wed, 7 Feb 2018 20:40:22 +0100 Subject: [PATCH 0743/1154] Updated confirmOutput dialog Build it manually (to allow not indenting the address and using a different font). --- firmware/layout2.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 3f593dc44c..9c340085a9 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -129,31 +129,31 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) char str_out[32 + 3]; bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); strlcat(str_out, " to", sizeof(str_out)); - static char lines[2][28]; const char *addr = out->address; int addrlen = strlen(addr); - int numlines = addrlen <= 34 ? 2 : 3; - int linelen = (addrlen + 3) / numlines + 1; - if (linelen > 27) { - linelen = 27; + int numlines = addrlen <= 42 ? 2 : 3; + int linelen = (addrlen - 1) / numlines + 1; + if (linelen > 21) { + linelen = 21; } - if (numlines == 3) { - strlcpy(lines[0], addr, linelen + 1); - addr += linelen; + const char **str = split_message((const uint8_t *)addr, addrlen, linelen); + layoutLast = layoutDialogSwipe; + layoutSwipe(); + oledClear(); + oledDrawBitmap(0, 0, &bmp_icon_question); + oledDrawString(20, 0 * 9, _("Confirm sending"), FONT_STANDARD); + oledDrawString(20, 1 * 9, str_out, FONT_STANDARD); + int left = linelen > 18 ? 0 : 20; + oledDrawString(left, 2 * 9, str[0], FONT_FIXED); + oledDrawString(left, 3 * 9, str[1], FONT_FIXED); + oledDrawString(left, 4 * 9, str[2], FONT_FIXED); + oledDrawString(left, 5 * 9, str[3], FONT_FIXED); + if (!str[3][0]) { + oledHLine(OLED_HEIGHT - 13); } - strlcpy(lines[1], addr, linelen + 1); - addr += linelen; - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Confirm sending"), - str_out, - lines[0], - lines[1], - addr, - NULL - ); + layoutButtonNo(_("Cancel")); + layoutButtonYes(_("Confirm")); + oledRefresh(); } void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) From 8806accb2e3d2ac5ea97056bd81b220cdc661eb3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 7 Feb 2018 20:47:25 +0100 Subject: [PATCH 0744/1154] Distinguish 1 and l better. --- gen/fontfixed.inc | 4 ++-- gen/fonts/fontfixed.png | Bin 1786 -> 1794 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gen/fontfixed.inc b/gen/fontfixed.inc index f372ac27ec..823d4b0a17 100644 --- a/gen/fontfixed.inc +++ b/gen/fontfixed.inc @@ -47,7 +47,7 @@ /* 0x2e . */ (uint8_t *)"\x03\x00\x02\x00", /* 0x2f / */ (uint8_t *)"\x03\x06\x38\xc0", /* 0x30 0 */ (uint8_t *)"\x05\x7c\x82\x92\x82\x7c", - /* 0x31 1 */ (uint8_t *)"\x05\x00\x42\xfe\x02\x00", + /* 0x31 1 */ (uint8_t *)"\x05\x22\x42\xfe\x02\x02", /* 0x32 2 */ (uint8_t *)"\x05\x42\x86\x8a\x92\x62", /* 0x33 3 */ (uint8_t *)"\x05\x44\x82\x92\x92\x6c", /* 0x34 4 */ (uint8_t *)"\x05\x18\x28\x48\x88\xfe", @@ -106,7 +106,7 @@ /* 0x69 i */ (uint8_t *)"\x05\x00\x22\xbe\x02\x00", /* 0x6a j */ (uint8_t *)"\x05\x02\x01\x21\xbe\x00", /* 0x6b k */ (uint8_t *)"\x05\xfe\x08\x14\x22\x00", - /* 0x6c l */ (uint8_t *)"\x05\x82\x82\xfe\x02\x02", + /* 0x6c l */ (uint8_t *)"\x05\x80\x80\xfc\x02\x02", /* 0x6d m */ (uint8_t *)"\x05\x3e\x20\x1e\x20\x1e", /* 0x6e n */ (uint8_t *)"\x05\x3e\x10\x20\x20\x1e", /* 0x6f o */ (uint8_t *)"\x05\x1c\x22\x22\x22\x1c", diff --git a/gen/fonts/fontfixed.png b/gen/fonts/fontfixed.png index ad263ab5b995425e05bb57a7148d0995103874d3..50c77f7a4b2fd9dbfee3d64127396cd9040cf7ee 100644 GIT binary patch delta 1534 zcmVGcR+$yQek&k4~E+DLo^(#7P2L9oA6-JF@M3b1HWgDA%-RV{{8>= z2S(MM^`joVPjg9m2Mp2c25RM%E!Aji@SaiF9gyICOeQ{$M({N9{^hLsp0jUIw9Q@7 zq}k2dcCZ>9s(;vjvLfgA;<7B}f#nu;xlc{z_O;#qYax1Hk8!=-KmLUM*RN{Fu=y&s z5;$H>Un>L?#xv>DmD)FGk{o%y=f=H%T_B@%{&pSJN`I{%#~r%yU^ztZ?@{uqJg)Z4 zMdhN79DZ`wvf^oio5rGI=fz2FxRtiBu{YV~R-@@Cdw;^zZdh`N-n&9>8>Lx;4Z{;! z6+gE)u^RbcQ za$7%AVP{*JQejqTTkLsThL3^dq|2PcjM%fMt#Zts@P0T5sSD9tc+UiIVa)R>r@Vf) zQf9igEr0gBz9*M;WY;sXXE_1$kNJijZ{>z*+o{yEFsTM)N>MZ^kblo9^w2_YDyCTG z1WXn>WPMHOf0jR6d4q(Bxg|oe?(WOwcIINd{hhjws+f0~=X8auMA47KQq}+L&)zgc zuMPgEFnevQ4F0tNEi@|3__!IQQ0fGR4pJglIX;%2K69xJ~b( z<&d?S(tF*bFnitXNITM-0_np&I~R31%z8Ex*@$(1^?609M{9Doaf?>vv|cj~lq{4i zFtn1T)Qs+JE2~jXol6orNNtJo9u@BR$;zFw z=bT*Sxz7T}1uYUKYiuh@7D^WAdf#x~#ecn_WO-DfhpifYE&ctp_*I15b}cbB6!XsQ z)F@5mR8cef6pF`f%-6Es4PonNOGKyVZ_Vo@2`2=V=LgLP8=t>{vr~<#NRt}q334r% zEc@B4W_CUK@pk;DzJn?3>O~AwPd**G_WUWK!+fYIxW&ll@55B(F;#Q3^|u$!1ApKK zj-BkjvQEv)z#BC*J&ZyWncPPd`X5lpDVYgM&^QKjaJ>R}?OyQ-cncR}LSyxqA^}*+CA*Sc-!&Q~eQi8*!#e3X$KQKYYvSrwl z|9<7Xe;sk7Lwv#d5GSV`AzeQ-&i-KM()_Rud)A8;9{O86_t6>d+*Fhs8#sFhc?RHLoIdq!b*K!W!%nfN>!!Pm$P#{;gx*Z%=)FgV6S zlq@_LbWN~QQ4+1`&p50x#8t_P*NUU%@PVuKAcWzEVro3eQGkdukH3<3(@;}jO*?G@h9xRepNe$%~!FN z!0~GOS|OM)o=Kms)P6vd7=y28l{G$ky)pcoI>nx&byN{03ndE-hWQsN zxAh|xcD9u%6=sFD#h$li_!vk|y39Guh&_ASD#z>z?}vksx)8mE_e=m6#yp>L%IkM4 zWu|M}Vt>!;XL4Cbc0Ch&mJ=}lm~YteR&JQKok~3mt~9Bbr#eL?XQI_YZz`r(<^)U@ zI%IuK=zqTDUI-I&ON3(G-IvSl%*A;7J9QmZG4C?ZX?+5g^Y6cY9G0s7XMgsl8G3E- zKZV(ATV?RC4QQcRkx((rW;YGK@ILuNmQ81t#eccCp2-xy*At@UFe^)y8sRp*i_>b8j`+@oYwB^5WeEvANMol7H|WTjbMx@^m57Zsu|pt*{6rGU1c=TkF-$YNH7l-Al&d33I|VKTfcd(O#K zp8G6tERPB$Yj7({7D^WAdf#x~#l4|qd6T{a2!DK9d=w$KT}zA&#k_MnHA+)CRn&|= zh2n7=^R=vZL)iM+64B}TTk|?e!V_-g`9br+#^-O~>{O#F(xe7@f?NwG%YHVinO#qQ zydD3k?_dhMdJ)6alTU}PJ%38*Fdu3PcT^{SaTjgV!CODQa2^0RaO`CFm33-X1{S%P zD1T{fS2^Vm;J3J7POCC(g*?u1YJ1-5qGa7~^_*M0`^+Os7D^WA8S|!+)CVQG&PX5b zl66MKwz)$w{xJ)uDG$4?nw~eUO6>Xeg<}dYz0Ks7RHxC%i`!jW9{lDmTF5#)r87!v zSwfNTb^Wts;jg9@|Dc-Y1GQWpQkBdbOMi-EPFm;UtZbx3%kR1>whfNAXssW}U6J{S zQMjY%E>|p&8?$_`=4Zqgj|h6B%F$YIXjgRS(xR0kb|&Ms`IzR&tii*Y!a4KaRI*en zWlc?%+_SS%%rhzF)0CS1mv9o(qjqWT)&EkHrFxNyqvwZH9cr=wO4k3ZWW5+zihr6> zcMC^$i52UremYmS;-~n%5f6S!Uo-1mq0JNY`LJ0n=}pNLTcfZf+X}l%&!JY0NU{yP zzO8w0e@lj4n{d`uRaSlRIa`S7Is0%`rL&aaaB1-#_uUUnkg;qT_T;}`IqzRb+~^Qr zu)f5}DM#emI>T&ne%OXR>%|HW{Y@?2`{)dJa@lMxyRD;+u!dHI=zCS6^XeWYUli)O zYNxYYlXd#jI8|@Dliv#_huKEEvvSWtR(;)%<^NL^%>35&yVE3;ER-zJH^HTo69(E9 YA6j#FmCSrYA^-pY07*qoM6N<$f?vG{p#T5? From 68168393b9ea61328f4bb43bc3059ab32c4be2e9 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 03:54:48 +0100 Subject: [PATCH 0745/1154] Add USB 2.1 (WebUSB preparation) Most code taken from https://github.com/devanlai/dap42 and https://github.com/devanlai/dapboot --- usb21_standard.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ usb21_standard.h | 63 ++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 usb21_standard.c create mode 100644 usb21_standard.h diff --git a/usb21_standard.c b/usb21_standard.c new file mode 100644 index 0000000000..7ed1986cf4 --- /dev/null +++ b/usb21_standard.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "util.h" +#include "usb21_standard.h" + +static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, + uint8_t *buf, uint16_t len) +{ + uint8_t *tmpbuf = buf; + uint16_t count, total = 0, totallen = 0; + uint16_t i; + + memcpy(buf, bos, count = MIN(len, bos->bLength)); + buf += count; + len -= count; + total += count; + totallen += bos->bLength; + + /* For each device capability */ + for (i = 0; i < bos->bNumDeviceCaps; i++) { + /* Copy device capability descriptor. */ + const struct usb_device_capability_descriptor *cap = + bos->capabilities[i]; + + memcpy(buf, cap, count = MIN(len, cap->bLength)); + buf += count; + len -= count; + total += count; + totallen += cap->bLength; + } + + /* Fill in wTotalLength. */ + *(uint16_t *)(tmpbuf + 2) = totallen; + + return total; +} + +static const struct usb_bos_descriptor* usb21_bos; + +static int usb21_standard_get_descriptor(usbd_device* usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { + int descr_type = req->wValue >> 8; + if (descr_type == USB_DT_BOS) { + if (!usb21_bos) { + return USBD_REQ_NOTSUPP; + } + *len = MIN(*len, build_bos_descriptor(usb21_bos, *buf, *len)); + return USBD_REQ_HANDLED; + } + } + + return USBD_REQ_NEXT_CALLBACK; +} + +static void usb21_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + &usb21_standard_get_descriptor); +} + +void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store) { + usb21_bos = binary_object_store; + + /* Register the control request handler _before_ the config is set */ + usb21_set_config(usbd_dev, 0x0000); + usbd_register_set_config_callback(usbd_dev, usb21_set_config); +} diff --git a/usb21_standard.h b/usb21_standard.h new file mode 100644 index 0000000000..e7578a533b --- /dev/null +++ b/usb21_standard.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef USB21_STANDARD_H_INCLUDED +#define USB21_STANDARD_H_INCLUDED + +#include + +/* USB 3.1 Descriptor Types - Table 9-6 */ +#define USB_DT_BOS 15 +#define USB_DT_DEVICE_CAPABILITY 16 +#define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 +#define USB_DT_SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49 + +struct usb_device_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; +} __attribute__((packed)); + +struct usb_bos_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; + /* Descriptor ends here. The following are used internally: */ + const struct usb_device_capability_descriptor **capabilities; +} __attribute__((packed)); + +#define USB_DT_BOS_SIZE 5 + +/* USB Device Capability Types - USB 3.1 Table 9-14 */ +#define USB_DC_WIRELESS_USB 1 +#define USB_DC_USB_2_0_EXTENSION 2 +#define USB_DC_SUPERSPEED_USB 3 +#define USB_DC_CONTAINER_ID 4 +#define USB_DC_PLATFORM 5 +#define USB_DC_POWER_DELIVERY_CAPABILITY 6 +#define USB_DC_BATTERY_INFO_CAPABILITY 7 +#define USB_DC_PD_CONSUMER_PORT_CAPABILITY 8 +#define USB_DC_PD_PROVIDER_PORT_CAPABILITY 9 +#define USB_DC_SUPERSPEED_PLUS 10 +#define USB_DC_PRECISION_TIME_MEASUREMENT 11 +#define USB_DC_WIRELESS_USB_EXT 12 + +extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); + +#endif From e6981e85cdc3f96c305cc22b349c15fcf978341e Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 03:57:13 +0100 Subject: [PATCH 0746/1154] Add WinUSB (WebUSB preparation) Some code taken from https://github.com/devanlai/dapboot Some code written according to the WCID documentation - https://github.com/pbatard/libwdi/wiki/WCID-Devices --- winusb.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ winusb.h | 30 ++++++++++ winusb_defs.h | 86 +++++++++++++++++++++++++++ 3 files changed, 276 insertions(+) create mode 100644 winusb.c create mode 100644 winusb.h create mode 100644 winusb_defs.h diff --git a/winusb.c b/winusb.c new file mode 100644 index 0000000000..1d8d645bb1 --- /dev/null +++ b/winusb.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "util.h" +#include "winusb.h" + +static int usb_descriptor_type(uint16_t wValue) { + return wValue >> 8; +} + +static int usb_descriptor_index(uint16_t wValue) { + return wValue & 0xFF; +} + +static struct winusb_compatible_id_descriptor winusb_wcid = { + .header = { + .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + + 1 * sizeof(struct winusb_compatible_id_function_section), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, + .bNumSections = 1, + .reserved = { 0, 0, 0, 0, 0, 0, 0 }, + }, + .functions = { + { + // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number + .bInterfaceNumber = 0, + .reserved0 = { 1 }, + .compatibleId = "WINUSB", + .subCompatibleId = "", + .reserved1 = { 0, 0, 0, 0, 0, 0} + }, + } +}; + +static struct usb_string_descriptor winusb_string_descriptor = { + .bLength = sizeof(WINUSB_EXTRA_STRING) + sizeof(struct usb_string_descriptor), + .bDescriptorType = USB_DT_STRING, + .wData = WINUSB_EXTRA_STRING +}; + +static const struct winusb_extended_properties_descriptor guid = { + .header = { + .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) + + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, + .wNumFeatures = 1, + }, + .features = { + { + .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), + .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, + .wNameLength = sizeof(u"DeviceInterfaceGUIDs"), + .name = u"DeviceInterfaceGUIDs", + .dwPropertyDataLength = (WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_C), + .propertyData = WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID, + }, + } +}; + +static int winusb_descriptor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return USBD_REQ_NEXT_CALLBACK; + } + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { + if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { + *buf = (uint8_t*)(&winusb_string_descriptor); + *len = MIN(*len, winusb_string_descriptor.bLength); + return USBD_REQ_HANDLED; + } + } + return USBD_REQ_NEXT_CALLBACK; +} + +static int winusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && + (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { + *buf = (uint8_t*)(&winusb_wcid); + *len = MIN(*len, winusb_wcid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && + (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR)) { + + *buf = (uint8_t*)(&guid); + *len = MIN(*len, guid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else { + status = USBD_REQ_NOTSUPP; + } + + return status; +} + +static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); +} + +void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { + winusb_wcid.functions[0].bInterfaceNumber = interface; + + usbd_register_set_config_callback(usbd_dev, winusb_set_config); + + /* Windows probes the compatible ID before setting the configuration, + so also register the callback now */ + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_RECIPIENT, + winusb_descriptor_request); +} + diff --git a/winusb.h b/winusb.h new file mode 100644 index 0000000000..1f2ff9a3c9 --- /dev/null +++ b/winusb.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_H_INCLUDED +#define WINUSB_H_INCLUDED + +#include "winusb_defs.h" + +// Arbitrary, but must be equivalent to the last character in extra string +#define WINUSB_MS_VENDOR_CODE '!' +#define WINUSB_EXTRA_STRING u"MSFT100!" + +extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); + +#endif diff --git a/winusb_defs.h b/winusb_defs.h new file mode 100644 index 0000000000..3b249dd5a4 --- /dev/null +++ b/winusb_defs.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_DEFS_H_INCLUDED +#define WINUSB_DEFS_H_INCLUDED + +#include + +/* Microsoft OS 1.0 descriptors */ + +/* Extended Compat ID OS Feature Descriptor Specification */ +#define WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 +#define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 +#define WINUSB_BCD_VERSION 0x0100 + +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C (sizeof(u"DeviceInterfaceGUIDs")) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof("DeviceInterfaceGUIDs")) +#define WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\0" +// double null is intentional - it's an array of guids with 1 item + +#define WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID) +#define WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 + +#define WINUSB_EXTRA_STRING_INDEX 0xee + +/* Table 2. Function Section */ +struct winusb_compatible_id_function_section { + uint8_t bInterfaceNumber; + uint8_t reserved0[1]; + char compatibleId[8]; + char subCompatibleId[8]; + uint8_t reserved1[6]; +} __attribute__((packed)); + +/* Table 1. Header Section */ +struct winusb_compatible_id_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bNumSections; + uint8_t reserved[7]; +} __attribute__((packed)); + +struct winusb_compatible_id_descriptor { + struct winusb_compatible_id_descriptor_header header; + struct winusb_compatible_id_function_section functions[]; +} __attribute__((packed)); + +struct winusb_extended_properties_feature_descriptor { + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint16_t wNameLength; + uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; + uint32_t dwPropertyDataLength; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_U]; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wNumFeatures; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor { + struct winusb_extended_properties_descriptor_header header; + struct winusb_extended_properties_feature_descriptor features[]; +} __attribute__((packed)); + +#endif From a062127cef4d5ac682699cbbc80a841de72943a2 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 03:58:49 +0100 Subject: [PATCH 0747/1154] Add WebUSB descriptors Most code taken from https://github.com/devanlai/dap42 and https://github.com/devanlai/dapboot --- webusb.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ webusb.h | 32 ++++++++++++++++++ webusb_defs.h | 61 +++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 webusb.c create mode 100644 webusb.h create mode 100644 webusb_defs.h diff --git a/webusb.c b/webusb.c new file mode 100644 index 0000000000..beb909c089 --- /dev/null +++ b/webusb.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "util.h" +#include "webusb.h" +#include "usb21_standard.h" + +const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 1 +}; + +static const char* webusb_https_url; + +static int webusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WEBUSB_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + switch (req->wIndex) { + case WEBUSB_REQ_GET_URL: { + struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); + uint16_t index = req->wValue; + if (index == 0) { + return USBD_REQ_NOTSUPP; + } + + if (index == 1) { + size_t url_len = strlen(webusb_https_url); + url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; + url->bDescriptorType = WEBUSB_DT_URL; + url->bScheme = WEBUSB_URL_SCHEME_HTTPS; + memcpy(&url->URL, webusb_https_url, url_len); + *len = MIN(*len, url->bLength); + status = USBD_REQ_HANDLED; + } else { + // TODO: stall instead? + status = USBD_REQ_NOTSUPP; + } + break; + } + default: { + status = USBD_REQ_NOTSUPP; + break; + } + } + + return status; +} + +static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + webusb_control_vendor_request); +} + +void webusb_setup(usbd_device* usbd_dev, const char* https_url) { + webusb_https_url = https_url; + + usbd_register_set_config_callback(usbd_dev, webusb_set_config); +} diff --git a/webusb.h b/webusb.h new file mode 100644 index 0000000000..f41695fe31 --- /dev/null +++ b/webusb.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_H_INCLUDED +#define WEBUSB_H_INCLUDED + +#include +#include "webusb_defs.h" + +// Arbitrary +#define WEBUSB_VENDOR_CODE 0x01 + +extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; +extern void webusb_setup(usbd_device* usbd_dev, + const char** https_urls, size_t num_https_urls); + +#endif diff --git a/webusb_defs.h b/webusb_defs.h new file mode 100644 index 0000000000..45b5f2478d --- /dev/null +++ b/webusb_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_DEFS_H_INCLUDED +#define WEBUSB_DEFS_H_INCLUDED + +#include + +#define WEBUSB_REQ_GET_URL 0x02 + +#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 +#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 +#define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2 +#define WEBUSB_DT_URL 3 + +#define WEBUSB_URL_SCHEME_HTTP 0 +#define WEBUSB_URL_SCHEME_HTTPS 1 + +struct webusb_platform_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t platformCapabilityUUID[16]; + uint16_t bcdVersion; + uint8_t bVendorCode; + uint8_t iLandingPage; +} __attribute__((packed)); + +#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) + +// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor +// see also this (for endianness explanation) +// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 +#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} + +struct webusb_url_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char URL[]; +} __attribute__((packed)); + +#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 + +#endif From 05e218bcb8279ccaa19f258dc7844648353353a0 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 03:59:57 +0100 Subject: [PATCH 0748/1154] Add WinUSB, WebUSB, USB2.1 to build --- Makefile | 4 ++++ webusb.h | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 81d418d9d1..ba1ebf59bc 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,10 @@ ifneq ($(EMULATOR),1) OBJS += timer.o endif +OBJS += usb21_standard.o +OBJS += webusb.o +OBJS += winusb.o + OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/webusb.h b/webusb.h index f41695fe31..342408f1f7 100644 --- a/webusb.h +++ b/webusb.h @@ -26,7 +26,6 @@ #define WEBUSB_VENDOR_CODE 0x01 extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; -extern void webusb_setup(usbd_device* usbd_dev, - const char** https_urls, size_t num_https_urls); +extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); #endif From cb067bd14c57445430fbaa4da8c77badf0d1f772 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 04:28:13 +0100 Subject: [PATCH 0749/1154] Switch from HID to WebUSB Also renaming varions functions from hid_ to webusb_ to actually reflect what they are doing --- firmware/usb.c | 241 +++++++++++++++++++------------------------------ 1 file changed, 95 insertions(+), 146 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 7a59b6fa02..ee8e3406cd 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -29,18 +29,27 @@ #include "util.h" #include "timer.h" +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + + #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK #define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_U2F 2 +#define USB_INTERFACE_COUNT 3 #else #define USB_INTERFACE_INDEX_U2F 1 +#define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_MAIN_IN (0x81) +#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) +#if DEBUG_LINK #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#endif #define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_OUT (0x03) @@ -50,7 +59,7 @@ X(SERIAL_NUMBER, storage_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ - X(INTERFACE_U2F, "U2F Interface") + X(INTERFACE_U2F, "TREZOR U2F Interface") \ #define X(name, value) USB_STRING_##name, enum { @@ -68,60 +77,20 @@ static const char *usb_strings[] = { static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0200, .iManufacturer = USB_STRING_MANUFACTURER, .iProduct = USB_STRING_PRODUCT, .iSerialNumber = USB_STRING_SERIAL_NUMBER, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -#if DEBUG_LINK -static const uint8_t hid_report_descriptor_debug[] = { - 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; -#endif - static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) 0x09, 0x01, // USAGE (U2F HID Authenticator Device) @@ -141,26 +110,6 @@ static const uint8_t hid_report_descriptor_u2f[] = { 0xc0 // END_COLLECTION }; -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - static const struct { struct usb_hid_descriptor hid_descriptor_u2f; struct { @@ -181,38 +130,6 @@ static const struct { } }; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor hid_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), -}}; - static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -245,7 +162,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ +static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, @@ -261,29 +178,64 @@ static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor hid_iface_debug[] = {{ +static const struct usb_interface_descriptor webusb_iface_debug[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = hid_endpoints_debug, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = webusb_endpoints_debug, + .extra = NULL, + .extralen = 0, }}; + #endif +static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 2, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 2, +}}; + +static const struct usb_interface_descriptor webusb_iface_main[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = webusb_endpoints_main, + .extra = NULL, + .extralen = 0, +}}; + + +// Windows are strict about interfaces appearing +// in correct order static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = webusb_iface_main, #if DEBUG_LINK }, { .num_altsetting = 1, - .altsetting = hid_iface_debug, + .altsetting = webusb_iface_debug, #endif }, { .num_altsetting = 1, @@ -294,11 +246,7 @@ static const struct usb_config_descriptor config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, -#if DEBUG_LINK - .bNumInterfaces = 3, -#else - .bNumInterfaces = 2, -#endif + .bNumInterfaces = USB_INTERFACE_COUNT, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, @@ -312,40 +260,24 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (void)dev; if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) return 0; - if (req->wIndex == USB_INTERFACE_INDEX_U2F) { - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = sizeof(hid_report_descriptor_u2f); - return 1; - } - -#if DEBUG_LINK - if (req->wIndex == USB_INTERFACE_INDEX_DEBUG) { - debugLog(0, "", "hid_control_request debug"); - *buf = (uint8_t *)hid_report_descriptor_debug; - *len = sizeof(hid_report_descriptor_debug); - return 1; - } -#endif - - debugLog(0, "", "hid_control_request main"); - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); return 1; } static volatile char tiny = 0; -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void main_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_rx_callback"); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; + debugLog(0, "", "main_rx_callback"); if (!tiny) { msg_read(buf, 64); } else { @@ -353,23 +285,23 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } } -static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) +static void u2f_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - debugLog(0, "", "hid_u2f_rx_callback"); + debugLog(0, "", "u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } #if DEBUG_LINK -static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) +static void debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_debug_rx_callback"); + debugLog(0, "", "debug_rx_callback"); if (!tiny) { msg_debug_read(buf, 64); } else { @@ -378,17 +310,17 @@ static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) } #endif -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_u2f_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); #if DEBUG_LINK usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); #endif usbd_register_control_callback( @@ -399,12 +331,29 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + // Debug link interface does not have WinUSB set; + // if you really need debug link on windows, edit the descriptor in winusb.c + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } void usbPoll(void) @@ -415,7 +364,7 @@ void usbPoll(void) // write pending data data = msg_out_data(); if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} } data = u2f_out_data(); if (data) { From a22abfe90b846a7884bd365e2d8de99124ad000b Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Sun, 17 Dec 2017 04:36:47 +0100 Subject: [PATCH 0750/1154] Bootloader - Switch from HID to WebUSB --- bootloader/usb.c | 133 ++++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 83 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 6442ab229d..8b64769969 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -18,7 +18,6 @@ */ #include -#include #include #include @@ -37,8 +36,16 @@ #include "secp256k1.h" #include "memzero.h" +#include "debug.h" + +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + #define FIRMWARE_MAGIC "TRZR" +#define USB_INTERFACE_INDEX_MAIN 0 + #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -48,93 +55,54 @@ static bool old_was_unsigned; static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0300, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ +static const struct usb_endpoint_descriptor endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 1, + .bInterval = 2, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 1, + .bInterval = 2, }}; -static const struct usb_interface_descriptor hid_iface[] = {{ +static const struct usb_interface_descriptor iface[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = 0, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, }}; static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = iface, }}; static const struct usb_config_descriptor config = { @@ -155,23 +123,6 @@ static const char *usb_strings[] = { "", // empty serial }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) -{ - (void)complete; - (void)dev; - - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; - - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); - - return 1; -} - enum { STATE_READY, STATE_OPEN, @@ -315,8 +266,9 @@ static void restore_metadata(const uint8_t *backup) flash_lock(); } -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void rx_callback(usbd_device *dev, uint8_t ep) { + debugLog(0, "", "rx_callback start"); (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); static uint8_t towrite[4] __attribute__((aligned(4))); @@ -628,23 +580,39 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); - - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request - ); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); + debugLog(0, "", "set_config done"); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; + +void usbInit(void) +{ + debugLog(0, "", "usb_init"); + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); +} void checkButtons(void) { @@ -678,8 +646,7 @@ void checkButtons(void) void usbLoop(bool firmware_present) { brand_new_firmware = !firmware_present; - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbInit(); for (;;) { usbd_poll(usbd_dev); if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { From 56d3cbe2e93b133ba6f269e1b64c0ac7192ab2f1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 13 Jan 2018 17:20:46 +0100 Subject: [PATCH 0751/1154] bootloader: remove debug --- bootloader/usb.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 8b64769969..c647a868e9 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -36,8 +36,6 @@ #include "secp256k1.h" #include "memzero.h" -#include "debug.h" - #include "usb21_standard.h" #include "webusb.h" #include "winusb.h" @@ -268,7 +266,6 @@ static void restore_metadata(const uint8_t *backup) static void rx_callback(usbd_device *dev, uint8_t ep) { - debugLog(0, "", "rx_callback start"); (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); static uint8_t towrite[4] __attribute__((aligned(4))); @@ -586,7 +583,6 @@ static void set_config(usbd_device *dev, uint16_t wValue) usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); - debugLog(0, "", "set_config done"); } static usbd_device *usbd_dev; @@ -605,7 +601,6 @@ static const struct usb_bos_descriptor bos_descriptor = { void usbInit(void) { - debugLog(0, "", "usb_init"); usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, set_config); usb21_setup(usbd_dev, &bos_descriptor); From 38b4d507bc12e737879d016adc7dfa914a64c59d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 18 Jan 2018 00:35:03 +0100 Subject: [PATCH 0752/1154] webusb: remove unused constants --- usb21_standard.h | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/usb21_standard.h b/usb21_standard.h index e7578a533b..e5358bcd5f 100644 --- a/usb21_standard.h +++ b/usb21_standard.h @@ -22,10 +22,8 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 +#define USB_DT_BOS 15 #define USB_DT_DEVICE_CAPABILITY 16 -#define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 -#define USB_DT_SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49 struct usb_device_capability_descriptor { uint8_t bLength; @@ -45,18 +43,7 @@ struct usb_bos_descriptor { #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_WIRELESS_USB 1 -#define USB_DC_USB_2_0_EXTENSION 2 -#define USB_DC_SUPERSPEED_USB 3 -#define USB_DC_CONTAINER_ID 4 -#define USB_DC_PLATFORM 5 -#define USB_DC_POWER_DELIVERY_CAPABILITY 6 -#define USB_DC_BATTERY_INFO_CAPABILITY 7 -#define USB_DC_PD_CONSUMER_PORT_CAPABILITY 8 -#define USB_DC_PD_PROVIDER_PORT_CAPABILITY 9 -#define USB_DC_SUPERSPEED_PLUS 10 -#define USB_DC_PRECISION_TIME_MEASUREMENT 11 -#define USB_DC_WIRELESS_USB_EXT 12 +#define USB_DC_PLATFORM 5 extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); From 132cc4b4748fa507a9aa47d15fd638637bcf23da Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Jan 2018 20:51:38 +0100 Subject: [PATCH 0753/1154] make winusb_string_descriptor const --- winusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/winusb.c b/winusb.c index 1d8d645bb1..d5e6a13884 100644 --- a/winusb.c +++ b/winusb.c @@ -49,8 +49,8 @@ static struct winusb_compatible_id_descriptor winusb_wcid = { } }; -static struct usb_string_descriptor winusb_string_descriptor = { - .bLength = sizeof(WINUSB_EXTRA_STRING) + sizeof(struct usb_string_descriptor), +static const struct usb_string_descriptor winusb_string_descriptor = { + .bLength = sizeof(struct usb_string_descriptor) + sizeof(WINUSB_EXTRA_STRING), .bDescriptorType = USB_DT_STRING, .wData = WINUSB_EXTRA_STRING }; From 56c5a46095ea2abc963888de7c56a08916cd3878 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Jan 2018 21:25:55 +0100 Subject: [PATCH 0754/1154] winusb: cleanup DeviceInterfaceGUIDs usage --- winusb.c | 8 ++++---- winusb_defs.h | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/winusb.c b/winusb.c index d5e6a13884..1ba2f96845 100644 --- a/winusb.c +++ b/winusb.c @@ -67,10 +67,10 @@ static const struct winusb_extended_properties_descriptor guid = { { .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, - .wNameLength = sizeof(u"DeviceInterfaceGUIDs"), - .name = u"DeviceInterfaceGUIDs", - .dwPropertyDataLength = (WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_C), - .propertyData = WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID, + .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, + .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, + .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, + .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, }, } }; diff --git a/winusb_defs.h b/winusb_defs.h index 3b249dd5a4..830e6b1545 100644 --- a/winusb_defs.h +++ b/winusb_defs.h @@ -28,14 +28,17 @@ #define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 #define WINUSB_BCD_VERSION 0x0100 -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C (sizeof(u"DeviceInterfaceGUIDs")) -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof("DeviceInterfaceGUIDs")) -#define WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\0" -// double null is intentional - it's an array of guids with 1 item +// Apparently using DeviceInterfaceGUID does not always work on Windows 7. +// DeviceInterfaceGUIDs does seem to work. +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) -#define WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID) -#define WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_RANDOM_GUID) / 2) -#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 +// extra null is intentional - it's an array of GUIDs with 1 item +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 #define WINUSB_EXTRA_STRING_INDEX 0xee @@ -68,7 +71,7 @@ struct winusb_extended_properties_feature_descriptor { uint16_t wNameLength; uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; uint32_t dwPropertyDataLength; - uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUIDS_SIZE_U]; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; } __attribute__((packed)); struct winusb_extended_properties_descriptor_header { From 966d8cb4ce561c37aaf8d261a981d3dc91e01e19 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Jan 2018 22:54:49 +0100 Subject: [PATCH 0755/1154] winusb: fix WINUSB_EXTRA_STRING --- winusb.c | 2 +- winusb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/winusb.c b/winusb.c index 1ba2f96845..1f78f9a2c9 100644 --- a/winusb.c +++ b/winusb.c @@ -50,7 +50,7 @@ static struct winusb_compatible_id_descriptor winusb_wcid = { }; static const struct usb_string_descriptor winusb_string_descriptor = { - .bLength = sizeof(struct usb_string_descriptor) + sizeof(WINUSB_EXTRA_STRING), + .bLength = 0x12, .bDescriptorType = USB_DT_STRING, .wData = WINUSB_EXTRA_STRING }; diff --git a/winusb.h b/winusb.h index 1f2ff9a3c9..16a6df1153 100644 --- a/winusb.h +++ b/winusb.h @@ -23,7 +23,7 @@ // Arbitrary, but must be equivalent to the last character in extra string #define WINUSB_MS_VENDOR_CODE '!' -#define WINUSB_EXTRA_STRING u"MSFT100!" +#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); From 6acfc5d1b3c55de4545cc8a749d0cb6552592624 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Jan 2018 00:14:01 +0100 Subject: [PATCH 0756/1154] trezorhal: reply with winusb guid just for the main interface (0) --- winusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winusb.c b/winusb.c index 1f78f9a2c9..afdaf8b706 100644 --- a/winusb.c +++ b/winusb.c @@ -115,7 +115,8 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev, status = USBD_REQ_HANDLED; } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && - (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR)) { + (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && + (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { *buf = (uint8_t*)(&guid); *len = MIN(*len, guid.header.dwLength); From ab76828e16b552c82f468e5d89f1af0645258995 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 27 Jan 2018 23:56:24 +0100 Subject: [PATCH 0757/1154] update usb descriptors --- bootloader/usb.c | 4 ++-- firmware/usb.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index c647a868e9..57d70cd1a8 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -73,14 +73,14 @@ static const struct usb_endpoint_descriptor endpoints[2] = {{ .bEndpointAddress = ENDPOINT_ADDRESS_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }}; static const struct usb_interface_descriptor iface[] = {{ diff --git a/firmware/usb.c b/firmware/usb.c index ee8e3406cd..be7cae7b91 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -136,14 +136,14 @@ static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ @@ -201,14 +201,14 @@ static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }}; static const struct usb_interface_descriptor webusb_iface_main[] = {{ From d7de064bde0edb77f6198fddf3d016bb3b42caa1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 20 Feb 2018 19:14:35 +0100 Subject: [PATCH 0758/1154] bump version to 1.7.0; update firmware changelog --- firmware/ChangeLog | 6 ++++++ firmware/trezor.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 41c7f9b6a3..30acfd98b8 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,9 @@ +Version 1.7.0 +* Stable release, optional update +* Use fixed-width font for addresses +* Enable WebUSB +* Lots of under-the-hood improvements + Version 1.6.0 * Stable release, optional update * Native SegWit (Bech32) address support diff --git a/firmware/trezor.h b/firmware/trezor.h index c47e38306b..20fcfc481e 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,7 +23,7 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 6 +#define VERSION_MINOR 7 #define VERSION_PATCH 0 #define STR(X) #X From 7fa8ae136fc45ddfae94ff54be8fd763dc6b159a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 24 Feb 2018 17:26:57 +0100 Subject: [PATCH 0759/1154] firmware: implement behaviour of state (still missing in PassphraseAck) --- firmware/fsm.c | 11 ++++++-- firmware/protect.c | 1 + firmware/protob/messages.options | 6 ++-- firmware/storage.c | 47 ++++++++++++++++++++++++++++++++ firmware/storage.h | 2 ++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index f05d80fba6..c4b633a226 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -232,10 +232,15 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore void fsm_msgInitialize(Initialize *msg) { - (void)msg; recovery_abort(); signing_abort(); - session_clear(false); // do not clear PIN + if (msg->has_state && msg->state.size == 64) { + if (!session_compareState(msg->state.bytes)) { + session_clear(false); // do not clear PIN + } + } else { + session_clear(false); // do not clear PIN + } layoutHome(); fsm_msgGetFeatures(0); } @@ -301,6 +306,8 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); + resp->has_state = true; resp->state.size = 64; session_getState(NULL, resp->state.bytes); + msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/protect.c b/firmware/protect.c index c81509f23f..3b586e5b1d 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -253,6 +253,7 @@ bool protectPassphrase(void) bool result; for (;;) { usbPoll(); + // TODO: correctly process PassphraseAck with state field set (mismatch => Failure) if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { msg_tiny_id = 0xFFFF; PassphraseAck *ppa = (PassphraseAck *)msg_tiny; diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 90329e7d50..88e96cbdec 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -1,4 +1,4 @@ -Initialize.state max_size:32 +Initialize.state max_size:64 Features.vendor max_size:33 Features.device_id max_size:25 @@ -10,7 +10,7 @@ Features.bootloader_hash max_size:32 Features.model max_size:17 Features.fw_vendor max_size:256 Features.fw_vendor_keys max_size:32 -Features.state max_size:32 +Features.state max_size:64 ApplySettings.language max_size:17 ApplySettings.label max_size:33 @@ -27,7 +27,7 @@ ButtonRequest.data max_size:256 PinMatrixAck.pin max_size:10 PassphraseAck.passphrase max_size:51 -PassphraseAck.state max_size:32 +PassphraseAck.state max_size:64 Entropy.entropy max_size:1024 diff --git a/firmware/storage.c b/firmware/storage.c index 926aed6bfb..ebdb01cf27 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -28,6 +28,7 @@ #include "sha2.h" #include "aes/aes.h" #include "pbkdf2.h" +#include "hmac.h" #include "bip32.h" #include "bip39.h" #include "curves.h" @@ -124,6 +125,9 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char CONFIDENTIAL sessionPassphrase[51]; +static bool sessionStateSaltSet; +static uint8_t sessionStateSalt[32]; + #define STORAGE_VERSION 9 void storage_show_error(void) @@ -266,6 +270,8 @@ void session_clear(bool clear_pin) memzero(&sessionSeed, sizeof(sessionSeed)); sessionPassphraseCached = false; memzero(&sessionPassphrase, sizeof(sessionPassphrase)); + sessionStateSaltSet = false; + memzero(&sessionStateSalt, sizeof(sessionStateSalt)); if (clear_pin) { sessionPinCached = false; } @@ -709,6 +715,47 @@ bool session_isPassphraseCached(void) return sessionPassphraseCached; } +void session_getState(const uint8_t *salt, uint8_t *state) +{ + if (!salt) { + if (!sessionStateSaltSet) { + // generate a random salt if not provided and not already cached + random_buffer(sessionStateSalt, 32); + } + } else { + // otherwise copy provided salt to cached salt + memcpy(sessionStateSalt, salt, 32); + } + + sessionStateSaltSet = true; + + // state[0:32] = salt + memcpy(state, sessionStateSalt, 32); + + // state[32:64] = HMAC(passphrase, salt || device_id) + HMAC_SHA256_CTX ctx; + if (sessionPassphraseCached) { + hmac_sha256_Init(&ctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase)); + } else { + hmac_sha256_Init(&ctx, (const uint8_t *)"", 0); + } + hmac_sha256_Update(&ctx, sessionStateSalt, 32); + hmac_sha256_Update(&ctx, (const uint8_t *)storage_uuid, sizeof(storage_uuid)); + hmac_sha256_Final(&ctx, state + 32); + + memzero(&ctx, sizeof(ctx)); +} + +bool session_compareState(const uint8_t *state) +{ + if (!state) { + return false; + } + uint8_t istate[64]; + session_getState(state, istate); + return 0 == memcmp(state, istate, 64); +} + void session_cachePin(void) { sessionPinCached = true; diff --git a/firmware/storage.h b/firmware/storage.h index a8a883299b..2c15e7eb06 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -103,6 +103,8 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); +void session_getState(const uint8_t *salt, uint8_t *state); +bool session_compareState(const uint8_t *state); void storage_setMnemonic(const char *mnemonic); bool storage_containsMnemonic(const char *mnemonic); From 7834eaba26b5f537753a6bf8a8cf30c165501908 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 27 Feb 2018 15:41:02 +0100 Subject: [PATCH 0760/1154] protect: passphrase is optional --- firmware/protect.c | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 3b586e5b1d..ffbe4aa391 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -257,7 +257,7 @@ bool protectPassphrase(void) if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { msg_tiny_id = 0xFFFF; PassphraseAck *ppa = (PassphraseAck *)msg_tiny; - session_cachePassphrase(ppa->passphrase); + session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : ""); result = true; break; } diff --git a/vendor/trezor-common b/vendor/trezor-common index 43b6464883..d85f7ac6bb 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 43b64648832028efbb93079a1bd17794ed4044cb +Subproject commit d85f7ac6bbcccbc83012d85fdf25635e57c5f15b From e460c4fe17743a87b9170907ec5466d7e05f92bf Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 3 Mar 2018 22:22:45 +0100 Subject: [PATCH 0761/1154] session: rework get_state --- firmware/fsm.c | 10 +++++-- firmware/protob/messages.options | 3 +- firmware/storage.c | 47 ++++++++++---------------------- firmware/storage.h | 3 +- vendor/trezor-common | 2 +- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index c4b633a226..c36fb7452a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -234,9 +234,14 @@ void fsm_msgInitialize(Initialize *msg) { recovery_abort(); signing_abort(); - if (msg->has_state && msg->state.size == 64) { - if (!session_compareState(msg->state.bytes)) { + if (msg && msg->has_state && msg->state.size == 64) { + uint8_t i_state[64]; + if (!session_getState(msg->state.bytes, i_state, NULL)) { session_clear(false); // do not clear PIN + } else { + if (0 != memcmp(msg->state.bytes, i_state, 64)) { + session_clear(false); // do not clear PIN + } } } else { session_clear(false); // do not clear PIN @@ -306,7 +311,6 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); - resp->has_state = true; resp->state.size = 64; session_getState(NULL, resp->state.bytes); msg_write(MessageType_MessageType_Features, resp); } diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 88e96cbdec..a34b9f9d8a 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -10,7 +10,6 @@ Features.bootloader_hash max_size:32 Features.model max_size:17 Features.fw_vendor max_size:256 Features.fw_vendor_keys max_size:32 -Features.state max_size:64 ApplySettings.language max_size:17 ApplySettings.label max_size:33 @@ -29,6 +28,8 @@ PinMatrixAck.pin max_size:10 PassphraseAck.passphrase max_size:51 PassphraseAck.state max_size:64 +PassphraseStateRequest.state max_size:64 + Entropy.entropy max_size:1024 GetPublicKey.address_n max_count:8 diff --git a/firmware/storage.c b/firmware/storage.c index ebdb01cf27..1fe9e9b846 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -125,9 +125,6 @@ static bool sessionPinCached; static bool sessionPassphraseCached; static char CONFIDENTIAL sessionPassphrase[51]; -static bool sessionStateSaltSet; -static uint8_t sessionStateSalt[32]; - #define STORAGE_VERSION 9 void storage_show_error(void) @@ -270,8 +267,6 @@ void session_clear(bool clear_pin) memzero(&sessionSeed, sizeof(sessionSeed)); sessionPassphraseCached = false; memzero(&sessionPassphrase, sizeof(sessionPassphrase)); - sessionStateSaltSet = false; - memzero(&sessionStateSalt, sizeof(sessionStateSalt)); if (clear_pin) { sessionPinCached = false; } @@ -715,45 +710,31 @@ bool session_isPassphraseCached(void) return sessionPassphraseCached; } -void session_getState(const uint8_t *salt, uint8_t *state) +bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) { - if (!salt) { - if (!sessionStateSaltSet) { - // generate a random salt if not provided and not already cached - random_buffer(sessionStateSalt, 32); - } + if (!passphrase && !sessionPassphraseCached) { + return false; } else { - // otherwise copy provided salt to cached salt - memcpy(sessionStateSalt, salt, 32); + passphrase = sessionPassphrase; + } + if (!salt) { + // if salt is not provided fill the first half of the state with random data + random_buffer(state, 32); + } else { + // if salt is provided fill the first half of the state with salt + memcpy(state, salt, 32); } - - sessionStateSaltSet = true; - // state[0:32] = salt - memcpy(state, sessionStateSalt, 32); - // state[32:64] = HMAC(passphrase, salt || device_id) HMAC_SHA256_CTX ctx; - if (sessionPassphraseCached) { - hmac_sha256_Init(&ctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase)); - } else { - hmac_sha256_Init(&ctx, (const uint8_t *)"", 0); - } - hmac_sha256_Update(&ctx, sessionStateSalt, 32); + hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); + hmac_sha256_Update(&ctx, state, 32); hmac_sha256_Update(&ctx, (const uint8_t *)storage_uuid, sizeof(storage_uuid)); hmac_sha256_Final(&ctx, state + 32); memzero(&ctx, sizeof(ctx)); -} -bool session_compareState(const uint8_t *state) -{ - if (!state) { - return false; - } - uint8_t istate[64]; - session_getState(state, istate); - return 0 == memcmp(state, istate, 64); + return true; } void session_cachePin(void) diff --git a/firmware/storage.h b/firmware/storage.h index 2c15e7eb06..431e830c6c 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -103,8 +103,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); -void session_getState(const uint8_t *salt, uint8_t *state); -bool session_compareState(const uint8_t *state); +bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); void storage_setMnemonic(const char *mnemonic); bool storage_containsMnemonic(const char *mnemonic); diff --git a/vendor/trezor-common b/vendor/trezor-common index d85f7ac6bb..0924bd6826 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit d85f7ac6bbcccbc83012d85fdf25635e57c5f15b +Subproject commit 0924bd6826bb63f66010e2e511356d54ea733df3 From d5e49556c5f96e10f56e000849a2c5669d576b9f Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 2 Mar 2018 18:00:10 +0100 Subject: [PATCH 0762/1154] Indicate own dest address in send dialog If the destination address is controlled by the TREZOR (the wallet set the address_n field), show the path to the address on the confirm output dialog in the same format as the "show on Trezor" dialog indicates the path. --- firmware/layout2.c | 238 +++++++++++++++++++++++---------------------- 1 file changed, 121 insertions(+), 117 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 9c340085a9..e65234f4f5 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -36,6 +36,122 @@ #define BITCOIN_DIVISIBILITY (8) +static const char *slip44_extras(uint32_t coin_type) +{ + if ((coin_type & 0x80000000) == 0) { + return 0; + } + switch (coin_type & 0x7fffffff) { + case 40: return "EXP"; // Expanse + case 43: return "NEM"; // NEM + case 60: return "ETH"; // Ethereum Mainnet + case 61: return "ETC"; // Ethereum Classic Mainnet + case 108: return "UBQ"; // UBIQ + case 137: return "RSK"; // Rootstock Mainnet + case 37310: return "tRSK"; // Rootstock Testnet + } + return 0; +} + +#define BIP32_MAX_LAST_ELEMENT 1000000 + +static const char *address_n_str(const uint32_t *address_n, size_t address_n_count) +{ + if (address_n_count > 8) { + return _("Unknown long path"); + } + if (address_n_count == 0) { + return _("Path: m"); + } + + // known BIP44/49 path + static char path[100]; + if (address_n_count == 5 && + (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) && + (address_n[1] & 0x80000000) && + (address_n[2] & 0x80000000) && + (address_n[3] <= 1) && + (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { + bool native_segwit = (address_n[0] == (0x80000000 + 84)); + bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); + bool legacy = false; + const CoinInfo *coin = coinByCoinType(address_n[1]); + const char *abbr = 0; + if (native_segwit) { + if (coin && coin->has_segwit && coin->bech32_prefix) { + abbr = coin->coin_shortcut + 1; + } + } else + if (p2sh_segwit) { + if (coin && coin->has_segwit && coin->has_address_type_p2sh) { + abbr = coin->coin_shortcut + 1; + } + } else { + if (coin) { + if (coin->has_segwit && coin->has_address_type_p2sh) { + legacy = true; + } + abbr = coin->coin_shortcut + 1; + } else { + abbr = slip44_extras(address_n[1]); + } + } + uint32_t accnum = (address_n[2] & 0x7fffffff) + 1; + if (abbr && accnum < 100) { + memset(path, 0, sizeof(path)); + strlcpy(path, abbr, sizeof(path)); + // TODO: how to name accounts? + // currently we have "legacy account", "account" and "segwit account" + // for BIP44/P2PKH, BIP49/P2SH-P2WPKH and BIP84/P2WPKH respectivelly + if (legacy) { + strlcat(path, " legacy", sizeof(path)); + } + if (native_segwit) { + strlcat(path, " segwit", sizeof(path)); + } + strlcat(path, " account #", sizeof(path)); + char acc[3]; + memset(acc, 0, sizeof(acc)); + if (accnum < 10) { + acc[0] = '0' + accnum; + } else { + acc[0] = '0' + (accnum / 10); + acc[1] = '0' + (accnum % 10); + } + strlcat(path, acc, sizeof(path)); + return path; + } + } + + // "Path: m" / i ' + static char address_str[7 + 8 * (1 + 9 + 1) + 1]; + char *c = address_str + sizeof(address_str) - 1; + + *c = 0; c--; + + for (int n = (int)address_n_count - 1; n >= 0; n--) { + uint32_t i = address_n[n]; + if (i & 0x80000000) { + *c = '\''; c--; + } + i = i & 0x7fffffff; + do { + *c = '0' + (i % 10); c--; + i /= 10; + } while (i > 0); + *c = '/'; c--; + } + *c = 'm'; c--; + *c = ' '; c--; + *c = ':'; c--; + *c = 'h'; c--; + *c = 't'; c--; + *c = 'a'; c--; + *c = 'P'; + + return c; +} + // split longer string into 4 rows, rowlen chars each static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) { @@ -149,7 +265,11 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) oledDrawString(left, 4 * 9, str[2], FONT_FIXED); oledDrawString(left, 5 * 9, str[3], FONT_FIXED); if (!str[3][0]) { - oledHLine(OLED_HEIGHT - 13); + if (out->address_n_count > 0) { + oledDrawString(0, 5*9, address_n_str(out->address_n, out->address_n_count), FONT_STANDARD); + } else { + oledHLine(OLED_HEIGHT - 13); + } } layoutButtonNo(_("Cancel")); layoutButtonYes(_("Confirm")); @@ -324,122 +444,6 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } -static const char *slip44_extras(uint32_t coin_type) -{ - if ((coin_type & 0x80000000) == 0) { - return 0; - } - switch (coin_type & 0x7fffffff) { - case 40: return "EXP"; // Expanse - case 43: return "NEM"; // NEM - case 60: return "ETH"; // Ethereum Mainnet - case 61: return "ETC"; // Ethereum Classic Mainnet - case 108: return "UBQ"; // UBIQ - case 137: return "RSK"; // Rootstock Mainnet - case 37310: return "tRSK"; // Rootstock Testnet - } - return 0; -} - -#define BIP32_MAX_LAST_ELEMENT 1000000 - -static const char *address_n_str(const uint32_t *address_n, size_t address_n_count) -{ - if (address_n_count > 8) { - return _("Unknown long path"); - } - if (address_n_count == 0) { - return _("Path: m"); - } - - // known BIP44/49 path - static char path[100]; - if (address_n_count == 5 && - (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) && - (address_n[1] & 0x80000000) && - (address_n[2] & 0x80000000) && - (address_n[3] <= 1) && - (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { - bool native_segwit = (address_n[0] == (0x80000000 + 84)); - bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); - bool legacy = false; - const CoinInfo *coin = coinByCoinType(address_n[1]); - const char *abbr = 0; - if (native_segwit) { - if (coin && coin->has_segwit && coin->bech32_prefix) { - abbr = coin->coin_shortcut + 1; - } - } else - if (p2sh_segwit) { - if (coin && coin->has_segwit && coin->has_address_type_p2sh) { - abbr = coin->coin_shortcut + 1; - } - } else { - if (coin) { - if (coin->has_segwit && coin->has_address_type_p2sh) { - legacy = true; - } - abbr = coin->coin_shortcut + 1; - } else { - abbr = slip44_extras(address_n[1]); - } - } - uint32_t accnum = (address_n[2] & 0x7fffffff) + 1; - if (abbr && accnum < 100) { - memset(path, 0, sizeof(path)); - strlcpy(path, abbr, sizeof(path)); - // TODO: how to name accounts? - // currently we have "legacy account", "account" and "segwit account" - // for BIP44/P2PKH, BIP49/P2SH-P2WPKH and BIP84/P2WPKH respectivelly - if (legacy) { - strlcat(path, " legacy", sizeof(path)); - } - if (native_segwit) { - strlcat(path, " segwit", sizeof(path)); - } - strlcat(path, " account #", sizeof(path)); - char acc[3]; - memset(acc, 0, sizeof(acc)); - if (accnum < 10) { - acc[0] = '0' + accnum; - } else { - acc[0] = '0' + (accnum / 10); - acc[1] = '0' + (accnum % 10); - } - strlcat(path, acc, sizeof(path)); - return path; - } - } - - // "Path: m" / i ' - static char address_str[7 + 8 * (1 + 9 + 1) + 1]; - char *c = address_str + sizeof(address_str) - 1; - - *c = 0; c--; - - for (int n = (int)address_n_count - 1; n >= 0; n--) { - uint32_t i = address_n[n]; - if (i & 0x80000000) { - *c = '\''; c--; - } - i = i & 0x7fffffff; - do { - *c = '0' + (i % 10); c--; - i /= 10; - } while (i > 0); - *c = '/'; c--; - } - *c = 'm'; c--; - *c = ' '; c--; - *c = ':'; c--; - *c = 'h'; c--; - *c = 't'; c--; - *c = 'a'; c--; - *c = 'P'; - - return c; -} - void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count) { if (layoutLast != layoutAddress) { From 2a4a298d586c06a0c6dbd4c6e2ed9af6fc9bff86 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 7 Mar 2018 14:04:37 +0100 Subject: [PATCH 0763/1154] firmware: refactor fsm_getDerivedNode to include fingerprint --- firmware/fsm.c | 54 ++++++++++++++++++++-------------------------- firmware/layout2.c | 11 +++++++--- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index c36fb7452a..1a508c637a 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -194,9 +194,12 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name) return coin; } -static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count) +static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) { static CONFIDENTIAL HDNode node; + if (fingerprint) { + *fingerprint = 0; + } if (!storage_getRootNode(&node, curve, true)) { fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); @@ -205,7 +208,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, if (!address_n || address_n_count == 0) { return &node; } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); layoutHome(); return 0; @@ -439,19 +442,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) curve = msg->ecdsa_curve_name; } uint32_t fingerprint; - HDNode *node; - if (msg->address_n_count == 0) { - /* get master node */ - fingerprint = 0; - node = fsm_getDerivedNode(curve, msg->address_n, 0); - } else { - /* get parent node */ - node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count - 1); - if (!node) return; - fingerprint = hdnode_fingerprint(node); - /* get child */ - hdnode_private_ckd(node, msg->address_n[msg->address_n_count - 1]); - } + HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); + if (!node) return; hdnode_fill_public_key(node); if (msg->has_show_display && msg->show_display) { @@ -545,7 +537,7 @@ void fsm_msgSignTx(SignTx *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - const HDNode *node = fsm_getDerivedNode(coin->curve_name, 0, 0); + const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); if (!node) return; signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); @@ -573,7 +565,7 @@ void fsm_msgEthereumSignTx(EthereumSignTx *msg) CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; ethereum_signing_init(msg, node); @@ -594,7 +586,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; bool encrypt = msg->has_encrypt && msg->encrypt; @@ -789,7 +781,7 @@ void fsm_msgGetAddress(GetAddress *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); if (!node) return; hdnode_fill_public_key(node); @@ -844,7 +836,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; resp->address.size = 20; @@ -883,7 +875,7 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; ethereum_message_sign(msg, node, resp); @@ -945,7 +937,7 @@ void fsm_msgSignMessage(SignMessage *msg) const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); if (!node) return; layoutProgressSwipe(_("Signing"), 0); @@ -1027,7 +1019,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) if (msg->has_ecdsa_curve_name) { curve = msg->ecdsa_curve_name; } - HDNode *node = fsm_getDerivedNode(curve, address_n, 5); + HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); if (!node) return; bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); @@ -1104,7 +1096,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) curve = msg->ecdsa_curve_name; } - const HDNode *node = fsm_getDerivedNode(curve, address_n, 5); + const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); if (!node) return; int result_size = 0; @@ -1140,7 +1132,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) CHECK_PIN - node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; hdnode_get_address_raw(node, coin->address_type, address_raw); } @@ -1177,7 +1169,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; layoutProgressSwipe(_("Decrypting"), 0); @@ -1266,7 +1258,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) RESP_INIT(NEMAddress); - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count); + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; if (!hdnode_get_nem_address(node, msg->network, resp->address)) @@ -1339,7 +1331,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { RESP_INIT(NEMSignedTx); - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count); + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); if (!node) return; hdnode_fill_public_key(node); @@ -1503,7 +1495,7 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) CHECK_PIN - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; const uint8_t *salt = msg->payload.bytes; @@ -1557,7 +1549,7 @@ void fsm_msgCosiCommit(CosiCommit *msg) CHECK_PIN - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; uint8_t nonce[32]; @@ -1597,7 +1589,7 @@ void fsm_msgCosiSign(CosiSign *msg) CHECK_PIN - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count); + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; uint8_t nonce[32]; diff --git a/firmware/layout2.c b/firmware/layout2.c index e65234f4f5..b56f787db9 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -511,11 +511,16 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno void layoutPublicKey(const uint8_t *pubkey) { - char hex[32*2+1], desc[16]; + char hex[32 * 2 + 1], desc[16]; strlcpy(desc, "Public Key: 00", sizeof(desc)); - data2hex(pubkey, 1, desc + 12); + if (pubkey[0] == 1) { + /* ed25519 public key */ + // pass - leave 00 + } else { + data2hex(pubkey, 1, desc + 12); + } data2hex(pubkey + 1, 32, hex); - const char **str = split_message((const uint8_t *)hex, 32*2, 16); + const char **str = split_message((const uint8_t *)hex, 32 * 2, 16); layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0], str[1], str[2], str[3], NULL); } From e0b5526f274618a650bee55f765e88f5b90263d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 7 Mar 2018 14:16:24 +0100 Subject: [PATCH 0764/1154] bootloader: react to GetFeatures too --- bootloader/usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bootloader/usb.c b/bootloader/usb.c index 57d70cd1a8..76ca596a0b 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -292,6 +292,10 @@ static void rx_callback(usbd_device *dev, uint8_t ep) flash_state = STATE_OPEN; return; } + if (msg_id == 0x0037) { // GetFeatures message (id 55) + send_msg_features(dev); + return; + } if (msg_id == 0x0001) { // Ping message (id 1) send_msg_success(dev); return; From 4af78f06a3f8a8f29ec2281e860d05e303f8f80d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Mar 2018 15:33:44 +0100 Subject: [PATCH 0765/1154] bootloader: refactor signatures_ok return value --- bootloader/bootloader.c | 9 ++++++--- bootloader/signatures.c | 26 +++++++++++++------------- bootloader/signatures.h | 3 +++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 2cf8988aeb..9d86b5e112 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -76,8 +76,10 @@ void show_unofficial_warning(const uint8_t *hash) // everything is OK, user pressed 2x Continue -> continue program } -void __attribute__((noreturn)) load_app(void) +void __attribute__((noreturn)) load_app(int signed_firmware) { + (void)signed_firmware; + // zero out SRAM memset_reg(_ram_start, _ram_end, 0); @@ -146,13 +148,14 @@ int main(void) oledRefresh(); uint8_t hash[32]; - if (!signatures_ok(hash)) { + int signed_firmware = signatures_ok(hash); + if (SIG_OK != signed_firmware) { show_unofficial_warning(hash); } delay(100000); - load_app(); + load_app(signed_firmware); } #endif diff --git a/bootloader/signatures.c b/bootloader/signatures.c index c49901e671..e178ecec7a 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -51,23 +51,23 @@ int signatures_ok(uint8_t *store_hash) memcpy(store_hash, hash, 32); } - if (sigindex1 < 1 || sigindex1 > PUBKEYS) return 0; // invalid index - if (sigindex2 < 1 || sigindex2 > PUBKEYS) return 0; // invalid index - if (sigindex3 < 1 || sigindex3 > PUBKEYS) return 0; // invalid index + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index + if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index + if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index - if (sigindex1 == sigindex2) return 0; // duplicate use - if (sigindex1 == sigindex3) return 0; // duplicate use - if (sigindex2 == sigindex3) return 0; // duplicate use + if (sigindex1 == sigindex2) return SIG_FAIL; // duplicate use + if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use + if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure - return 0; + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash)) { // failure + return SIG_FAIL; } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash) != 0) { // failure - return 0; + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash)) { // failure + return SIG_FAIL; } - if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash) != 0) { // failture - return 0; + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash)) { // failture + return SIG_FAIL; } - return 1; + return SIG_OK; } diff --git a/bootloader/signatures.h b/bootloader/signatures.h index 60037d69a5..01b5f308c1 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -20,6 +20,9 @@ #ifndef __SIGNATURES_H__ #define __SIGNATURES_H__ +#define SIG_OK 0x5A3CA5C3 +#define SIG_FAIL 0x00000000 + int signatures_ok(uint8_t *store_hash); #endif From 5ad53e99c37c7b98a18002bffc0295ef83a96281 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Mar 2018 15:42:31 +0100 Subject: [PATCH 0766/1154] bootloader: bump version to 1.4.0 --- bootloader/bootloader.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index ee4b8722d4..064f270ee2 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,15 +21,15 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 3 -#define VERSION_PATCH 3 +#define VERSION_MINOR 4 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x03" -#define VERSION_PATCH_CHAR "\x03" +#define VERSION_MINOR_CHAR "\x04" +#define VERSION_PATCH_CHAR "\x00" #include #include "memory.h" From e444dadbb2dbbd9aa3713f6587a7ac1e8a146494 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 13 Mar 2018 13:23:15 +0200 Subject: [PATCH 0767/1154] storage: next firmware version would be 1.7.0 --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 1fe9e9b846..9c5faefbdb 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -160,7 +160,7 @@ bool storage_from_flash(void) // version 6: since 1.3.6 // version 7: since 1.5.1 // version 8: since 1.5.2 - // version 9: since 1.6.1 + // version 9: since 1.7.0 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; From b20336e82d19d95a0ce65d13d6c7bcf9d11ac668 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 14 Mar 2018 00:35:59 +0100 Subject: [PATCH 0768/1154] Revert WinUSB feature This reverts the following range of commits: 68168393b9ea61328f4bb43bc3059ab32c4be2e9..ab76828e16b552c82f468e5d89f1af0645258995 Revert "update usb descriptors" This reverts commit ab76828e16b552c82f468e5d89f1af0645258995. Revert "trezorhal: reply with winusb guid just for the main interface (0)" This reverts commit 6acfc5d1b3c55de4545cc8a749d0cb6552592624. Revert "winusb: fix WINUSB_EXTRA_STRING" This reverts commit 966d8cb4ce561c37aaf8d261a981d3dc91e01e19. Revert "winusb: cleanup DeviceInterfaceGUIDs usage" This reverts commit 56c5a46095ea2abc963888de7c56a08916cd3878. Revert "make winusb_string_descriptor const" This reverts commit 132cc4b4748fa507a9aa47d15fd638637bcf23da. Revert "webusb: remove unused constants" This reverts commit 38b4d507bc12e737879d016adc7dfa914a64c59d. Revert "bootloader: remove debug" This reverts commit 56d3cbe2e93b133ba6f269e1b64c0ac7192ab2f1. Revert "Bootloader - Switch from HID to WebUSB" This reverts commit a22abfe90b846a7884bd365e2d8de99124ad000b. Revert "Switch from HID to WebUSB" This reverts commit cb067bd14c57445430fbaa4da8c77badf0d1f772. Revert "Add WinUSB, WebUSB, USB2.1 to build" This reverts commit 05e218bcb8279ccaa19f258dc7844648353353a0. Revert "Add WebUSB descriptors" This reverts commit a062127cef4d5ac682699cbbc80a841de72943a2. Revert "Add WinUSB (WebUSB preparation)" This reverts commit e6981e85cdc3f96c305cc22b349c15fcf978341e. --- Makefile | 4 - bootloader/usb.c | 124 +++++++++++++++--------- firmware/usb.c | 247 ++++++++++++++++++++++++++++------------------- usb21_standard.h | 17 +++- webusb.c | 94 ------------------ webusb.h | 31 ------ webusb_defs.h | 61 ------------ winusb.c | 161 ------------------------------ winusb.h | 30 ------ winusb_defs.h | 89 ----------------- 10 files changed, 245 insertions(+), 613 deletions(-) delete mode 100644 webusb.c delete mode 100644 webusb.h delete mode 100644 webusb_defs.h delete mode 100644 winusb.c delete mode 100644 winusb.h delete mode 100644 winusb_defs.h diff --git a/Makefile b/Makefile index ba1ebf59bc..81d418d9d1 100644 --- a/Makefile +++ b/Makefile @@ -19,10 +19,6 @@ ifneq ($(EMULATOR),1) OBJS += timer.o endif -OBJS += usb21_standard.o -OBJS += webusb.o -OBJS += winusb.o - OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/bootloader/usb.c b/bootloader/usb.c index 76ca596a0b..1e2a752d99 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -36,14 +37,8 @@ #include "secp256k1.h" #include "memzero.h" -#include "usb21_standard.h" -#include "webusb.h" -#include "winusb.h" - #define FIRMWARE_MAGIC "TRZR" -#define USB_INTERFACE_INDEX_MAIN 0 - #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -53,21 +48,60 @@ static bool old_was_unsigned; static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, + .bcdUSB = 0x0200, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0300, + .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1, }; -static const struct usb_endpoint_descriptor endpoints[2] = {{ +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + +static const struct { + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) hid_function = { + .hid_descriptor = { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + } +}; + +static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN, @@ -83,24 +117,24 @@ static const struct usb_endpoint_descriptor endpoints[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor iface[] = {{ +static const struct usb_interface_descriptor hid_iface[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = 0, - .endpoint = endpoints, - .extra = NULL, - .extralen = 0, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), }}; static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = iface, + .altsetting = hid_iface, }}; static const struct usb_config_descriptor config = { @@ -121,6 +155,23 @@ static const char *usb_strings[] = { "", // empty serial }; +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) +{ + (void)complete; + (void)dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) + return 0; + + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); + + return 1; +} + enum { STATE_READY, STATE_OPEN, @@ -264,7 +315,7 @@ static void restore_metadata(const uint8_t *backup) flash_lock(); } -static void rx_callback(usbd_device *dev, uint8_t ep) +static void hid_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); @@ -581,37 +632,23 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } -static void set_config(usbd_device *dev, uint16_t wValue) +static void hid_set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + + usbd_register_control_callback( + dev, + USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + hid_control_request + ); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); - -static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, -}; - -static const struct usb_bos_descriptor bos_descriptor = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), - .capabilities = capabilities -}; - -void usbInit(void) -{ - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config); - usb21_setup(usbd_dev, &bos_descriptor); - static const char* origin_url = "trezor.io/start"; - webusb_setup(usbd_dev, origin_url); - winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); -} +static uint8_t usbd_control_buffer[128]; void checkButtons(void) { @@ -645,7 +682,8 @@ void checkButtons(void) void usbLoop(bool firmware_present) { brand_new_firmware = !firmware_present; - usbInit(); + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); for (;;) { usbd_poll(usbd_dev); if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { diff --git a/firmware/usb.c b/firmware/usb.c index be7cae7b91..7a59b6fa02 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -29,27 +29,18 @@ #include "util.h" #include "timer.h" -#include "usb21_standard.h" -#include "webusb.h" -#include "winusb.h" - - #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK #define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_U2F 2 -#define USB_INTERFACE_COUNT 3 #else #define USB_INTERFACE_INDEX_U2F 1 -#define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_MAIN_IN (0x81) -#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) -#if DEBUG_LINK +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) -#endif #define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_OUT (0x03) @@ -59,7 +50,7 @@ X(SERIAL_NUMBER, storage_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ - X(INTERFACE_U2F, "TREZOR U2F Interface") \ + X(INTERFACE_U2F, "U2F Interface") #define X(name, value) USB_STRING_##name, enum { @@ -77,20 +68,60 @@ static const char *usb_strings[] = { static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, + .bcdUSB = 0x0200, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0200, + .bcdDevice = 0x0100, .iManufacturer = USB_STRING_MANUFACTURER, .iProduct = USB_STRING_PRODUCT, .iSerialNumber = USB_STRING_SERIAL_NUMBER, .bNumConfigurations = 1, }; +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; + +#if DEBUG_LINK +static const uint8_t hid_report_descriptor_debug[] = { + 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) + 0x09, 0x01, // USAGE (1) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION +}; +#endif + static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) 0x09, 0x01, // USAGE (U2F HID Authenticator Device) @@ -110,6 +141,26 @@ static const uint8_t hid_report_descriptor_u2f[] = { 0xc0 // END_COLLECTION }; +static const struct { + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) hid_function = { + .hid_descriptor = { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + } +}; + static const struct { struct usb_hid_descriptor hid_descriptor_u2f; struct { @@ -130,22 +181,54 @@ static const struct { } }; -static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ + +static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, .bInterval = 1, }}; +static const struct usb_interface_descriptor hid_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), +}}; + +static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 2, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 2, +}}; + static const struct usb_interface_descriptor hid_iface_u2f[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, @@ -162,7 +245,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ +static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, @@ -178,64 +261,29 @@ static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor webusb_iface_debug[] = {{ +static const struct usb_interface_descriptor hid_iface_debug[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceClass = USB_CLASS_HID, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = webusb_endpoints_debug, - .extra = NULL, - .extralen = 0, + .endpoint = hid_endpoints_debug, + .extra = &hid_function, + .extralen = sizeof(hid_function), }}; - #endif -static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor webusb_iface_main[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = webusb_endpoints_main, - .extra = NULL, - .extralen = 0, -}}; - - -// Windows are strict about interfaces appearing -// in correct order static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = webusb_iface_main, + .altsetting = hid_iface, #if DEBUG_LINK }, { .num_altsetting = 1, - .altsetting = webusb_iface_debug, + .altsetting = hid_iface_debug, #endif }, { .num_altsetting = 1, @@ -246,7 +294,11 @@ static const struct usb_config_descriptor config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, - .bNumInterfaces = USB_INTERFACE_COUNT, +#if DEBUG_LINK + .bNumInterfaces = 3, +#else + .bNumInterfaces = 2, +#endif .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, @@ -260,24 +312,40 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (void)dev; if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) return 0; - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); + if (req->wIndex == USB_INTERFACE_INDEX_U2F) { + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = sizeof(hid_report_descriptor_u2f); + return 1; + } + +#if DEBUG_LINK + if (req->wIndex == USB_INTERFACE_INDEX_DEBUG) { + debugLog(0, "", "hid_control_request debug"); + *buf = (uint8_t *)hid_report_descriptor_debug; + *len = sizeof(hid_report_descriptor_debug); + return 1; + } +#endif + + debugLog(0, "", "hid_control_request main"); + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); return 1; } static volatile char tiny = 0; -static void main_rx_callback(usbd_device *dev, uint8_t ep) +static void hid_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; - debugLog(0, "", "main_rx_callback"); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; + debugLog(0, "", "hid_rx_callback"); if (!tiny) { msg_read(buf, 64); } else { @@ -285,23 +353,23 @@ static void main_rx_callback(usbd_device *dev, uint8_t ep) } } -static void u2f_rx_callback(usbd_device *dev, uint8_t ep) +static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - debugLog(0, "", "u2f_rx_callback"); + debugLog(0, "", "hid_u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } #if DEBUG_LINK -static void debug_rx_callback(usbd_device *dev, uint8_t ep) +static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "debug_rx_callback"); + debugLog(0, "", "hid_debug_rx_callback"); if (!tiny) { msg_debug_read(buf, 64); } else { @@ -310,17 +378,17 @@ static void debug_rx_callback(usbd_device *dev, uint8_t ep) } #endif -static void set_config(usbd_device *dev, uint16_t wValue) +static void hid_set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_u2f_rx_callback); #if DEBUG_LINK usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); #endif usbd_register_control_callback( @@ -331,29 +399,12 @@ static void set_config(usbd_device *dev, uint16_t wValue) } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); - -static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, -}; - -static const struct usb_bos_descriptor bos_descriptor = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), - .capabilities = capabilities -}; +static uint8_t usbd_control_buffer[128]; void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config); - usb21_setup(usbd_dev, &bos_descriptor); - static const char* origin_url = "trezor.io/start"; - webusb_setup(usbd_dev, origin_url); - // Debug link interface does not have WinUSB set; - // if you really need debug link on windows, edit the descriptor in winusb.c - winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); + usbd_register_set_config_callback(usbd_dev, hid_set_config); } void usbPoll(void) @@ -364,7 +415,7 @@ void usbPoll(void) // write pending data data = msg_out_data(); if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} } data = u2f_out_data(); if (data) { diff --git a/usb21_standard.h b/usb21_standard.h index e5358bcd5f..e7578a533b 100644 --- a/usb21_standard.h +++ b/usb21_standard.h @@ -22,8 +22,10 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 +#define USB_DT_BOS 15 #define USB_DT_DEVICE_CAPABILITY 16 +#define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 +#define USB_DT_SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49 struct usb_device_capability_descriptor { uint8_t bLength; @@ -43,7 +45,18 @@ struct usb_bos_descriptor { #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_PLATFORM 5 +#define USB_DC_WIRELESS_USB 1 +#define USB_DC_USB_2_0_EXTENSION 2 +#define USB_DC_SUPERSPEED_USB 3 +#define USB_DC_CONTAINER_ID 4 +#define USB_DC_PLATFORM 5 +#define USB_DC_POWER_DELIVERY_CAPABILITY 6 +#define USB_DC_BATTERY_INFO_CAPABILITY 7 +#define USB_DC_PD_CONSUMER_PORT_CAPABILITY 8 +#define USB_DC_PD_PROVIDER_PORT_CAPABILITY 9 +#define USB_DC_SUPERSPEED_PLUS 10 +#define USB_DC_PRECISION_TIME_MEASUREMENT 11 +#define USB_DC_WIRELESS_USB_EXT 12 extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); diff --git a/webusb.c b/webusb.c deleted file mode 100644 index beb909c089..0000000000 --- a/webusb.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include "util.h" -#include "webusb.h" -#include "usb21_standard.h" - -const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { - .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DC_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = WEBUSB_UUID, - .bcdVersion = 0x0100, - .bVendorCode = WEBUSB_VENDOR_CODE, - .iLandingPage = 1 -}; - -static const char* webusb_https_url; - -static int webusb_control_vendor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; - - if (req->bRequest != WEBUSB_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } - - int status = USBD_REQ_NOTSUPP; - switch (req->wIndex) { - case WEBUSB_REQ_GET_URL: { - struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); - uint16_t index = req->wValue; - if (index == 0) { - return USBD_REQ_NOTSUPP; - } - - if (index == 1) { - size_t url_len = strlen(webusb_https_url); - url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; - url->bDescriptorType = WEBUSB_DT_URL; - url->bScheme = WEBUSB_URL_SCHEME_HTTPS; - memcpy(&url->URL, webusb_https_url, url_len); - *len = MIN(*len, url->bLength); - status = USBD_REQ_HANDLED; - } else { - // TODO: stall instead? - status = USBD_REQ_NOTSUPP; - } - break; - } - default: { - status = USBD_REQ_NOTSUPP; - break; - } - } - - return status; -} - -static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - webusb_control_vendor_request); -} - -void webusb_setup(usbd_device* usbd_dev, const char* https_url) { - webusb_https_url = https_url; - - usbd_register_set_config_callback(usbd_dev, webusb_set_config); -} diff --git a/webusb.h b/webusb.h deleted file mode 100644 index 342408f1f7..0000000000 --- a/webusb.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef WEBUSB_H_INCLUDED -#define WEBUSB_H_INCLUDED - -#include -#include "webusb_defs.h" - -// Arbitrary -#define WEBUSB_VENDOR_CODE 0x01 - -extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; -extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); - -#endif diff --git a/webusb_defs.h b/webusb_defs.h deleted file mode 100644 index 45b5f2478d..0000000000 --- a/webusb_defs.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef WEBUSB_DEFS_H_INCLUDED -#define WEBUSB_DEFS_H_INCLUDED - -#include - -#define WEBUSB_REQ_GET_URL 0x02 - -#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 -#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 -#define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2 -#define WEBUSB_DT_URL 3 - -#define WEBUSB_URL_SCHEME_HTTP 0 -#define WEBUSB_URL_SCHEME_HTTPS 1 - -struct webusb_platform_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - uint8_t bReserved; - uint8_t platformCapabilityUUID[16]; - uint16_t bcdVersion; - uint8_t bVendorCode; - uint8_t iLandingPage; -} __attribute__((packed)); - -#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) - -// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor -// see also this (for endianness explanation) -// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 -#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} - -struct webusb_url_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bScheme; - char URL[]; -} __attribute__((packed)); - -#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 - -#endif diff --git a/winusb.c b/winusb.c deleted file mode 100644 index afdaf8b706..0000000000 --- a/winusb.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include "util.h" -#include "winusb.h" - -static int usb_descriptor_type(uint16_t wValue) { - return wValue >> 8; -} - -static int usb_descriptor_index(uint16_t wValue) { - return wValue & 0xFF; -} - -static struct winusb_compatible_id_descriptor winusb_wcid = { - .header = { - .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + - 1 * sizeof(struct winusb_compatible_id_function_section), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, - .bNumSections = 1, - .reserved = { 0, 0, 0, 0, 0, 0, 0 }, - }, - .functions = { - { - // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number - .bInterfaceNumber = 0, - .reserved0 = { 1 }, - .compatibleId = "WINUSB", - .subCompatibleId = "", - .reserved1 = { 0, 0, 0, 0, 0, 0} - }, - } -}; - -static const struct usb_string_descriptor winusb_string_descriptor = { - .bLength = 0x12, - .bDescriptorType = USB_DT_STRING, - .wData = WINUSB_EXTRA_STRING -}; - -static const struct winusb_extended_properties_descriptor guid = { - .header = { - .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) - + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, - .wNumFeatures = 1, - }, - .features = { - { - .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), - .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, - .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, - .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, - .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, - .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, - }, - } -}; - -static int winusb_descriptor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; - - if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { - return USBD_REQ_NEXT_CALLBACK; - } - - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { - if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { - *buf = (uint8_t*)(&winusb_string_descriptor); - *len = MIN(*len, winusb_string_descriptor.bLength); - return USBD_REQ_HANDLED; - } - } - return USBD_REQ_NEXT_CALLBACK; -} - -static int winusb_control_vendor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; - - if (req->bRequest != WINUSB_MS_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } - - int status = USBD_REQ_NOTSUPP; - if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && - (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { - *buf = (uint8_t*)(&winusb_wcid); - *len = MIN(*len, winusb_wcid.header.dwLength); - status = USBD_REQ_HANDLED; - - } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && - (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && - (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { - - *buf = (uint8_t*)(&guid); - *len = MIN(*len, guid.header.dwLength); - status = USBD_REQ_HANDLED; - - } else { - status = USBD_REQ_NOTSUPP; - } - - return status; -} - -static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); -} - -void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { - winusb_wcid.functions[0].bInterfaceNumber = interface; - - usbd_register_set_config_callback(usbd_dev, winusb_set_config); - - /* Windows probes the compatible ID before setting the configuration, - so also register the callback now */ - - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); - - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_RECIPIENT, - winusb_descriptor_request); -} - diff --git a/winusb.h b/winusb.h deleted file mode 100644 index 16a6df1153..0000000000 --- a/winusb.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef WINUSB_H_INCLUDED -#define WINUSB_H_INCLUDED - -#include "winusb_defs.h" - -// Arbitrary, but must be equivalent to the last character in extra string -#define WINUSB_MS_VENDOR_CODE '!' -#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} - -extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); - -#endif diff --git a/winusb_defs.h b/winusb_defs.h deleted file mode 100644 index 830e6b1545..0000000000 --- a/winusb_defs.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2016, Devan Lai - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef WINUSB_DEFS_H_INCLUDED -#define WINUSB_DEFS_H_INCLUDED - -#include - -/* Microsoft OS 1.0 descriptors */ - -/* Extended Compat ID OS Feature Descriptor Specification */ -#define WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 -#define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 -#define WINUSB_BCD_VERSION 0x0100 - -// Apparently using DeviceInterfaceGUID does not always work on Windows 7. -// DeviceInterfaceGUIDs does seem to work. -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) - -// extra null is intentional - it's an array of GUIDs with 1 item -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) -#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 - -#define WINUSB_EXTRA_STRING_INDEX 0xee - -/* Table 2. Function Section */ -struct winusb_compatible_id_function_section { - uint8_t bInterfaceNumber; - uint8_t reserved0[1]; - char compatibleId[8]; - char subCompatibleId[8]; - uint8_t reserved1[6]; -} __attribute__((packed)); - -/* Table 1. Header Section */ -struct winusb_compatible_id_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint8_t bNumSections; - uint8_t reserved[7]; -} __attribute__((packed)); - -struct winusb_compatible_id_descriptor { - struct winusb_compatible_id_descriptor_header header; - struct winusb_compatible_id_function_section functions[]; -} __attribute__((packed)); - -struct winusb_extended_properties_feature_descriptor { - uint32_t dwLength; - uint32_t dwPropertyDataType; - uint16_t wNameLength; - uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; - uint32_t dwPropertyDataLength; - uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; -} __attribute__((packed)); - -struct winusb_extended_properties_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint16_t wNumFeatures; -} __attribute__((packed)); - -struct winusb_extended_properties_descriptor { - struct winusb_extended_properties_descriptor_header header; - struct winusb_extended_properties_feature_descriptor features[]; -} __attribute__((packed)); - -#endif From b933e292db1c00238e1289a215e77f0ef0fbe144 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 Mar 2018 03:02:36 +0100 Subject: [PATCH 0769/1154] bootloader: fix signatures_ok usage in usb.c after refactoring --- bootloader/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 1e2a752d99..4be378618a 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -444,7 +444,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } if (brand_new_firmware || button.YesUp) { // check whether current firmware is signed - if (signatures_ok(NULL)) { + if (SIG_OK == signatures_ok(NULL)) { old_was_unsigned = false; // backup metadata backup_metadata(meta_backup); @@ -603,7 +603,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // 1) old firmware was unsigned // 2) firmware restore flag isn't set // 3) signatures are not ok - if (old_was_unsigned || (flags & 0x01) == 0 || !signatures_ok(NULL)) { + if (old_was_unsigned || (flags & 0x01) == 0 || SIG_OK != signatures_ok(NULL)) { memzero(meta_backup, sizeof(meta_backup)); } // copy new firmware header From 816b4e0f72c65096c8fb961b08de6560a5e788d9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 Mar 2018 03:15:08 +0100 Subject: [PATCH 0770/1154] bootloader: process WipeDevice --- bootloader/usb.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/bootloader/usb.c b/bootloader/usb.c index 4be378618a..4dea3c15a5 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -351,6 +351,38 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) send_msg_success(dev); return; } + if (msg_id == 0x0005) { // WipeDevice message (id 5) + layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + if (button.YesUp) { + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // erase metadata area + for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // erase code area + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); + flash_state = STATE_END; + layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); + send_msg_success(dev); + } else { + flash_state = STATE_END; + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); + send_msg_failure(dev); + } + return; + } if (msg_id == 0x0020) { // SelfTest message (id 32) // USB TEST From dbe444029a1dad58652f91e2c81d8cbe4318993c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 Mar 2018 04:15:41 +0100 Subject: [PATCH 0771/1154] bootloader: guard signatures_ok calls with firmware_present (or !brand_new_firmware) --- bootloader/signatures.c | 2 ++ bootloader/usb.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bootloader/signatures.c b/bootloader/signatures.c index e178ecec7a..9f9e540f6a 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -40,6 +40,8 @@ static const uint8_t * const pubkey[PUBKEYS] = { int signatures_ok(uint8_t *store_hash) { + if (!firmware_present()) return SIG_FAIL; // no firmware present + const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); diff --git a/bootloader/usb.c b/bootloader/usb.c index 4dea3c15a5..4fbf088126 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -476,7 +476,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } if (brand_new_firmware || button.YesUp) { // check whether current firmware is signed - if (SIG_OK == signatures_ok(NULL)) { + if (!brand_new_firmware && SIG_OK == signatures_ok(NULL)) { old_was_unsigned = false; // backup metadata backup_metadata(meta_backup); @@ -632,10 +632,11 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) layoutProgress("INSTALLING ... Please wait", 1000); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); // wipe storage if: + // 0) there was no firmware // 1) old firmware was unsigned // 2) firmware restore flag isn't set // 3) signatures are not ok - if (old_was_unsigned || (flags & 0x01) == 0 || SIG_OK != signatures_ok(NULL)) { + if (brand_new_firmware || old_was_unsigned || (flags & 0x01) == 0 || SIG_OK != signatures_ok(NULL)) { memzero(meta_backup, sizeof(meta_backup)); } // copy new firmware header From 5ae04c17c53602fb1793b98b06563997954be6e4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 19 Mar 2018 15:18:54 +0100 Subject: [PATCH 0772/1154] firmware: set version to 1.6.1 --- firmware/ChangeLog | 3 +-- firmware/storage.c | 2 +- firmware/trezor.h | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 30acfd98b8..5ca85f1a7d 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,7 +1,6 @@ -Version 1.7.0 +Version 1.6.1 * Stable release, optional update * Use fixed-width font for addresses -* Enable WebUSB * Lots of under-the-hood improvements Version 1.6.0 diff --git a/firmware/storage.c b/firmware/storage.c index 9c5faefbdb..1fe9e9b846 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -160,7 +160,7 @@ bool storage_from_flash(void) // version 6: since 1.3.6 // version 7: since 1.5.1 // version 8: since 1.5.2 - // version 9: since 1.7.0 + // version 9: since 1.6.1 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; diff --git a/firmware/trezor.h b/firmware/trezor.h index 20fcfc481e..d40a10e29c 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,8 +23,8 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 7 -#define VERSION_PATCH 0 +#define VERSION_MINOR 6 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) From 559a700fb04092bf6bc3410fd30ea463c19ef6c6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 20 Mar 2018 15:41:16 +0100 Subject: [PATCH 0773/1154] fsm: add for button before Recovery device --- firmware/fsm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 1a508c637a..d6bcfc0ee0 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1212,6 +1212,13 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, From d6f41dba9e41ba49780878dadf157939d2eeb101 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 20 Mar 2018 14:48:40 +0100 Subject: [PATCH 0774/1154] messages: fix size of msg_tiny and add static_assert --- firmware/messages.c | 11 ++++++++++- firmware/messages.h | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 6db0d54dbd..d290da7798 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -314,7 +314,16 @@ const uint8_t *msg_debug_out_data(void) #endif -CONFIDENTIAL uint8_t msg_tiny[64]; +CONFIDENTIAL uint8_t msg_tiny[128]; +_Static_assert(sizeof(msg_tiny) >= sizeof(Cancel), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(Initialize), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(PassphraseAck), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny"); +#if DEBUG_LINK +_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), "msg_tiny too tiny"); +#endif uint16_t msg_tiny_id = 0xFFFF; void msg_read_tiny(const uint8_t *buf, int len) diff --git a/firmware/messages.h b/firmware/messages.h index e0a5c8b6fc..ace4a44480 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -47,7 +47,7 @@ bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr); void msg_read_tiny(const uint8_t *buf, int len); void msg_debug_read_tiny(const uint8_t *buf, int len); -extern uint8_t msg_tiny[64]; +extern uint8_t msg_tiny[128]; extern uint16_t msg_tiny_id; #endif From 9588e8f2736b60916f51e470deb18f55112a6ebc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 11 Mar 2018 15:58:11 +0100 Subject: [PATCH 0775/1154] update bootloader to 1.4.0 via firmware, run unsigned firmware in unprivileged mode --- bootloader/bootloader.c | 4 +-- firmware/.gitignore | 2 ++ firmware/Makefile | 5 +++ firmware/bl_check.c | 75 +++++++++++++++++++++++++++++++++++++++++ firmware/bl_check.h | 25 ++++++++++++++ firmware/bl_data-gen.py | 19 +++++++++++ firmware/fastflash.c | 2 +- firmware/trezor.c | 2 ++ memory.c | 18 ++++++++++ memory.h | 1 + util.h | 13 +++++-- 11 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 firmware/bl_check.c create mode 100644 firmware/bl_check.h create mode 100755 firmware/bl_data-gen.py diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 9d86b5e112..185180bd82 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -78,12 +78,10 @@ void show_unofficial_warning(const uint8_t *hash) void __attribute__((noreturn)) load_app(int signed_firmware) { - (void)signed_firmware; - // zero out SRAM memset_reg(_ram_start, _ram_end, 0); - load_vector_table((const vector_table_t *) FLASH_APP_START); + jump_to_firmware((const vector_table_t *) FLASH_APP_START, signed_firmware); } bool firmware_present(void) diff --git a/firmware/.gitignore b/firmware/.gitignore index be84b50dd3..e21cd098b0 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -2,3 +2,5 @@ coins_array.h coins_count.h nem_mosaics.[ch] + +bl_data.h diff --git a/firmware/Makefile b/firmware/Makefile index c49eb33fb5..915435363d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -13,6 +13,7 @@ else OBJS += usb.o endif +OBJS += bl_check.o OBJS += u2f.o OBJS += messages.o OBJS += storage.o @@ -120,6 +121,10 @@ coins_array.h: coins-gen.py coins.json nem_mosaics.c nem_mosaics.h: nem_mosaics.py nem_mosaics.json $(PYTHON) $< +bl_data.h: bl_data-gen.py ../bootloader/bootloader.bin + $(PYTHON) $< + clean:: rm -f coins_count.h coins_array.h rm -f nem_mosaics.c nem_mosaics.h + rm -f bl_data.h diff --git a/firmware/bl_check.c b/firmware/bl_check.c new file mode 100644 index 0000000000..1e53497f2c --- /dev/null +++ b/firmware/bl_check.c @@ -0,0 +1,75 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include "bl_data.h" +#include "memory.h" +#include "layout.h" +#include "gettext.h" +#include "util.h" + +int known_bootloader(int r, const uint8_t *hash) { + if (r != 32) return 0; + if (0 == memcmp(hash, "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98", 32)) return 1; // 1.2.0a + if (0 == memcmp(hash, "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e", 32)) return 1; // 1.2.0b + if (0 == memcmp(hash, "\xc4\xc3\x25\x39\xb4\xa0\x25\xa8\xe7\x53\xa4\xc4\x62\x64\x28\x59\x11\xa4\x5f\xcb\x14\xf4\x71\x81\x79\xe7\x11\xb1\xce\x99\x05\x24", 32)) return 1; // 1.2.5 + if (0 == memcmp(hash, "\x42\x59\x66\x94\xa0\xf2\x9d\x1e\xc2\x35\x71\x29\x2d\x54\x39\xd8\x2f\xa1\x8c\x07\x37\xcb\x10\x7e\x98\xf6\x1e\xf5\x93\x4d\xe7\x16", 32)) return 1; // 1.3.0a + if (0 == memcmp(hash, "\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37", 32)) return 1; // 1.3.0b + if (0 == memcmp(hash, "\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15", 32)) return 1; // 1.3.1 + if (0 == memcmp(hash, "\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07", 32)) return 1; // 1.3.2 + if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 + if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 + return 0; +} + +void check_bootloader(void) +{ + uint8_t hash[32]; + int r = memory_bootloader_hash(hash); + + if (!known_bootloader(r, hash)) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unknown bootloader", "detected.", NULL, "Unplug your TREZOR", "contact our support.", NULL); + system_halt(); + } + + if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { + // all OK -> done + return; + } + + // unlock sectors + memory_write_unlock(); + + // replace bootloader + flash_unlock(); + for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + for (int i = 0; i < FLASH_BOOT_LEN / 4; i++) { + const uint32_t *w = (const uint32_t *)(bl_data + i * 4); + flash_program_word(FLASH_BOOT_START + i * 4, *w); + } + flash_lock(); + + // show info and halt + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); + system_halt(); +} diff --git a/firmware/bl_check.h b/firmware/bl_check.h new file mode 100644 index 0000000000..8ab070c52a --- /dev/null +++ b/firmware/bl_check.h @@ -0,0 +1,25 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __BL_CHECK_H__ +#define __BL_CHECK_H__ + +void check_bootloader(void); + +#endif diff --git a/firmware/bl_data-gen.py b/firmware/bl_data-gen.py new file mode 100755 index 0000000000..da25fa5a17 --- /dev/null +++ b/firmware/bl_data-gen.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +from hashlib import sha256 + +fn = '../bootloader/bootloader.bin' + +data = open(fn, 'rb').read() +if len(data) > 32768: + raise Exception('bootloader has to be smaller than 32768 bytes') + +data += b'\x00' * (32768 - len(data)) + +h = sha256(sha256(data).digest()).digest() + +bl_hash = ', '.join('0x%02x' % x for x in bytearray(h)) +bl_data = ', '.join('0x%02x' % x for x in bytearray(data)) + +with open('bl_data.h', 'wt') as f: + f.write('static const uint8_t bl_hash[32] = {%s};\n' % bl_hash) + f.write('static const uint8_t bl_data[32768] = {%s};\n' % bl_data) diff --git a/firmware/fastflash.c b/firmware/fastflash.c index 7d7d8600b9..e6b803b928 100644 --- a/firmware/fastflash.c +++ b/firmware/fastflash.c @@ -37,5 +37,5 @@ void __attribute__((noreturn)) run_bootloader(void) // copy bootloader memcpy(bootloader_vec, __bootloader_start__, (size_t) __bootloader_size__); - load_vector_table(bootloader_vec); + jump_to_firmware(bootloader_vec, FW_TRUSTED); } diff --git a/firmware/trezor.c b/firmware/trezor.c index 8c5d55a9a7..4491cd1f0b 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -30,6 +30,7 @@ #include "timer.h" #include "buttons.h" #include "gettext.h" +#include "bl_check.h" #include "fastflash.h" /* Screen timeout */ @@ -91,6 +92,7 @@ int main(void) __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks oledInit(); #else + check_bootloader(); setupApp(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif diff --git a/memory.c b/memory.c index da07841913..e2416159f4 100644 --- a/memory.c +++ b/memory.c @@ -49,7 +49,25 @@ void memory_protect(void) #endif } +// Remove write-protection on all flash sectors. +// +// This is an undocumented feature/bug of STM32F205/F405 microcontrollers, +// where flash controller reads its write protection bits from FLASH_OPTCR +// register not from OPTION_BYTES, rendering write protection useless. +// This behaviour is fixed in future designs of flash controller used for +// example in STM32F427, where the protection bits are read correctly +// from OPTION_BYTES and not form FLASH_OPCTR register. +// +// Read protection is unaffected and always stays locked to the desired value. +void memory_write_unlock(void) +{ + flash_unlock_option_bytes(); + flash_program_option_bytes(0x0FFFCCEC); + flash_lock_option_bytes(); +} + int memory_bootloader_hash(uint8_t *hash) + { sha256_Raw((const uint8_t *)FLASH_BOOT_START, FLASH_BOOT_LEN, hash); sha256_Raw(hash, 32, hash); diff --git a/memory.h b/memory.h index f6c4a87050..7a342a4f61 100644 --- a/memory.h +++ b/memory.h @@ -103,6 +103,7 @@ #define FLASH_CODE_SECTOR_LAST 7 void memory_protect(void); +void memory_write_unlock(void); int memory_bootloader_hash(uint8_t *hash); #endif diff --git a/util.h b/util.h index de3f9d5e0b..effa53b7af 100644 --- a/util.h +++ b/util.h @@ -21,6 +21,7 @@ #define __UTIL_H_ #include +#include #if !EMULATOR #include @@ -52,10 +53,16 @@ extern uint8_t _ram_start[], _ram_end[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); -static inline void __attribute__((noreturn)) load_vector_table(const vector_table_t *vector_table) +#define FW_SIGNED 0x5A3CA5C3 +#define FW_UNTRUSTED 0x00000000 + +static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table_t *vector_table, int trust) { - // Relocate vector table - SCB_VTOR = (uint32_t)vector_table; + if (FW_SIGNED == trust) { // trusted signed firmware + SCB_VTOR = (uint32_t)vector_table; // * relocate vector table + } else { // untrusted firmware + mpu_config(); // * configure MPU + } // Set stack pointer __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); From 95dd254094d6151121fba1933b09d35a7b2a4e62 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 19 Mar 2018 15:44:41 +0100 Subject: [PATCH 0776/1154] util: use shutdown from trezor-core instead of system_halt --- bootloader/bootloader.c | 2 +- firmware/storage.c | 2 +- startup.s | 24 ++++++++++++++++++++++++ util.c | 5 ----- util.h | 4 +--- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 185180bd82..6093fce329 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -46,7 +46,7 @@ void layoutFirmwareHash(const uint8_t *hash) void show_halt(void) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL); - system_halt(); + shutdown(); } void show_unofficial_warning(const uint8_t *hash) diff --git a/firmware/storage.c b/firmware/storage.c index 1fe9e9b846..27a16296a8 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -130,7 +130,7 @@ static char CONFIDENTIAL sessionPassphrase[51]; void storage_show_error(void) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); - system_halt(); + shutdown(); } void storage_check_flash_errors(void) diff --git a/startup.s b/startup.s index 58aec193bb..f2f29c074d 100644 --- a/startup.s +++ b/startup.s @@ -36,4 +36,28 @@ reset_handler: // loop forever if the application code returns b . + .global shutdown + .type shutdown, STT_FUNC +shutdown: + cpsid f + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + ldr lr, =0xffffffff + ldr r0, =_ram_start + ldr r1, =_ram_end + // set to value in r2 + bl memset_reg + b . // loop forever + .end diff --git a/util.c b/util.c index 197c45445b..768410c318 100644 --- a/util.c +++ b/util.c @@ -66,8 +66,3 @@ uint32_t readprotobufint(uint8_t **ptr) (*ptr)++; return result; } - -void __attribute__((noreturn)) system_halt(void) -{ - for (;;) {} // loop forever -} diff --git a/util.h b/util.h index effa53b7af..04fb637c2d 100644 --- a/util.h +++ b/util.h @@ -43,15 +43,13 @@ void data2hex(const void *data, uint32_t len, char *str); // read protobuf integer and advance pointer uint32_t readprotobufint(uint8_t **ptr); -// halt execution (or do an endless loop) -void __attribute__((noreturn)) system_halt(void); - #if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); +extern void __attribute__((noreturn)) shutdown(void); #define FW_SIGNED 0x5A3CA5C3 #define FW_UNTRUSTED 0x00000000 From ceced152a8f74bfcd53e277d937d8f14bc07180d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 21 Mar 2018 12:29:38 +0100 Subject: [PATCH 0777/1154] docs: update changelogs --- bootloader/ChangeLog | 11 +++++++++++ firmware/ChangeLog | 1 + 2 files changed, 12 insertions(+) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index 9bc863fed3..dc409aebdf 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,3 +1,14 @@ +Version 1.4.0 +* More flash-write tests +* Don't restore storage from unofficial firmware +* Support WipeDevice message +* Activate MPU and don't switch VTOR table for unofficial firmware + +Version 1.3.3 +* Add self-test +* Erase metadata backup after usage +* Erase SRAM on application start + Version 1.3.2 * Don't show recovery seed warning if firmware is flashed for the first time * Don't show fingerprint if firmware is flashed for the first time diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 5ca85f1a7d..98422c25d4 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -2,6 +2,7 @@ Version 1.6.1 * Stable release, optional update * Use fixed-width font for addresses * Lots of under-the-hood improvements +* Fixed issue with write-protection settings Version 1.6.0 * Stable release, optional update From 0220818b60abf31f0c2be3579262a873ace0548c Mon Sep 17 00:00:00 2001 From: slush0 Date: Thu, 22 Mar 2018 20:23:56 +0100 Subject: [PATCH 0778/1154] Fixed path to releases.json --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc8d47ea53..636151db0b 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ This creates file `build/bootloader-TAG.bin` and prints its fingerprint and size ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? -1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/releases.json +1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/1/releases.json 2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/trezor-1.3.6.bin` 3. Compute fingerprint: `tail -c +257 trezor.signed.bin | sha256sum` From 2a12764198622670b5182e7a66400185dc6d22cc Mon Sep 17 00:00:00 2001 From: slush0 Date: Thu, 22 Mar 2018 20:26:44 +0100 Subject: [PATCH 0779/1154] Updated path to firmware 1.6.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 636151db0b..8e8e1a8a64 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This creates file `build/bootloader-TAG.bin` and prints its fingerprint and size ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? 1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/1/releases.json -2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/trezor-1.3.6.bin` +2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/1/trezor-1.6.1.bin` 3. Compute fingerprint: `tail -c +257 trezor.signed.bin | sha256sum` Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag). Firmware has a special header (of length 256 bytes) holding signatures themselves, which must be avoided while calculating the fingerprint, that's why tail command has to be used. From 2f8ea9d5c765f1b8d21a3e2bfe36e2a2283a0bfd Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 23 Mar 2018 12:31:03 +0700 Subject: [PATCH 0780/1154] Fix building firmware in docker Fixes #320 --- build-firmware.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build-firmware.sh b/build-firmware.sh index 6543b7fc59..86ae83fe61 100755 --- a/build-firmware.sh +++ b/build-firmware.sh @@ -16,6 +16,7 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ make -C vendor/nanopb/generator/proto && \ make -C firmware/protob && \ make && \ + make -C bootloader && \ make -C firmware sign && \ cp firmware/trezor.bin /$BINFILE && \ cp firmware/trezor.elf /$ELFFILE" From c4e1c5953eceb6daf30eb7ac830e98b65e20b8a0 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 23:00:29 +0100 Subject: [PATCH 0781/1154] Fix shift overflow Avoid undefined behavior by casting uint8_t to uint32_t before shifting by 24 bits. --- bootloader/usb.c | 2 +- firmware/crypto.c | 2 +- firmware/fsm.c | 16 ++++++++-------- firmware/messages.c | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 4fbf088126..51bee89e79 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -334,7 +334,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } // struct.unpack(">HL") => msg, size msg_id = (buf[3] << 8) + buf[4]; - msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; + msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; } if (flash_state == STATE_READY || flash_state == STATE_OPEN) { diff --git a/firmware/crypto.c b/firmware/crypto.c index dae6c4fef4..349116bef9 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -82,7 +82,7 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) return 1 + 2; } if (in[0] == 254) { - *out = in[1] + (in[2] << 8) + (in[3] << 16) + (in[4] << 24); + *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t) in[4] << 24); return 1 + 4; } *out = 0; // ignore 64 bit diff --git a/firmware/fsm.c b/firmware/fsm.c index d6bcfc0ee0..592a35fc0c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1010,10 +1010,10 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint32_t address_n[5]; address_n[0] = 0x80000000 | 13; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); const char *curve = SECP256K1_NAME; if (msg->has_ecdsa_curve_name) { @@ -1086,10 +1086,10 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) uint32_t address_n[5]; address_n[0] = 0x80000000 | 17; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); const char *curve = SECP256K1_NAME; if (msg->has_ecdsa_curve_name) { diff --git a/firmware/messages.c b/firmware/messages.c index d290da7798..653ae7f417 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -259,7 +259,7 @@ void msg_read_common(char type, const uint8_t *buf, int len) return; } msg_id = (buf[3] << 8) + buf[4]; - msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + msg_size = ((uint32_t) buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; fields = MessageFields(type, 'i', msg_id); if (!fields) { // unknown message @@ -333,7 +333,7 @@ void msg_read_tiny(const uint8_t *buf, int len) return; } uint16_t msg_id = (buf[3] << 8) + buf[4]; - uint32_t msg_size = (buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; + uint32_t msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; if (msg_size > 64 || len - msg_size < 9) { return; } From a7158f39a5cd154856c90288ea8e8d7a13368852 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 23 Mar 2018 17:19:30 +0100 Subject: [PATCH 0782/1154] fix out-of-bounds read (for debug_link) Pinmatrix should always be null-terminated for debug-link. The memset overwrote the terminating nul character. --- firmware/pinmatrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index c3a5aac99c..e2234292a8 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -69,7 +69,7 @@ void pinmatrix_done(char *pin) } i++; } - memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm)); + memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm) - 1); } #if DEBUG_LINK From 4ebbe8c274f9d9435cc15058f1463a032ab1bb4d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 18:53:54 +0100 Subject: [PATCH 0783/1154] Fix compilation problems --- emulator/setup.c | 4 ++++ firmware/bl_check.c | 10 ++++++++-- script/cibuild | 1 + util.h | 3 ++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/emulator/setup.c b/emulator/setup.c index f994916d3e..2ea8f92193 100644 --- a/emulator/setup.c +++ b/emulator/setup.c @@ -48,6 +48,10 @@ void setup(void) { setup_flash(); } +void __attribute__((noreturn)) shutdown(void) { + for(;;); +} + void emulatorRandom(void *buffer, size_t size) { ssize_t n = read(urandom, buffer, size); if (n < 0 || ((size_t) n) != size) { diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 1e53497f2c..0d6b3bba09 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -47,7 +47,7 @@ void check_bootloader(void) if (!known_bootloader(r, hash)) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unknown bootloader", "detected.", NULL, "Unplug your TREZOR", "contact our support.", NULL); - system_halt(); + shutdown(); } if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { @@ -55,6 +55,11 @@ void check_bootloader(void) return; } +#if 0 + // ENABLE THIS AT YOUR OWN RISK + // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK + // YOUR DEVICE. + // unlock sectors memory_write_unlock(); @@ -71,5 +76,6 @@ void check_bootloader(void) // show info and halt layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); - system_halt(); + shutdown(); +#endif } diff --git a/script/cibuild b/script/cibuild index 023969661f..b8dc112261 100755 --- a/script/cibuild +++ b/script/cibuild @@ -19,6 +19,7 @@ if [ "$FASTFLASH" = 1 ]; then make -C fastflash fi +make -C bootloader make -C vendor/nanopb/generator/proto make -C firmware/protob diff --git a/util.h b/util.h index 04fb637c2d..8b6a9f2eb0 100644 --- a/util.h +++ b/util.h @@ -43,13 +43,14 @@ void data2hex(const void *data, uint32_t len, char *str); // read protobuf integer and advance pointer uint32_t readprotobufint(uint8_t **ptr); +extern void __attribute__((noreturn)) shutdown(void); + #if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); -extern void __attribute__((noreturn)) shutdown(void); #define FW_SIGNED 0x5A3CA5C3 #define FW_UNTRUSTED 0x00000000 From 2587e49843738c0a4b69abe16c42849e7eed4bf1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 23 Mar 2018 13:10:04 +0100 Subject: [PATCH 0784/1154] Disable fastflash. It doesn't make sense any more and doesn't work with newer bootloaders. --- .travis.yml | 6 ++---- fastflash/Makefile | 22 ---------------------- fastflash/bootloader.c | 1 - fastflash/signatures.c | 28 ---------------------------- fastflash/usb.c | 1 - firmware/Makefile | 18 ------------------ firmware/fastflash.c | 41 ----------------------------------------- firmware/fastflash.h | 25 ------------------------- firmware/trezor.c | 8 -------- script/cibuild | 5 ----- 10 files changed, 2 insertions(+), 153 deletions(-) delete mode 100644 fastflash/Makefile delete mode 120000 fastflash/bootloader.c delete mode 100644 fastflash/signatures.c delete mode 120000 fastflash/usb.c delete mode 100644 firmware/fastflash.c delete mode 100644 firmware/fastflash.h diff --git a/.travis.yml b/.travis.yml index 89fd55befa..374b6f701e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,8 @@ env: - PYTHON=python3 - PROTOBUF_VERSION=3.4.0 matrix: - - DEBUG_LINK=0 FASTFLASH=0 - - DEBUG_LINK=1 FASTFLASH=0 - - DEBUG_LINK=0 FASTFLASH=1 - - DEBUG_LINK=1 FASTFLASH=1 + - DEBUG_LINK=0 + - DEBUG_LINK=1 matrix: include: diff --git a/fastflash/Makefile b/fastflash/Makefile deleted file mode 100644 index 5b768eb49c..0000000000 --- a/fastflash/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -APPVER = fastflash - -NAME = bootloader - -OBJS += bootloader.o -OBJS += signatures.o -OBJS += usb.o - -OBJS += ../vendor/trezor-crypto/bignum.small.o -OBJS += ../vendor/trezor-crypto/ecdsa.small.o -OBJS += ../vendor/trezor-crypto/secp256k1.small.o -OBJS += ../vendor/trezor-crypto/sha2.small.o -OBJS += ../vendor/trezor-crypto/memzero.small.o - -CFLAGS += -DUSE_PRECOMPUTED_IV=0 -CFLAGS += -DUSE_PRECOMPUTED_CP=0 - -OPTFLAGS ?= -Os - -include ../Makefile.include - -CFLAGS += -I../bootloader diff --git a/fastflash/bootloader.c b/fastflash/bootloader.c deleted file mode 120000 index 3c60d798d4..0000000000 --- a/fastflash/bootloader.c +++ /dev/null @@ -1 +0,0 @@ -../bootloader/bootloader.c \ No newline at end of file diff --git a/fastflash/signatures.c b/fastflash/signatures.c deleted file mode 100644 index 556dd6a946..0000000000 --- a/fastflash/signatures.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2017 Saleem Rashid - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include -#include - -int signatures_ok(uint8_t *store_hash) -{ - (void) store_hash; - - return false; -} diff --git a/fastflash/usb.c b/fastflash/usb.c deleted file mode 120000 index 13b2a33e6b..0000000000 --- a/fastflash/usb.c +++ /dev/null @@ -1 +0,0 @@ -../bootloader/usb.c \ No newline at end of file diff --git a/firmware/Makefile b/firmware/Makefile index 915435363d..2e5b329333 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,10 +1,5 @@ APPVER = 1.0.0 -ifeq ($(FASTFLASH),1) -OBJS += fastflash.o -OBJS += bootloader.o -endif - NAME = trezor ifeq ($(EMULATOR),1) @@ -87,12 +82,6 @@ OBJS += protob/types.pb.o include ../Makefile.include -ifeq ($(FASTFLASH),1) -CFLAGS += -DFASTFLASH=1 -else -CFLAGS += -DFASTFLASH=0 -endif - DEBUG_LINK ?= 0 DEBUG_LOG ?= 0 @@ -105,13 +94,6 @@ CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')" CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_NEM=1 -bootloader.o: ../fastflash/bootloader.bin - $(OBJCOPY) -I binary -O elf32-littlearm -B arm \ - --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_start=__bootloader_start__ \ - --redefine-sym _binary_$(shell echo -n "$<" | tr -c "[:alnum:]" "_")_size=__bootloader_size__ \ - --rename-section .data=.rodata \ - $< $@ - coins_count.h: coins-gen.py coins.json $(PYTHON) $< count > $@ diff --git a/firmware/fastflash.c b/firmware/fastflash.c deleted file mode 100644 index e6b803b928..0000000000 --- a/firmware/fastflash.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2017 Saleem Rashid - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include "fastflash.h" -#include "util.h" - -#include -#include -#include - -#define bootloader_vec ((vector_table_t *) 0x20000000) - -void __attribute__((noreturn)) run_bootloader(void) -{ - extern uint8_t __bootloader_start__[]; - extern uint8_t __bootloader_size__[]; - - // zero out SRAM - memset_reg(_ram_start, _ram_end, 0); - - // copy bootloader - memcpy(bootloader_vec, __bootloader_start__, (size_t) __bootloader_size__); - - jump_to_firmware(bootloader_vec, FW_TRUSTED); -} diff --git a/firmware/fastflash.h b/firmware/fastflash.h deleted file mode 100644 index fe8bc05a9a..0000000000 --- a/firmware/fastflash.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2017 Saleem Rashid - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#ifndef __FASTFLASH_H__ -#define __FASTFLASH_H__ - -void __attribute__((noreturn)) run_bootloader(void); - -#endif diff --git a/firmware/trezor.c b/firmware/trezor.c index 4491cd1f0b..7a008d20b8 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -31,7 +31,6 @@ #include "buttons.h" #include "gettext.h" #include "bl_check.h" -#include "fastflash.h" /* Screen timeout */ uint32_t system_millis_lock_start; @@ -97,13 +96,6 @@ int main(void) __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif -#if FASTFLASH - uint16_t state = gpio_port_read(BTN_PORT); - if ((state & BTN_PIN_NO) == 0) { - run_bootloader(); - } -#endif - timer_init(); #ifdef APPVER diff --git a/script/cibuild b/script/cibuild index b8dc112261..a4f0b07f22 100755 --- a/script/cibuild +++ b/script/cibuild @@ -14,11 +14,6 @@ else fi make - -if [ "$FASTFLASH" = 1 ]; then - make -C fastflash -fi - make -C bootloader make -C vendor/nanopb/generator/proto make -C firmware/protob From 39ea33523dafe44b8a7abfe05599b4aa3ffcf845 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 24 Mar 2018 20:56:07 +0100 Subject: [PATCH 0785/1154] Don't hog CPU on shutdown --- emulator/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulator/setup.c b/emulator/setup.c index 2ea8f92193..b5effa83ce 100644 --- a/emulator/setup.c +++ b/emulator/setup.c @@ -49,7 +49,7 @@ void setup(void) { } void __attribute__((noreturn)) shutdown(void) { - for(;;); + for(;;) pause(); } void emulatorRandom(void *buffer, size_t size) { From 1fcd512b7ff70fb4166e8b26befc4362c7cd62d2 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 18:53:54 +0100 Subject: [PATCH 0786/1154] Fix compilation problems --- script/cibuild | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index a4f0b07f22..098deb8c0f 100755 --- a/script/cibuild +++ b/script/cibuild @@ -14,7 +14,9 @@ else fi make -make -C bootloader +if [ "$EMULATOR" != 1 ]; then + make -C bootloader +fi make -C vendor/nanopb/generator/proto make -C firmware/protob From c09590b54d287dd1755aabd193b6d90dd062cc41 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 15 Mar 2018 19:00:54 +0100 Subject: [PATCH 0787/1154] Cleaner flash handling using FLASH_PTR Use `FLASH_PTR` macro to convert a flash address to a const pointer. For real hardware it is just a cast, for emulator we subtract the `FLASH_ORIGIN` and use it as index into the memory mapped flash file. Make write access to flash with volatile pointers Also use FLASH_PTR in DebugMemory* for now. This allows for reading and writing the flash in the emulator or just crash it by reading outside the flash... --- Makefile.include | 2 +- bootloader/bootloader.c | 8 ++--- bootloader/usb.c | 10 +++--- emulator/emulator.h | 2 -- emulator/flash.c | 8 ++--- emulator/setup.c | 2 +- firmware/fsm.c | 4 ++- firmware/protect.c | 7 ++-- firmware/storage.c | 77 +++++++++++++++++------------------------ firmware/storage.h | 6 ++-- memory.c | 2 +- memory.h | 11 ++++-- 12 files changed, 64 insertions(+), 75 deletions(-) diff --git a/Makefile.include b/Makefile.include index c9e8fd578f..d257bd329a 100644 --- a/Makefile.include +++ b/Makefile.include @@ -13,7 +13,7 @@ AS := as OPTFLAGS ?= -O3 DBGFLAGS ?= -g3 -ggdb3 -CPUFLAGS ?= -m32 +CPUFLAGS ?= FPUFLAGS ?= else PREFIX ?= arm-none-eabi- diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 6093fce329..b47fedae88 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -81,19 +81,19 @@ void __attribute__((noreturn)) load_app(int signed_firmware) // zero out SRAM memset_reg(_ram_start, _ram_end, 0); - jump_to_firmware((const vector_table_t *) FLASH_APP_START, signed_firmware); + jump_to_firmware((const vector_table_t *) FLASH_PTR(FLASH_APP_START), signed_firmware); } bool firmware_present(void) { #ifndef APPVER - if (memcmp((const void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match + if (memcmp(FLASH_PTR(FLASH_META_MAGIC), "TRZR", 4)) { // magic does not match return false; } - if (*((const uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 4096) { // firmware reports smaller size than 4kB return false; } - if (*((const uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size return false; } #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 51bee89e79..ec69a818bc 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -302,7 +302,7 @@ static void erase_metadata_sectors(void) static void backup_metadata(uint8_t *backup) { - memcpy(backup, (void *)FLASH_META_START, FLASH_META_LEN); + memcpy(backup, FLASH_PTR(FLASH_META_START), FLASH_META_LEN); } static void restore_metadata(const uint8_t *backup) @@ -434,7 +434,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // compute hash of written test pattern uint8_t hash[32]; - sha256_Raw((unsigned char *)FLASH_META_START, FLASH_META_LEN, hash); + sha256_Raw(FLASH_PTR(FLASH_META_START), FLASH_META_LEN, hash); // restore metadata from backup erase_metadata_sectors(); @@ -504,7 +504,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) // flash status register should show now error and // the config block should contain only \xff. uint8_t hash[32]; - sha256_Raw((unsigned char *)FLASH_META_START, FLASH_META_LEN, hash); + sha256_Raw(FLASH_PTR(FLASH_META_START), FLASH_META_LEN, hash); if ((FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) != 0 || memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { send_msg_failure(dev); @@ -619,7 +619,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) return; } uint8_t hash[32]; - sha256_Raw((unsigned char *)FLASH_APP_START, flash_len - FLASH_META_DESC_LEN, hash); + sha256_Raw(FLASH_PTR(FLASH_APP_START), flash_len - FLASH_META_DESC_LEN, hash); layoutFirmwareHash(hash); do { delay(100000); @@ -630,7 +630,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) bool hash_check_ok = brand_new_firmware || button.YesUp; layoutProgress("INSTALLING ... Please wait", 1000); - uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); + uint8_t flags = *FLASH_PTR(FLASH_META_FLAGS); // wipe storage if: // 0) there was no firmware // 1) old firmware was unsigned diff --git a/emulator/emulator.h b/emulator/emulator.h index deaa73dea4..abb41355a9 100644 --- a/emulator/emulator.h +++ b/emulator/emulator.h @@ -26,8 +26,6 @@ #include -extern void *emulator_flash_base; - void emulatorPoll(void); void emulatorRandom(void *buffer, size_t size); diff --git a/emulator/flash.c b/emulator/flash.c index 708dd25981..b168d86bb1 100644 --- a/emulator/flash.c +++ b/emulator/flash.c @@ -17,8 +17,6 @@ * along with this library. If not, see . */ -#include - #include #include "memory.h" @@ -66,7 +64,7 @@ static void *sector_to_address(uint8_t sector) { return NULL; } - return (void *) (FLASH_ORIGIN + offset); + return (void *) FLASH_PTR(FLASH_ORIGIN + offset); } static ssize_t sector_to_size(uint8_t sector) { @@ -106,9 +104,9 @@ void flash_erase_all_sectors(uint32_t program_size) { } void flash_program_word(uint32_t address, uint32_t data) { - MMIO32(address) = data; + *(volatile uint32_t *)FLASH_PTR(address) = data; } void flash_program_byte(uint32_t address, uint8_t data) { - MMIO8(address) = data; + *(volatile uint8_t *)FLASH_PTR(address) = data; } diff --git a/emulator/setup.c b/emulator/setup.c index b5effa83ce..8000aa4ea9 100644 --- a/emulator/setup.c +++ b/emulator/setup.c @@ -34,7 +34,7 @@ #define EMULATOR_FLASH_FILE "emulator.img" -void *emulator_flash_base = NULL; +uint8_t *emulator_flash_base = NULL; uint32_t __stack_chk_guard; diff --git a/firmware/fsm.c b/firmware/fsm.c index 592a35fc0c..698106ccef 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1678,7 +1678,7 @@ void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) if (msg->has_length && msg->length < length) length = msg->length; resp->has_memory = true; - memcpy(resp->memory.bytes, (void*) msg->address, length); + memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); resp->memory.size = length; msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); } @@ -1696,7 +1696,9 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) } flash_lock(); } else { +#if !EMULATOR memcpy((void *) msg->address, msg->memory.bytes, length); +#endif } } diff --git a/firmware/protect.c b/firmware/protect.c index ffbe4aa391..d0ef4a8ffe 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -19,6 +19,7 @@ #include "protect.h" #include "storage.h" +#include "memory.h" #include "messages.h" #include "usb.h" #include "oled.h" @@ -159,8 +160,8 @@ bool protectPin(bool use_cached) if (!storage_hasPin() || (use_cached && session_isPinCached())) { return true; } - uint32_t *fails = storage_getPinFailsPtr(); - uint32_t wait = ~*fails; + uint32_t fails = storage_getPinFailsOffset(); + uint32_t wait = ~*(const uint32_t*)FLASH_PTR(fails); protectCheckMaxTry(wait); usbTiny(1); while (wait > 0) { @@ -205,7 +206,7 @@ bool protectPin(bool use_cached) storage_resetPinFails(fails); return true; } else { - protectCheckMaxTry(~*fails); + protectCheckMaxTry(~*(const uint32_t*)FLASH_PTR(fails)); fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); return false; } diff --git a/firmware/storage.c b/firmware/storage.c index 27a16296a8..2167b8a407 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -48,27 +48,13 @@ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t static uint32_t storage_uuid[12 / sizeof(uint32_t)]; -#ifndef __clang__ -// TODO: Fix this for Clang -_Static_assert(((uint32_t)storage_uuid & 3) == 0, "uuid unaligned"); -_Static_assert((sizeof(storage_uuid) & 3) == 0, "uuid unaligned"); -#endif +_Static_assert(sizeof(storage_uuid) == 12, "storage_uuid has wrong size"); -Storage CONFIDENTIAL storageUpdate; -#ifndef __clang__ -// TODO: Fix this for Clang -_Static_assert(((uint32_t)&storageUpdate & 3) == 0, "storage unaligned"); +Storage CONFIDENTIAL storageUpdate __attribute__((aligned(4))); _Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); -#endif -#define STORAGE_ROM ((const Storage *)(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid))) - -#if EMULATOR -// TODO: Fix this for emulator -#define storageRom STORAGE_ROM -#else -const Storage *storageRom = STORAGE_ROM; -#endif +#define FLASH_STORAGE (FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid)) +#define storageRom ((const Storage *) FLASH_PTR(FLASH_STORAGE)) char storage_uuid_str[25]; @@ -146,7 +132,7 @@ void storage_check_flash_errors(void) bool storage_from_flash(void) { storage_clear_update(); - if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, sizeof(storage_magic)) != 0) { + if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &storage_magic, sizeof(storage_magic)) != 0) { // wrong magic return false; } @@ -167,7 +153,7 @@ bool storage_from_flash(void) } // load uuid - memcpy(storage_uuid, (void *)(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); + memcpy(storage_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) @@ -215,20 +201,17 @@ bool storage_from_flash(void) flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts -#if !EMULATOR -// TODO: Fix this for emulator - _Static_assert(((uint32_t)&STORAGE_ROM->pin_failed_attempts & 3) == 0, "storage.pin_failed_attempts unaligned"); -#endif - flash_program_byte((uint32_t)&storageRom->has_pin_failed_attempts, 0); - flash_program_word((uint32_t)&storageRom->pin_failed_attempts, 0); + _Static_assert(((FLASH_STORAGE + offsetof(Storage, pin_failed_attempts)) & 3) == 0, "storage.pin_failed_attempts unaligned"); + flash_program_byte(FLASH_STORAGE + offsetof(Storage, has_pin_failed_attempts), 0); + flash_program_word(FLASH_STORAGE + offsetof(Storage, pin_failed_attempts), 0); flash_lock(); storage_check_flash_errors(); } - uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA; + const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); while (*u2fptr == 0) { u2fptr++; } - storage_u2f_offset = 32 * (u2fptr - (uint32_t*) FLASH_STORAGE_U2FAREA); + storage_u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); uint32_t u2fword = *u2fptr; while ((u2fword & 1) == 0) { storage_u2f_offset++; @@ -374,7 +357,7 @@ static void storage_commit_locked(bool update) // backup meta uint32_t meta_backup[FLASH_META_DESC_LEN / sizeof(uint32_t)]; - memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN); + memcpy(meta_backup, FLASH_PTR(FLASH_META_START), FLASH_META_DESC_LEN); // erase storage flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); @@ -763,14 +746,14 @@ static void storage_area_recycle(uint32_t new_pinfails) // first clear storage marker. In case of a failure below it is better // to clear the storage than to allow restarting with zero PIN failures flash_program_word(FLASH_STORAGE_START, 0); - if (*(uint32_t *)FLASH_STORAGE_START != 0) { + if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_START) != 0) { storage_show_error(); } // erase storage sector flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails); - if (*(uint32_t *)FLASH_STORAGE_PINAREA != new_pinfails) { + if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_PINAREA) != new_pinfails) { storage_show_error(); } @@ -782,24 +765,24 @@ static void storage_area_recycle(uint32_t new_pinfails) } } -void storage_resetPinFails(uint32_t *pinfailsptr) +void storage_resetPinFails(uint32_t flash_pinfails) { flash_clear_status_flags(); flash_unlock(); - if ((uint32_t) (pinfailsptr + 1) + if (flash_pinfails + sizeof(uint32_t) >= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) { // recycle extra storage sector storage_area_recycle(0xffffffff); } else { - flash_program_word((uint32_t) pinfailsptr, 0); + flash_program_word(flash_pinfails, 0); } flash_lock(); storage_check_flash_errors(); } -bool storage_increasePinFails(uint32_t *pinfailsptr) +bool storage_increasePinFails(uint32_t flash_pinfails) { - uint32_t newctr = *pinfailsptr << 1; + uint32_t newctr = *(const uint32_t*)FLASH_PTR(flash_pinfails) << 1; // counter already at maximum, we do not increase it any more // return success so that a good pin is accepted if (!newctr) @@ -807,19 +790,19 @@ bool storage_increasePinFails(uint32_t *pinfailsptr) flash_clear_status_flags(); flash_unlock(); - flash_program_word((uint32_t) pinfailsptr, newctr); + flash_program_word(flash_pinfails, newctr); flash_lock(); storage_check_flash_errors(); - return *pinfailsptr == newctr; + return *(const uint32_t*)FLASH_PTR(flash_pinfails) == newctr; } -uint32_t *storage_getPinFailsPtr(void) +uint32_t storage_getPinFailsOffset(void) { - uint32_t *pinfailsptr = (uint32_t *) FLASH_STORAGE_PINAREA; - while (*pinfailsptr == 0) - pinfailsptr++; - return pinfailsptr; + uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; + while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) + flash_pinfails += sizeof(uint32_t); + return flash_pinfails; } bool storage_isInitialized(void) @@ -866,15 +849,17 @@ uint32_t storage_getFlags(void) uint32_t storage_nextU2FCounter(void) { - uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32); + uint32_t flash_u2f_offset = FLASH_STORAGE_U2FAREA + + sizeof(uint32_t) * (storage_u2f_offset / 32); uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31); flash_clear_status_flags(); flash_unlock(); - flash_program_word((uint32_t) ptr, newval); + flash_program_word(flash_u2f_offset, newval); storage_u2f_offset++; if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) { - storage_area_recycle(*storage_getPinFailsPtr()); + storage_area_recycle(*(const uint32_t*) + FLASH_PTR(storage_getPinFailsOffset())); } flash_lock(); storage_check_flash_errors(); diff --git a/firmware/storage.h b/firmware/storage.h index 431e830c6c..945ca135c8 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -122,9 +122,9 @@ void storage_setPin(const char *pin); void session_cachePin(void); bool session_isPinCached(void); void storage_clearPinArea(void); -void storage_resetPinFails(uint32_t *pinfailptr); -bool storage_increasePinFails(uint32_t *pinfailptr); -uint32_t *storage_getPinFailsPtr(void); +void storage_resetPinFails(uint32_t flash_pinfails); +bool storage_increasePinFails(uint32_t flash_pinfails); +uint32_t storage_getPinFailsOffset(void); uint32_t storage_nextU2FCounter(void); void storage_setU2FCounter(uint32_t u2fcounter); diff --git a/memory.c b/memory.c index e2416159f4..1d68a3a2a7 100644 --- a/memory.c +++ b/memory.c @@ -69,7 +69,7 @@ void memory_write_unlock(void) int memory_bootloader_hash(uint8_t *hash) { - sha256_Raw((const uint8_t *)FLASH_BOOT_START, FLASH_BOOT_LEN, hash); + sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash); sha256_Raw(hash, 32, hash); return 32; } diff --git a/memory.h b/memory.h index 7a342a4f61..8bb9aac277 100644 --- a/memory.h +++ b/memory.h @@ -20,6 +20,8 @@ #ifndef __MEMORY_H__ #define __MEMORY_H__ +#include + /* flash memory layout: @@ -62,10 +64,13 @@ */ -#if EMULATOR -#define FLASH_ORIGIN ((uint32_t) emulator_flash_base) -#else #define FLASH_ORIGIN (0x08000000) + +#if EMULATOR +extern uint8_t *emulator_flash_base; +#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) +#else +#define FLASH_PTR(x) (const uint8_t*) (x) #endif #define FLASH_TOTAL_SIZE (512 * 1024) From 0127c1a374b9792f026ebd3313a20db2ec1774d9 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 20:12:01 +0100 Subject: [PATCH 0788/1154] Add function storage_getPinWait --- firmware/protect.c | 4 ++-- firmware/storage.c | 7 +++++++ firmware/storage.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index d0ef4a8ffe..713881e397 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -161,7 +161,7 @@ bool protectPin(bool use_cached) return true; } uint32_t fails = storage_getPinFailsOffset(); - uint32_t wait = ~*(const uint32_t*)FLASH_PTR(fails); + uint32_t wait = storage_getPinWait(fails); protectCheckMaxTry(wait); usbTiny(1); while (wait > 0) { @@ -206,7 +206,7 @@ bool protectPin(bool use_cached) storage_resetPinFails(fails); return true; } else { - protectCheckMaxTry(~*(const uint32_t*)FLASH_PTR(fails)); + protectCheckMaxTry(storage_getPinWait(fails)); fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); return false; } diff --git a/firmware/storage.c b/firmware/storage.c index 2167b8a407..bfa7467adb 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -797,6 +797,13 @@ bool storage_increasePinFails(uint32_t flash_pinfails) return *(const uint32_t*)FLASH_PTR(flash_pinfails) == newctr; } +uint32_t storage_getPinWait(uint32_t flash_pinfails) +{ + // The pin failure word is the inverted wait time in seconds. + // It's inverted because flash allows changing 1 to 0 but not vice versa. + return ~*(const uint32_t*)FLASH_PTR(flash_pinfails); +} + uint32_t storage_getPinFailsOffset(void) { uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; diff --git a/firmware/storage.h b/firmware/storage.h index 945ca135c8..3a8a16ebc6 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -124,6 +124,7 @@ bool session_isPinCached(void); void storage_clearPinArea(void); void storage_resetPinFails(uint32_t flash_pinfails); bool storage_increasePinFails(uint32_t flash_pinfails); +uint32_t storage_getPinWait(uint32_t flash_pinfails); uint32_t storage_getPinFailsOffset(void); uint32_t storage_nextU2FCounter(void); From 068f013bc6cc34400480f6d97258b88148810b8d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 22 Mar 2018 23:04:13 +0100 Subject: [PATCH 0789/1154] Force size fields in storage to be 32 bit Better storage compatibility between 64 bit and 32 bit builds. --- firmware/storage.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/storage.h b/firmware/storage.h index 3a8a16ebc6..8e19153540 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -35,7 +35,7 @@ #define STORAGE_BYTES(NAME, SIZE) \ bool has_##NAME; \ struct { \ - size_t size; \ + uint32_t size; \ uint8_t bytes[SIZE]; \ } NAME; @@ -48,7 +48,7 @@ typedef struct { uint32_t fingerprint; uint32_t child_num; struct { - size_t size; + uint32_t size; uint8_t bytes[32]; } chain_code; From 25e824aaa3c6b91b48ccc6ea7dbf310b6d73cf31 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 16 Mar 2018 21:40:39 +0100 Subject: [PATCH 0790/1154] Supervisor Calls Add Supervise interrupts to allow to do privileged operations like flashing from application code. --- Makefile | 1 + firmware/fsm.c | 16 +++---- firmware/storage.c | 107 ++++++++++++++++++++------------------------- startup.s | 12 +++++ supervise.c | 88 +++++++++++++++++++++++++++++++++++++ supervise.h | 77 ++++++++++++++++++++++++++++++++ timer.h | 8 +--- 7 files changed, 236 insertions(+), 73 deletions(-) create mode 100644 supervise.c create mode 100644 supervise.h diff --git a/Makefile b/Makefile index 81d418d9d1..f77970f549 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ endif OBJS += util.o OBJS += memory.o +OBJS += supervise.o ifneq ($(EMULATOR),1) OBJS += timer.o diff --git a/firmware/fsm.c b/firmware/fsm.c index 698106ccef..4ad2892158 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -55,6 +55,7 @@ #include "nem2.h" #include "rfc6979.h" #include "gettext.h" +#include "supervise.h" // message methods @@ -1687,14 +1688,14 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) { uint32_t length = msg->memory.size; if (msg->flash) { - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); for (uint32_t i = 0; i < length; i += 4) { uint32_t word; memcpy(&word, msg->memory.bytes + i, 4); - flash_program_word(msg->address + i, word); + flash_write32(msg->address + i, word); } - flash_lock(); + svc_flash_lock(); } else { #if !EMULATOR memcpy((void *) msg->address, msg->memory.bytes, length); @@ -1704,9 +1705,8 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) { - flash_clear_status_flags(); - flash_unlock(); - flash_erase_sector(msg->sector, FLASH_CR_PROGRAM_X32); - flash_lock(); + svc_flash_unlock(); + svc_flash_erase_sector(msg->sector); + svc_flash_lock(); } #endif diff --git a/firmware/storage.c b/firmware/storage.c index bfa7467adb..36b466c545 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -43,6 +43,7 @@ #include "gettext.h" #include "u2f.h" #include "memzero.h" +#include "supervise.h" /* magic constant to check validity of storage block */ static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t @@ -119,11 +120,11 @@ void storage_show_error(void) shutdown(); } -void storage_check_flash_errors(void) +void storage_check_flash_errors(uint32_t status) { #if !EMULATOR // flash operation failed - if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { + if (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { storage_show_error(); } #endif @@ -180,13 +181,12 @@ bool storage_from_flash(void) // erase newly added fields if (old_storage_size != sizeof(Storage)) { - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); for (uint32_t offset = old_storage_size; offset < sizeof(Storage); offset += sizeof(uint32_t)) { - flash_program_word(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid) + offset, 0); + flash_write32(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid) + offset, 0); } - flash_lock(); - storage_check_flash_errors(); + storage_check_flash_errors(svc_flash_lock()); } if (version <= 5) { @@ -195,17 +195,14 @@ bool storage_from_flash(void) if (pinctr > 31) { pinctr = 31; } - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); // erase extra storage sector - flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); - flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); - // erase storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts - _Static_assert(((FLASH_STORAGE + offsetof(Storage, pin_failed_attempts)) & 3) == 0, "storage.pin_failed_attempts unaligned"); - flash_program_byte(FLASH_STORAGE + offsetof(Storage, has_pin_failed_attempts), 0); - flash_program_word(FLASH_STORAGE + offsetof(Storage, pin_failed_attempts), 0); - flash_lock(); - storage_check_flash_errors(); + svc_flash_erase_sector(FLASH_META_SECTOR_LAST); + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); + // storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts + // are erased by storage_update below + storage_check_flash_errors(svc_flash_lock()); } const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); while (*u2fptr == 0) { @@ -257,7 +254,7 @@ void session_clear(bool clear_pin) static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwords) { for (int i = 0; i < nwords; i++) { - flash_program_word(addr, *src++); + flash_write32(addr, *src++); addr += sizeof(uint32_t); } return addr; @@ -360,7 +357,8 @@ static void storage_commit_locked(bool update) memcpy(meta_backup, FLASH_PTR(FLASH_META_START), FLASH_META_DESC_LEN); // erase storage - flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32); + svc_flash_erase_sector(FLASH_META_SECTOR_FIRST); + svc_flash_program(FLASH_CR_PROGRAM_X32); // copy meta back uint32_t flash = FLASH_META_START; @@ -377,7 +375,7 @@ static void storage_commit_locked(bool update) // fill remainder with zero for future extensions while (flash < FLASH_STORAGE_PINAREA) { - flash_program_word(flash, 0); + flash_write32(flash, 0); flash += sizeof(uint32_t); } } @@ -389,11 +387,9 @@ void storage_clear_update(void) void storage_update(void) { - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); storage_commit_locked(true); - flash_lock(); - storage_check_flash_errors(); + storage_check_flash_errors(svc_flash_lock()); } static void storage_setNode(const HDNodeType *node) { @@ -732,11 +728,9 @@ bool session_isPinCached(void) void storage_clearPinArea(void) { - flash_clear_status_flags(); - flash_unlock(); - flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); - flash_lock(); - storage_check_flash_errors(); + svc_flash_unlock(); + svc_flash_erase_sector(FLASH_META_SECTOR_LAST); + storage_check_flash_errors(svc_flash_lock()); storage_u2f_offset = 0; } @@ -745,39 +739,38 @@ static void storage_area_recycle(uint32_t new_pinfails) { // first clear storage marker. In case of a failure below it is better // to clear the storage than to allow restarting with zero PIN failures - flash_program_word(FLASH_STORAGE_START, 0); + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(FLASH_STORAGE_START, 0); if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_START) != 0) { storage_show_error(); } - // erase storage sector - flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32); - flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails); - if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_PINAREA) != new_pinfails) { + // erase pinarea/u2f sector + svc_flash_erase_sector(FLASH_META_SECTOR_LAST); + flash_write32(FLASH_STORAGE_PINAREA, new_pinfails); + if (*(const volatile uint32_t *)FLASH_PTR(FLASH_STORAGE_PINAREA) != new_pinfails) { storage_show_error(); } - if (storage_u2f_offset > 0) { - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter += storage_u2f_offset; - storage_u2f_offset = 0; - storage_commit_locked(true); - } + // restore storage sector + storageUpdate.has_u2f_counter = true; + storageUpdate.u2f_counter += storage_u2f_offset; + storage_u2f_offset = 0; + storage_commit_locked(true); } void storage_resetPinFails(uint32_t flash_pinfails) { - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); if (flash_pinfails + sizeof(uint32_t) >= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) { // recycle extra storage sector storage_area_recycle(0xffffffff); } else { - flash_program_word(flash_pinfails, 0); + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(flash_pinfails, 0); } - flash_lock(); - storage_check_flash_errors(); + storage_check_flash_errors(svc_flash_lock()); } bool storage_increasePinFails(uint32_t flash_pinfails) @@ -788,11 +781,10 @@ bool storage_increasePinFails(uint32_t flash_pinfails) if (!newctr) return true; - flash_clear_status_flags(); - flash_unlock(); - flash_program_word(flash_pinfails, newctr); - flash_lock(); - storage_check_flash_errors(); + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(flash_pinfails, newctr); + storage_check_flash_errors(svc_flash_lock()); return *(const uint32_t*)FLASH_PTR(flash_pinfails) == newctr; } @@ -860,16 +852,15 @@ uint32_t storage_nextU2FCounter(void) sizeof(uint32_t) * (storage_u2f_offset / 32); uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31); - flash_clear_status_flags(); - flash_unlock(); - flash_program_word(flash_u2f_offset, newval); + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(flash_u2f_offset, newval); storage_u2f_offset++; if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) { storage_area_recycle(*(const uint32_t*) FLASH_PTR(storage_getPinFailsOffset())); } - flash_lock(); - storage_check_flash_errors(); + storage_check_flash_errors(svc_flash_lock()); return storageRom->u2f_counter + storage_u2f_offset; } @@ -884,11 +875,9 @@ void storage_wipe(void) session_clear(true); storage_generate_uuid(); - flash_clear_status_flags(); - flash_unlock(); + svc_flash_unlock(); storage_commit_locked(false); - flash_lock(); - storage_check_flash_errors(); + storage_check_flash_errors(svc_flash_lock()); storage_clearPinArea(); } diff --git a/startup.s b/startup.s index f2f29c074d..5cd3d02608 100644 --- a/startup.s +++ b/startup.s @@ -60,4 +60,16 @@ shutdown: bl memset_reg b . // loop forever + .ltorg // dump literal pool (for the ldr ...,=... commands above) + + .global sv_call_handler + .type sv_call_handler, STT_FUNC + +sv_call_handler: + tst lr, #4 + ite eq + mrseq r0, msp + mrsne r0, psp + b svc_handler_main + .end diff --git a/supervise.c b/supervise.c new file mode 100644 index 0000000000..840d29d356 --- /dev/null +++ b/supervise.c @@ -0,0 +1,88 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include "supervise.h" +#include "memory.h" + +static void svhandler_flash_unlock(void) { + flash_clear_status_flags(); + flash_unlock(); +} + +static void svhandler_flash_program(uint32_t psize) { + /* Wait for any write operation to complete. */ + flash_wait_for_last_operation(); + /* check program size argument */ + if (psize != FLASH_CR_PROGRAM_X8 + && psize != FLASH_CR_PROGRAM_X16 + && psize != FLASH_CR_PROGRAM_X32 + && psize != FLASH_CR_PROGRAM_X64) + return; + FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) + | (psize << FLASH_CR_PROGRAM_SHIFT); + FLASH_CR |= FLASH_CR_PG; +} + +static void svhandler_flash_erase_sector(uint16_t sector) { + /* we only allow erasing meta sectors 2 and 3. */ + if (sector < FLASH_META_SECTOR_FIRST || + sector > FLASH_META_SECTOR_LAST) { + return; + } + flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); +} + +static uint32_t svhandler_flash_lock(void) { + /* Wait for any write operation to complete. */ + flash_wait_for_last_operation(); + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; + /* lock flash register */ + FLASH_CR |= FLASH_CR_LOCK; + /* return flash status register */ + return FLASH_SR; +} + +extern volatile uint32_t system_millis; + +void svc_handler_main(uint32_t *stack) { + uint8_t svc_number = ((uint8_t*) stack[6])[-2]; + switch (svc_number) { + case SVC_FLASH_UNLOCK: + svhandler_flash_unlock(); + break; + case SVC_FLASH_PROGRAM: + svhandler_flash_program(stack[0]); + break; + case SVC_FLASH_ERASE: + svhandler_flash_erase_sector(stack[0]); + break; + case SVC_FLASH_LOCK: + stack[0] = svhandler_flash_lock(); + break; + case SVC_TIMER_MS: + stack[0] = system_millis; + break; + default: + stack[0] = 0xffffffff; + break; + } +} diff --git a/supervise.h b/supervise.h new file mode 100644 index 0000000000..05a0c3ffa8 --- /dev/null +++ b/supervise.h @@ -0,0 +1,77 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Jochen Hoenicke + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __SUPERVISE_H__ +#define __SUPERVISE_H__ + +#define SVC_FLASH_UNLOCK 0 +#define SVC_FLASH_ERASE 1 +#define SVC_FLASH_PROGRAM 2 +#define SVC_FLASH_LOCK 3 +#define SVC_TIMER_MS 4 + +/* Unlocks flash. This function needs to be called before programming + * or erasing. Multiple calls of flash_program and flash_erase can + * follow and should be completed with flash_lock(). + */ +inline void svc_flash_unlock(void) { + __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_UNLOCK) : "memory"); +} + +/* Enable flash write operations. + * @param program_size (8-bit, 16-bit, 32-bit or 64-bit) + * should be one of the FLASH_CR_PROGRAM_X.. constants + */ +inline void svc_flash_program(uint32_t program_size) { + register uint32_t r0 __asm__("r0") = program_size; + __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_PROGRAM), "r" (r0) : "memory"); +} + +/* Erase a flash sector. + * @param sector sector number 0..11 + * (this only allows erasing meta sectors 2 and 3 though). + */ +inline void svc_flash_erase_sector(uint8_t sector) { + register uint32_t r0 __asm__("r0") = sector; + __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_ERASE), "r" (r0) : "memory"); +} + +/* Lock flash after programming or erasing. + * @return flash status register (FLASH_SR) + */ +inline uint32_t svc_flash_lock(void) { + register uint32_t r0 __asm__("r0"); + __asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_FLASH_LOCK) : "memory"); + return r0; +} + +inline uint32_t svc_timer_ms(void) { + register uint32_t r0 __asm__("r0"); + __asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_TIMER_MS) : "memory"); + return r0; +} + +inline void flash_write32(uint32_t addr, uint32_t word) { + *((volatile uint32_t *) addr) = word; +} +inline void flash_write8(uint32_t addr, uint8_t byte) { + *((volatile uint8_t *) addr) = byte; +} + +#endif diff --git a/timer.h b/timer.h index ac76d07e5d..93fe22962b 100644 --- a/timer.h +++ b/timer.h @@ -21,18 +21,14 @@ #define __TIMER_H__ #include +#include "supervise.h" void timer_init(void); #if EMULATOR uint32_t timer_ms(void); #else -static inline uint32_t timer_ms(void) { - /* 1 tick = 1 ms */ - extern volatile uint32_t system_millis; - - return system_millis; -} +#define timer_ms svc_timer_ms #endif #endif From 68e02c94da1db8b2a45843e89254db9edc6db4c7 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Sat, 24 Mar 2018 02:09:56 +0100 Subject: [PATCH 0791/1154] Reworked memory protection unit --- setup.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/setup.c b/setup.c index 0cd7f43d78..f78c8ec619 100644 --- a/setup.c +++ b/setup.c @@ -141,11 +141,16 @@ void setupApp(void) gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } -#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4KB (0x0bUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_8KB (0x0cUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_16KB (0x0dUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32KB (0x0eUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0fUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512MB (0x1cUL << MPU_RASR_SIZE_LSB) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html #define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) @@ -161,29 +166,34 @@ void mpu_config(void) // Disable MPU MPU_CTRL = 0; - // Bootloader (0x08000000 - 0x08007FFF, 32 KiB, read-only, execute never) + // Note: later entries overwrite previous ones + // Flash (0x08000000 - 0x0807FFFF, 512 KiB, read-only, execute never) MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRO_URO; - // Metadata (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) - MPU_RBAR = FLASH_BASE | 0x8000 | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + // Metadata in Flash is read-write when unlocked + // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) + MPU_RBAR = (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Firmware (0x08010000 - 0x0807FFFF, 64 + 3 * 128 KiB = 64 + 128 + 256 KiB = 448 KiB, read-only) - MPU_RBAR = FLASH_BASE | 0x10000 | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_64KB | MPU_RASR_ATTR_AP_PRO_URO; - MPU_RBAR = FLASH_BASE | 0x20000 | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRO_URO; - MPU_RBAR = FLASH_BASE | 0x40000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_256KB | MPU_RASR_ATTR_AP_PRO_URO; - // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) - MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never) - MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512MB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) + MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) + MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Flash controller is protected + // (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never) + MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; + // Don't enable DMA controller access + // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) + MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; // Enable MPU MPU_CTRL = MPU_CTRL_ENABLE; From ed7a8bfa6cae2857a8b702ea86cc58364b7a14a8 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 26 Mar 2018 19:02:50 +0200 Subject: [PATCH 0792/1154] Fixes for emulator --- emulator/flash.c | 23 +++++++++++++++++++++++ firmware/Makefile | 2 +- firmware/storage.c | 2 -- memory.h | 7 +++++++ supervise.c | 4 ++++ supervise.h | 17 +++++++++++------ 6 files changed, 46 insertions(+), 9 deletions(-) diff --git a/emulator/flash.c b/emulator/flash.c index b168d86bb1..a275cf641a 100644 --- a/emulator/flash.c +++ b/emulator/flash.c @@ -18,6 +18,8 @@ */ #include +#include +#include #include "memory.h" @@ -110,3 +112,24 @@ void flash_program_word(uint32_t address, uint32_t data) { void flash_program_byte(uint32_t address, uint8_t data) { *(volatile uint8_t *)FLASH_PTR(address) = data; } + +static bool flash_locked = true; +void svc_flash_unlock(void) { + assert (flash_locked); + flash_locked = false; +} +void svc_flash_program(uint32_t size) { + (void) size; + assert (!flash_locked); +} +void svc_flash_erase_sector(uint16_t sector) { + assert (!flash_locked); + assert (sector >= FLASH_META_SECTOR_FIRST && + sector <= FLASH_META_SECTOR_LAST); + flash_erase_sector(sector, 3); +} +uint32_t svc_flash_lock(void) { + assert (!flash_locked); + flash_locked = true; + return 0; +} diff --git a/firmware/Makefile b/firmware/Makefile index 2e5b329333..1a9a336946 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -6,9 +6,9 @@ ifeq ($(EMULATOR),1) OBJS += udp.o else OBJS += usb.o +OBJS += bl_check.o endif -OBJS += bl_check.o OBJS += u2f.o OBJS += messages.o OBJS += storage.o diff --git a/firmware/storage.c b/firmware/storage.c index 36b466c545..fbcd5559fd 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -122,12 +122,10 @@ void storage_show_error(void) void storage_check_flash_errors(uint32_t status) { -#if !EMULATOR // flash operation failed if (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { storage_show_error(); } -#endif } bool storage_from_flash(void) diff --git a/memory.h b/memory.h index 8bb9aac277..99415604cf 100644 --- a/memory.h +++ b/memory.h @@ -111,4 +111,11 @@ void memory_protect(void); void memory_write_unlock(void); int memory_bootloader_hash(uint8_t *hash); +inline void flash_write32(uint32_t addr, uint32_t word) { + *(volatile uint32_t *) FLASH_PTR(addr) = word; +} +inline void flash_write8(uint32_t addr, uint8_t byte) { + *(volatile uint8_t *) FLASH_PTR(addr) = byte; +} + #endif diff --git a/supervise.c b/supervise.c index 840d29d356..4a5967bdd0 100644 --- a/supervise.c +++ b/supervise.c @@ -22,6 +22,8 @@ #include "supervise.h" #include "memory.h" +#if !EMULATOR + static void svhandler_flash_unlock(void) { flash_clear_status_flags(); flash_unlock(); @@ -86,3 +88,5 @@ void svc_handler_main(uint32_t *stack) { break; } } + +#endif diff --git a/supervise.h b/supervise.h index 05a0c3ffa8..1457568a6e 100644 --- a/supervise.h +++ b/supervise.h @@ -20,6 +20,8 @@ #ifndef __SUPERVISE_H__ #define __SUPERVISE_H__ +#if !EMULATOR + #define SVC_FLASH_UNLOCK 0 #define SVC_FLASH_ERASE 1 #define SVC_FLASH_PROGRAM 2 @@ -67,11 +69,14 @@ inline uint32_t svc_timer_ms(void) { return r0; } -inline void flash_write32(uint32_t addr, uint32_t word) { - *((volatile uint32_t *) addr) = word; -} -inline void flash_write8(uint32_t addr, uint8_t byte) { - *((volatile uint8_t *) addr) = byte; -} +#else + +extern void svc_flash_unlock(void); +extern void svc_flash_program(uint32_t program_size); +extern void svc_flash_erase_sector(uint16_t sector); +extern uint32_t svc_flash_lock(void); +extern uint32_t svc_timer_ms(void); + +#endif #endif From be64864efc8399572b2b665705258b663d1d0363 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 26 Mar 2018 23:35:40 +0200 Subject: [PATCH 0793/1154] Put persistent variables at end of stack Two variables of the bootloader are persistent: - __stack_chk_guard is used by interrupt handlers - system_millis is used by timer interrupt and service routines Note that currently __stack_chk_guard is shared between unprivileged firmware and bootloader. If we get more variables later it may make sense to make a section for this. --- memory.ld | 3 +++ memory_app_1.0.0.ld | 3 +++ setup.c | 2 -- timer.c | 2 +- util.h | 7 ++++--- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/memory.ld b/memory.ld index b147a90997..b022e15d3d 100644 --- a/memory.ld +++ b/memory.ld @@ -18,5 +18,8 @@ INCLUDE libopencm3_stm32f2.ld _ram_start = ORIGIN(ram); _ram_end = ORIGIN(ram) + LENGTH(ram); +_stack = _ram_end - 8; +__stack_chk_guard = _ram_end - 8; +system_millis = _ram_end - 4; _data_size = SIZEOF(.data); diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index 291bfd3120..a59e5da489 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -18,5 +18,8 @@ INCLUDE libopencm3_stm32f2.ld _ram_start = ORIGIN(ram); _ram_end = ORIGIN(ram) + LENGTH(ram); +_stack = _ram_end - 8; +__stack_chk_guard = _ram_end - 8; +system_millis = _ram_end - 4; _data_size = SIZEOF(.data); diff --git a/setup.c b/setup.c index f78c8ec619..efc3e7fdaa 100644 --- a/setup.c +++ b/setup.c @@ -29,8 +29,6 @@ #include "layout.h" #include "util.h" -uint32_t __stack_chk_guard; - static inline void __attribute__((noreturn)) fault_handler(const char *line1) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever diff --git a/timer.c b/timer.c index d58855fefd..93f0eb0ca0 100644 --- a/timer.c +++ b/timer.c @@ -25,7 +25,7 @@ #include /* 1 tick = 1 ms */ -volatile uint32_t system_millis; +extern volatile uint32_t system_millis; /* * Initialise the Cortex-M3 SysTick timer diff --git a/util.h b/util.h index 8b6a9f2eb0..4e807d1fab 100644 --- a/util.h +++ b/util.h @@ -48,6 +48,7 @@ extern void __attribute__((noreturn)) shutdown(void); #if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; +extern uint8_t _stack[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); @@ -59,13 +60,13 @@ static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table { if (FW_SIGNED == trust) { // trusted signed firmware SCB_VTOR = (uint32_t)vector_table; // * relocate vector table + // Set stack pointer + __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); } else { // untrusted firmware mpu_config(); // * configure MPU + __asm__ volatile("msr msp, %0" :: "r" (_stack)); } - // Set stack pointer - __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); - // Jump to address vector_table->reset(); From 9f50f09421e151548657900d23d4e171d10cfa80 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 27 Mar 2018 00:33:17 +0200 Subject: [PATCH 0794/1154] Init timer interrupt for unsigned firmware --- bootloader/bootloader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index b47fedae88..780af28b82 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -33,6 +33,7 @@ #include "layout.h" #include "serialno.h" #include "rng.h" +#include "timer.h" void layoutFirmwareHash(const uint8_t *hash) { @@ -149,10 +150,9 @@ int main(void) int signed_firmware = signatures_ok(hash); if (SIG_OK != signed_firmware) { show_unofficial_warning(hash); + timer_init(); } - delay(100000); - load_app(signed_firmware); } #endif From 7fc58eb5db904f5f2de2873ab1d5e35ca157ad7e Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 27 Mar 2018 01:58:30 +0200 Subject: [PATCH 0795/1154] bootloader: signatures_ok must work without magic signatures_ok is called before the magic is written to the flash to determine whether the metadata should be written back. --- bootloader/signatures.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/bootloader/signatures.c b/bootloader/signatures.c index 9f9e540f6a..e178ecec7a 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -40,8 +40,6 @@ static const uint8_t * const pubkey[PUBKEYS] = { int signatures_ok(uint8_t *store_hash) { - if (!firmware_present()) return SIG_FAIL; // no firmware present - const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); From 3a3bea1401288513447eae67c67deb5d06497b5d Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 30 Mar 2018 17:13:31 +0700 Subject: [PATCH 0796/1154] Emulator: allow software renderer Makes emulator usable in containers --- emulator/oled.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulator/oled.c b/emulator/oled.c index 26babdb51d..1f61981667 100644 --- a/emulator/oled.c +++ b/emulator/oled.c @@ -67,7 +67,7 @@ void oledInit(void) { exit(1); } - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + renderer = SDL_CreateRenderer(window, -1, 0); if (!renderer) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); exit(1); From 519c117e30edf663c32c247ea2c75c5f181bcb75 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 30 Mar 2018 10:31:48 +0200 Subject: [PATCH 0797/1154] nem: SignTx instead of ConfirmOutput in mosaic creation --- firmware/nem2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/nem2.c b/firmware/nem2.c index ebe90731f9..d26f9cc2c8 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -436,7 +436,7 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr } layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } From 1f377bd9f65e054e864c59e9479203c84e4df8c0 Mon Sep 17 00:00:00 2001 From: Yura Pakhuchiy Date: Fri, 30 Mar 2018 23:54:09 +0700 Subject: [PATCH 0798/1154] Fix emulator build in docker Emulator is a 64-bit application now, so we should install 64-bit version of libSDL. Rename docker image and emulator filename to indicate 64-bitness as well. --- Dockerfile.emulator | 5 ++--- build-emulator.sh | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Dockerfile.emulator b/Dockerfile.emulator index 90fe68175c..b1488055e8 100644 --- a/Dockerfile.emulator +++ b/Dockerfile.emulator @@ -4,11 +4,10 @@ FROM debian:9 # install build tools and dependencies -RUN dpkg --add-architecture i386 && \ - apt-get update && \ +RUN apt-get update && \ apt-get install -y \ build-essential curl unzip git python3 python3-pip \ - libsdl2-dev:i386 libsdl2-image-dev:i386 gcc-multilib + libsdl2-dev libsdl2-image-dev ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" diff --git a/build-emulator.sh b/build-emulator.sh index 37b16952a3..40d5d28d46 100755 --- a/build-emulator.sh +++ b/build-emulator.sh @@ -1,9 +1,9 @@ #!/bin/bash set -e -IMAGE=trezor-mcu-build-emulator +IMAGE=trezor-mcu-build-emulator64 TAG=${1:-master} -ELFFILE=build/trezor-emulator-$TAG +ELFFILE=build/trezor-emulator64-$TAG docker build -f Dockerfile.emulator -t $IMAGE . docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ From d564805baa0717a215692a511895458bb89adc41 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 2 Apr 2018 18:21:42 +0100 Subject: [PATCH 0799/1154] setup: Define __stack_chk_guard If it is not defined, at least some installations of GCC will use their own stack protector implementation (creating multiple definitions of __stack_chk_fail). --- setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.c b/setup.c index efc3e7fdaa..f78c8ec619 100644 --- a/setup.c +++ b/setup.c @@ -29,6 +29,8 @@ #include "layout.h" #include "util.h" +uint32_t __stack_chk_guard; + static inline void __attribute__((noreturn)) fault_handler(const char *line1) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); for (;;) {} // loop forever From 7092951a40b1ce50ce8d91ca3ebe1163c0b5c79a Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 24 Dec 2017 12:33:18 +0000 Subject: [PATCH 0800/1154] Makefile: Add GENERATE_CODE function Fixes #281 --- firmware/Makefile | 26 +++++++++++++++++-------- firmware/{bl_data-gen.py => bl_data.py} | 0 2 files changed, 18 insertions(+), 8 deletions(-) rename firmware/{bl_data-gen.py => bl_data.py} (100%) diff --git a/firmware/Makefile b/firmware/Makefile index 1a9a336946..6e6a9d1570 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -94,19 +94,29 @@ CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')" CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_NEM=1 +define GENERATE_CODE +# $(1) - Basename for script and output header file +# $(2) - Dependencies +# $(3) - Additional output files + +$(1).h $(3): $(1).py $(2) + $(PYTHON) $(1).py + +# Serialize build for parallel Make +$(1).h: $(3) + +clean:: + rm -f $(1).h $(3) +endef + +$(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) + coins_count.h: coins-gen.py coins.json $(PYTHON) $< count > $@ coins_array.h: coins-gen.py coins.json $(PYTHON) $< array > $@ -nem_mosaics.c nem_mosaics.h: nem_mosaics.py nem_mosaics.json - $(PYTHON) $< - -bl_data.h: bl_data-gen.py ../bootloader/bootloader.bin - $(PYTHON) $< - clean:: rm -f coins_count.h coins_array.h - rm -f nem_mosaics.c nem_mosaics.h - rm -f bl_data.h diff --git a/firmware/bl_data-gen.py b/firmware/bl_data.py similarity index 100% rename from firmware/bl_data-gen.py rename to firmware/bl_data.py From 88230e33c43b74759761d040fd0d03f7f4cdec59 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 24 Dec 2017 12:33:18 +0000 Subject: [PATCH 0801/1154] nem_mosaics: Fix Flake8 warnings --- firmware/nem_mosaics.py | 43 ++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index 096d453941..7b9f259996 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -1,13 +1,13 @@ #!/usr/bin/env python -import json, os, sys +import json +import os +import sys -import collections, numbers +import collections +import itertools +import numbers from google.protobuf import json_format -from itertools import chain - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "protob")) -import types_pb2 as types try: basestring @@ -28,7 +28,7 @@ extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_C extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; #endif -""".lstrip() +""".lstrip() # noqa: E501 CODE_TEMPLATE = """ // This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! @@ -38,7 +38,8 @@ CODE_TEMPLATE = """ const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {code}; const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; -""".lstrip() +""".lstrip() # noqa: E501 + def format_primitive(value): if isinstance(value, bool): @@ -54,9 +55,11 @@ def format_primitive(value): else: raise TypeError + def format_struct(struct): return "{\n" + "\n".join( - "\t.{0} = {1},".format(member, value) for member, value in struct.items() + "\t.{0} = {1},".format(member, value) + for member, value in struct.items() ) + "\n}" @@ -64,42 +67,56 @@ def format_field(field, value): if field.message_type is not None: raise TypeError elif field.enum_type: - return "{0}_{1}".format(field.enum_type.name, field.enum_type.values_by_number[value].name) + type_name = field.enum_type.name + enum_name = field.enum_type.values_by_number[value].name + return "{0}_{1}".format(type_name, enum_name) elif hasattr(value, "_values"): return format_primitive(value._values) else: return format_primitive(value) + def field_to_meta(field, value): if field.label == field.LABEL_REPEATED: return ("{}_count".format(field.name), format_primitive(len(value))) else: return ("has_{}".format(field.name), format_primitive(True)) + def message_to_struct(_message, proto): message = json_format.ParseDict(_message, proto()) - return collections.OrderedDict(chain.from_iterable( + return collections.OrderedDict(itertools.chain.from_iterable( ( field_to_meta(field, value), (field.name, format_field(field, value)), ) for field, value in message.ListFields() )) + def format_message(message, proto): return format_struct(message_to_struct(message, proto)) + def format_messages(messages, proto): return "{" + ",\n".join( format_message(message, proto) for message in messages ) + "}" + if __name__ == "__main__": os.chdir(os.path.abspath(os.path.dirname(__file__))) + sys.path.insert(0, "protob") + import types_pb2 as types + messages = json.load(open("nem_mosaics.json")) with open("nem_mosaics.h", "w+") as f: - f.write(HEADER_TEMPLATE.format(count=format_primitive(len(messages)))) + f.write(HEADER_TEMPLATE.format( + count=format_primitive(len(messages))) + ) with open("nem_mosaics.c", "w+") as f: - f.write(CODE_TEMPLATE.format(code=format_messages(messages, types.NEMMosaicDefinition))) + f.write(CODE_TEMPLATE.format( + code=format_messages(messages, types.NEMMosaicDefinition)) + ) From 69356e5f563f05f2c2fd8570c18bd47298d5c11f Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 24 Dec 2017 12:33:18 +0000 Subject: [PATCH 0802/1154] messages_map: Fix Flake8 warnings --- firmware/protob/messages_map.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index 6499cfb6aa..00dc2f7ce2 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -1,7 +1,10 @@ #!/usr/bin/env python from collections import defaultdict from messages_pb2 import MessageType -from types_pb2 import wire_in, wire_out, wire_debug_in, wire_debug_out, wire_tiny, wire_bootloader + +from types_pb2 import wire_in, wire_out +from types_pb2 import wire_debug_in, wire_debug_out +from types_pb2 import wire_bootloader, wire_tiny # len("MessageType_MessageType_") - len("_fields") == 17 TEMPLATE = "\t{{ {type} {dir} {msg_id:46} {fields:29} {process_func} }}," @@ -13,6 +16,7 @@ LABELS = { wire_debug_out: "debug out messages", } + def handle_message(message, extension): name = message.name short_name = name.split("MessageType_", 1).pop() @@ -32,15 +36,22 @@ def handle_message(message, extension): if tiny: return '\t// Message %s is used in tiny mode' % short_name + if direction == "i": + process_func = "(void (*)(void *)) fsm_msg%s" % short_name + else: + process_func = "0" + return TEMPLATE.format( type="'%c'," % interface, dir="'%c'," % direction, msg_id="MessageType_%s," % name, fields="%s_fields," % short_name, - process_func = "(void (*)(void *)) fsm_msg%s" % short_name if direction == "i" else "0" + process_func=process_func, ) -print('\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!') + +print("\t// This file is automatically generated" + "by messages_map.py -- DO NOT EDIT!") messages = defaultdict(list) From b3f1d79821273d4b1e826650e69d64f4c935c52c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 24 Dec 2017 13:41:48 +0000 Subject: [PATCH 0803/1154] coin_info: Refactor coins-gen.py --- firmware/.gitignore | 4 +- firmware/Makefile | 11 +--- firmware/coin_info.py | 131 ++++++++++++++++++++++++++++++++++++++++++ firmware/coins.c | 7 --- firmware/coins.h | 3 +- 5 files changed, 135 insertions(+), 21 deletions(-) create mode 100755 firmware/coin_info.py diff --git a/firmware/.gitignore b/firmware/.gitignore index e21cd098b0..a35c8127e0 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,6 +1,4 @@ -coins_array.h -coins_count.h - +coin_info.[ch] nem_mosaics.[ch] bl_data.h diff --git a/firmware/Makefile b/firmware/Makefile index 6e6a9d1570..88fa9ace0b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -16,6 +16,7 @@ OBJS += trezor.o OBJS += pinmatrix.o OBJS += fsm.o OBJS += coins.o +OBJS += coin_info.o OBJS += transaction.o OBJS += protect.o OBJS += layout2.o @@ -109,14 +110,6 @@ clean:: rm -f $(1).h $(3) endef +$(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) $(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) - -coins_count.h: coins-gen.py coins.json - $(PYTHON) $< count > $@ - -coins_array.h: coins-gen.py coins.json - $(PYTHON) $< array > $@ - -clean:: - rm -f coins_count.h coins_array.h diff --git a/firmware/coin_info.py b/firmware/coin_info.py new file mode 100755 index 0000000000..c8e8a5cf4d --- /dev/null +++ b/firmware/coin_info.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python2 +import json +import os + +import collections + +HEADER_TEMPLATE = """ +// This file is automatically generated by coin_info.py -- DO NOT EDIT! + +#ifndef __COIN_INFO_H__ +#define __COIN_INFO_H__ + +#include "coins.h" + +#if DEBUG_LINK +#define COINS_COUNT ({stable} + {debug}) +#else +#define COINS_COUNT ({stable}) +#endif + +extern const CoinInfo coins[COINS_COUNT]; + +#endif +""".lstrip() + +CODE_TEMPLATE = """ +// This file is automatically generated by coin_info.py -- DO NOT EDIT! + +#include "coins.h" + +#include "curves.h" +#include "secp256k1.h" + +const CoinInfo coins[COINS_COUNT] = {{ +{stable} +#if DEBUG_LINK +{debug} +#endif +}}; +""".lstrip() + + +def format_bool(value): + if value: + return "true" + else: + return "false" + + +def format_number(value): + if value is None: + value = 0 + return str(value) + + +def format_string(value): + if value is None: + return "NULL" + else: + return json.dumps(value) + + +def format_hex(value): + if value is None: + value = "0" + return "0x{:08x}".format(int(value, 16)) + + +def prepend_varint(string): + assert len(string) < 253 + + varint = "\"\\x{:02x}\"".format(len(string)) + return "{} {}".format(varint, format_string(string)) + + +def coin_to_struct(coin): + return collections.OrderedDict(( + ("coin_name", format_string(coin["coin_name"])), + ("coin_shortcut", format_string(coin["coin_shortcut"])), + ("maxfee_kb", format_number(coin["maxfee_kb"])), + ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 + ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 + ("has_address_type_p2sh", format_bool(coin["address_type_p2sh"] is not None)), # noqa: E501 + ("has_segwit", format_bool(coin["segwit"])), + ("has_forkid", format_bool(coin["forkid"] is not None)), + ("force_bip143", format_bool(coin["force_bip143"])), + ("address_type", format_number(coin["address_type"])), + ("address_type_p2sh", format_number(coin["address_type_p2sh"])), + ("xpub_magic", format_hex(coin["xpub_magic"])), + ("xprv_magic", format_hex(coin["xprv_magic"])), + ("forkid", format_number(coin["forkid"])), + ("bech32_prefix", format_string(coin["bech32_prefix"])), + ("coin_type", "({} | 0x80000000)".format(format_number(coin["bip44"]))), # noqa: E501 + ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 + ("curve", "&{}_info".format(coin["curve_name"])), + )) + + +def format_struct(struct): + return "{\n" + "\n".join( + "\t.{0} = {1},".format(member, value) + for member, value in struct.items() + ) + "\n}" + + +def format_coin(coin): + return format_struct(coin_to_struct(coin)) + + +def format_coins(coins): + return "\n".join("{},".format(format_coin(coin)) for coin in coins) + + +if __name__ == "__main__": + os.chdir(os.path.abspath(os.path.dirname(__file__))) + + coins = collections.defaultdict(list) + + for coin in json.load(open("coins.json")): + firmware = coin["firmware"] + coins[firmware].append(coin) + + with open("coin_info.h", "w+") as f: + f.write(HEADER_TEMPLATE.format(**{ + k: format_number(len(v)) for k, v in coins.items() + })) + + with open("coin_info.c", "w+") as f: + f.write(CODE_TEMPLATE.format(**{ + k: format_coins(v) for k, v in coins.items() + })) diff --git a/firmware/coins.c b/firmware/coins.c index 0618c60ddf..1600f9acbc 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -20,15 +20,8 @@ #include #include "coins.h" #include "address.h" -#include "curves.h" #include "ecdsa.h" #include "base58.h" -#include "secp256k1.h" - -// filled CoinInfo structure defined in coins.h -const CoinInfo coins[COINS_COUNT] = { -#include "coins_array.h" -}; const CoinInfo *coinByName(const char *name) { diff --git a/firmware/coins.h b/firmware/coins.h index eae9bbd61c..c6a1c0b7a7 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -24,7 +24,6 @@ #include #include "bip32.h" -#include "coins_count.h" #include "hasher.h" typedef struct _CoinInfo { @@ -49,7 +48,7 @@ typedef struct _CoinInfo { const curve_info *curve; } CoinInfo; -extern const CoinInfo coins[COINS_COUNT]; +#include "coin_info.h" const CoinInfo *coinByName(const char *name); const CoinInfo *coinByAddressType(uint32_t address_type); From bfb8dda5e8582b9e17bca0904affd8bfdf1b6652 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 24 Dec 2017 14:08:21 +0000 Subject: [PATCH 0804/1154] Travis CI: Do not run device tests if build fails --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 374b6f701e..1d4298d8aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,7 @@ matrix: - $PYTHON -m pip install --user rlp - $PYTHON -m pip install --user --no-deps git+https://github.com/trezor/python-trezor@master script: - - script/cibuild - - script/test -k 'not skip_t1' + - script/cibuild && script/test -k 'not skip_t1' install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 98493218831e3598293ca96b02651f31bd69f1a5 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 13:27:00 +0000 Subject: [PATCH 0805/1154] coins: Add Decred support --- firmware/coin_info.py | 1 + firmware/coins.h | 1 + 2 files changed, 2 insertions(+) diff --git a/firmware/coin_info.py b/firmware/coin_info.py index c8e8a5cf4d..509d06c152 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -84,6 +84,7 @@ def coin_to_struct(coin): ("has_segwit", format_bool(coin["segwit"])), ("has_forkid", format_bool(coin["forkid"] is not None)), ("force_bip143", format_bool(coin["force_bip143"])), + ("decred", format_bool(coin["decred"])), ("address_type", format_number(coin["address_type"])), ("address_type_p2sh", format_number(coin["address_type_p2sh"])), ("xpub_magic", format_hex(coin["xpub_magic"])), diff --git a/firmware/coins.h b/firmware/coins.h index c6a1c0b7a7..2cdd657240 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -36,6 +36,7 @@ typedef struct _CoinInfo { bool has_segwit; bool has_forkid; bool force_bip143; + bool decred; // address types > 0xFF represent a two-byte prefix in big-endian order uint32_t address_type; uint32_t address_type_p2sh; From 3f51bc36286216e0282a4786cfbc037ebafed6bf Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 19:22:31 +0000 Subject: [PATCH 0806/1154] signing: Use SignTx in signing_init --- firmware/fsm.c | 2 +- firmware/signing.c | 10 +++++----- firmware/signing.h | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 4ad2892158..6616b9e3e7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -541,7 +541,7 @@ void fsm_msgSignTx(SignTx *msg) const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); if (!node) return; - signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time); + signing_init(msg, coin, node); } void fsm_msgTxAck(TxAck *msg) diff --git a/firmware/signing.c b/firmware/signing.c index 3c7003408a..50e94c892b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -430,14 +430,14 @@ bool compile_input_script_sig(TxInputType *tinput) return tinput->script_sig.size > 0; } -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time) +void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) { - inputs_count = _inputs_count; - outputs_count = _outputs_count; + inputs_count = msg->inputs_count; + outputs_count = msg->outputs_count; coin = _coin; root = _root; - version = _version; - lock_time = _lock_time; + version = msg->version; + lock_time = msg->lock_time; tx_weight = 4 * (TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) diff --git a/firmware/signing.h b/firmware/signing.h index e4ee8c55d6..68c3ccf537 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -25,9 +25,10 @@ #include "bip32.h" #include "coins.h" #include "hasher.h" +#include "messages.pb.h" #include "types.pb.h" -void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinInfo *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time); +void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root); void signing_abort(void); void signing_txack(TransactionType *tx); From 057ec1227d600b4f1f82d31afb784adba9ac50e8 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 10 Dec 2017 19:22:31 +0000 Subject: [PATCH 0807/1154] signing: Add Decred support --- firmware/signing.c | 146 +++++++++++++++++++++++++++++++++++++++-- firmware/transaction.c | 90 +++++++++++++++++++++++-- firmware/transaction.h | 6 +- 3 files changed, 232 insertions(+), 10 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 50e94c892b..f9f63b39b6 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -45,7 +45,8 @@ enum { STAGE_REQUEST_4_OUTPUT, STAGE_REQUEST_SEGWIT_INPUT, STAGE_REQUEST_5_OUTPUT, - STAGE_REQUEST_SEGWIT_WITNESS + STAGE_REQUEST_SEGWIT_WITNESS, + STAGE_REQUEST_DECRED_WITNESS } signing_stage; static uint32_t idx1, idx2; static uint32_t signatures; @@ -57,6 +58,7 @@ static Hasher hashers[3]; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; +static uint8_t hash_prefix[32]; static uint8_t hash_check[32]; static uint64_t to_spend, authorized_amount, spending, change_spend; static uint32_t version = 1; @@ -92,6 +94,12 @@ enum { SIGHASH_FORKID = 0x40, }; +enum { + DECRED_SERIALIZE_FULL = 0, + DECRED_SERIALIZE_NO_WITNESS = 1, + DECRED_SERIALIZE_WITNESS_SIGNING = 3, +}; + /* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. @@ -298,6 +306,17 @@ void send_req_segwit_witness(void) msg_write(MessageType_MessageType_TxRequest, &resp); } +void send_req_decred_witness(void) +{ + signing_stage = STAGE_REQUEST_DECRED_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); +} + void send_req_5_output(void) { signing_stage = STAGE_REQUEST_5_OUTPUT; @@ -464,6 +483,18 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) next_nonsegwit_input = 0xffffffff; tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + + if (coin->decred) { + to.version |= (DECRED_SERIALIZE_FULL << 16); + to.is_decred = true; + to.decred_expiry = msg->decred_expiry; + + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + ti.is_decred = true; + ti.decred_expiry = msg->decred_expiry; + } + // segwit hashes for hashPrevouts and hashSequence hasher_Init(&hashers[0], coin->curve->hasher_type); hasher_Init(&hashers[1], coin->curve->hasher_type); @@ -503,6 +534,15 @@ static bool signing_check_input(TxInputType *txinput) { // compute segwit hashPrevouts & hashSequence tx_prevout_hash(&hashers[0], txinput); tx_sequence_hash(&hashers[1], txinput); + if (coin->decred) { + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_input(&to, txinput, resp.serialized.serialized_tx.bytes); + + // compute Decred hashPrefix + tx_serialize_input_hash(&ti, txinput); + } // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hashers[2], txinput); hasher_Update(&hashers[2], (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); @@ -589,8 +629,17 @@ static bool signing_check_output(TxOutputType *txoutput) { signing_abort(); return false; } + if (coin->decred) { + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); + + // compute Decred hashPrefix + tx_serialize_output_hash(&ti, &bin_output); + } // compute segwit hashOuts - tx_output_hash(&hashers[0], &bin_output); + tx_output_hash(&hashers[0], &bin_output, coin->decred); return true; } @@ -635,6 +684,10 @@ static void phase1_request_next_output(void) { idx1++; send_req_3_output(); } else { + if (coin->decred) { + // compute Decred hashPrefix + tx_hash_final(&ti, hash_prefix, false); + } hasher_Double(&hashers[0], hash_outputs); if (!signing_check_fee()) { return; @@ -643,7 +696,12 @@ static void phase1_request_next_output(void) { progress_meta_step = progress_step / (inputs_count + outputs_count); layoutProgress(_("Signing transaction"), progress); idx1 = 0; - phase2_request_next_input(); + if (coin->decred) { + // Decred prefix serialized in Phase 1, skip Phase 2 + send_req_decred_witness(); + } else { + phase2_request_next_input(); + } } } @@ -663,6 +721,15 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { hasher_Double(&hashers[0], hash); } +static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { + uint32_t hash_type = signing_hash_type(); + hasher_Reset(&hashers[0]); + hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); + hasher_Update(&hashers[0], hash_prefix, 32); + hasher_Update(&hashers[0], hash_witness, 32); + hasher_Final(&hashers[0], hash); +} + static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; @@ -785,6 +852,17 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { return true; } +static bool signing_sign_decred_input(TxInputType *txinput) { + uint8_t hash[32], hash_witness[32]; + tx_hash_final(&ti, hash_witness, false); + signing_hash_decred(hash_witness, hash); + resp.has_serialized = true; + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) + return false; + resp.serialized.serialized_tx.size = tx_serialize_decred_witness(&to, txinput, resp.serialized.serialized_tx.bytes); + return true; +} + #define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 void signing_txack(TransactionType *tx) @@ -842,6 +920,11 @@ void signing_txack(TransactionType *tx) } } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { + if (coin->decred) { + fsm_sendFailure(FailureType_Failure_DataError, _("Decred does not support Segwit")); + signing_abort(); + return; + } if (!coin->has_segwit) { fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); signing_abort(); @@ -883,6 +966,11 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_2_PREV_META: tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_type); + if (coin->decred) { + tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + tp.is_decred = true; + tp.decred_expiry = tx->decred_expiry; + } progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; if (tp.inputs_len > 0) { @@ -1008,7 +1096,7 @@ void signing_txack(TransactionType *tx) return; } // check hashOutputs - tx_output_hash(&hashers[0], &bin_output); + tx_output_hash(&hashers[0], &bin_output, coin->decred); if (!tx_serialize_output_hash(&ti, &bin_output)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); @@ -1146,6 +1234,56 @@ void signing_txack(TransactionType *tx) signing_abort(); } return; + + case STAGE_REQUEST_DECRED_WITNESS: + progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); + if (idx1 == 0) { + // witness + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + to.is_decred = true; + } + + // witness hash + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); + ti.is_decred = true; + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + signing_abort(); + return; + } + + for (idx2 = 0; idx2 < inputs_count; idx2++) { + uint32_t r; + if (idx2 == idx1) { + r = tx_serialize_decred_witness_hash(&ti, &tx->inputs[0]); + } else { + r = tx_serialize_decred_witness_hash(&ti, NULL); + } + + if (!r) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); + signing_abort(); + return; + } + } + + if (!signing_sign_decred_input(&tx->inputs[0])) { + return; + } + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_decred_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; } fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); diff --git a/firmware/transaction.c b/firmware/transaction.c index 8cbe21c53e..7f46e61ea1 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -173,6 +173,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T { memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; + out->decred_script_version = in->decred_script_version; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; size_t addr_raw_len; @@ -399,10 +400,14 @@ uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) return 4; } -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output) +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) { uint32_t r = 0; hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; + if (decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + hasher_Update(hasher, (const uint8_t *)&script_version, 2); r += 2; + } r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); return r; } @@ -451,7 +456,12 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out } r += 32; memcpy(out + r, &input->prev_index, 4); r += 4; - r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + out[r++] = tree; + } else { + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); + } memcpy(out + r, &input->sequence, 4); r += 4; tx->have_inputs++; @@ -471,7 +481,12 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) r += tx_serialize_header_hash(tx); } r += tx_prevout_hash(&(tx->hasher), input); - r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); r++; + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); + } r += tx_sequence_hash(&(tx->hasher), input); tx->have_inputs++; @@ -480,6 +495,53 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) return r; } +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) +{ + static const uint64_t amount = 0; + static const uint32_t block_height = 0x00000000; + static const uint32_t block_index = 0xFFFFFFFF; + + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += ser_length(tx->inputs_len, out + r); + } + memcpy(out + r, &amount, 8); r += 8; + memcpy(out + r, &block_height, 4); r += 4; + memcpy(out + r, &block_index, 4); r += 4; + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); + + tx->have_inputs++; + tx->size += r; + + return r; +} + +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) +{ + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + if (input == NULL) { + r += ser_length_hash(&(tx->hasher), 0); + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); + } + + tx->have_inputs++; + tx->size += r; + + return r; +} + uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) { return ser_length(tx->outputs_len, out); @@ -493,12 +555,20 @@ uint32_t tx_serialize_middle_hash(TxStruct *tx) uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); + if (tx->is_decred) { + memcpy(out + 4, &(tx->decred_expiry), 4); + return 8; + } return 4; } uint32_t tx_serialize_footer_hash(TxStruct *tx) { hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); + if (tx->is_decred) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->decred_expiry), 4); + return 8; + } return 4; } @@ -517,6 +587,10 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_ r += tx_serialize_middle(tx, out + r); } memcpy(out + r, &output->amount, 8); r += 8; + if (tx->is_decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + memcpy(out + r, &script_version, 2); r += 2; + } r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len @@ -541,7 +615,7 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) if (tx->have_outputs == 0) { r += tx_serialize_middle_hash(tx); } - r += tx_output_hash(&(tx->hasher), output); + r += tx_output_hash(&(tx->hasher), output, tx->is_decred); tx->have_outputs++; if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { @@ -583,12 +657,18 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->extra_data_received = 0; tx->size = 0; tx->is_segwit = false; + tx->is_decred = false; + tx->decred_expiry = 0; hasher_Init(&(tx->hasher), hasher_type); } void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { - hasher_Double(&(t->hasher), hash); + if (t->is_decred) { + hasher_Final(&(t->hasher), hash); + } else { + hasher_Double(&(t->hasher), hash); + } if (!reverse) return; for (uint8_t i = 0; i < 16; i++) { uint8_t k = hash[31 - i]; diff --git a/firmware/transaction.h b/firmware/transaction.h index a65f58970c..3695cfc4cc 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -34,7 +34,9 @@ typedef struct { uint32_t version; uint32_t lock_time; + uint32_t decred_expiry; bool is_segwit; + bool is_decred; uint32_t have_inputs; uint32_t have_outputs; @@ -58,18 +60,20 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_type); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t tx_input_weight(const TxInputType *txinput); From d63e294c0bab8fa9ff97007ac7b3fb766ff73d45 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sun, 17 Dec 2017 21:42:33 +0000 Subject: [PATCH 0808/1154] signing: Document Decred signing --- firmware/signing.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/firmware/signing.c b/firmware/signing.c index f9f63b39b6..05cb9054b3 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -122,7 +122,10 @@ Phase1 - check inputs, previous transactions, and outputs foreach I (idx1): Request I STAGE_REQUEST_1_INPUT Add I to segwit hash_prevouts, hash_sequence + Add I to Decred hash_prefix Add I to TransactionChecksum (prevout and type) + if (Decred) + Return I If not segwit, Calculate amount of I: Request prevhash I, META STAGE_REQUEST_2_PREV_META foreach prevhash I (idx2): @@ -134,7 +137,10 @@ foreach I (idx1): Calculate hash of streamed tx, compare to prevhash I foreach O (idx1): Request O STAGE_REQUEST_3_OUTPUT + Add O to Decred hash_prefix Add O to TransactionChecksum + if (Decred) + Return O Display output Ask for confirmation @@ -144,6 +150,9 @@ Ask for confirmation Phase2: sign inputs, check that nothing changed =============================================== +if (Decred) + Skip to STAGE_REQUEST_DECRED_WITNESS + foreach I (idx1): // input to sign if (idx1 is segwit) Request I STAGE_REQUEST_SEGWIT_INPUT @@ -153,8 +162,8 @@ foreach I (idx1): // input to sign foreach I (idx2): Request I STAGE_REQUEST_4_INPUT If idx1 == idx2 - Remember key for signing Fill scriptsig + Remember key for signing Add I to StreamTransactionSign Add I to TransactionChecksum foreach O (idx2): @@ -182,6 +191,17 @@ foreach I (idx1): // input to sign Check amount Sign segwit prevhash, sequence, amount, outputs Return witness + +Phase3: sign Decred inputs +========================== + +foreach I (idx1): // input to sign STAGE_REQUEST_DECRED_WITNESS + Request I + Fill scriptSig + Compute hash_witness + + Sign (hash_type || hash_prefix || hash_witness) + Return witness */ void send_req_1_input(void) From 77e76542bc18ea9a48aba7e83b5901e24863ea74 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 18 Dec 2017 16:49:17 +0000 Subject: [PATCH 0809/1154] signing: Compute tx_weight for Decred --- firmware/signing.c | 17 +++++++++++++---- firmware/transaction.c | 29 +++++++++++++++++++++++++++-- firmware/transaction.h | 3 ++- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 05cb9054b3..2aff6bd21c 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -478,9 +478,13 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) version = msg->version; lock_time = msg->lock_time; - tx_weight = 4 * (TXSIZE_HEADER + TXSIZE_FOOTER - + ser_length_size(inputs_count) - + ser_length_size(outputs_count)); + uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); + if (coin->decred) { + size += 4; // Decred expiry + size += ser_length_size(inputs_count); // Witness inputs count + } + + tx_weight = 4 * size; signatures = 0; idx1 = 0; @@ -904,7 +908,12 @@ void signing_txack(TransactionType *tx) switch (signing_stage) { case STAGE_REQUEST_1_INPUT: signing_check_input(&tx->inputs[0]); - tx_weight += tx_input_weight(&tx->inputs[0]); + + tx_weight += tx_input_weight(coin, &tx->inputs[0]); + if (coin->decred) { + tx_weight += tx_decred_witness_weight(&tx->inputs[0]); + } + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { memcpy(&input, tx->inputs, sizeof(TxInputType)); diff --git a/firmware/transaction.c b/firmware/transaction.c index 7f46e61ea1..e99dc75786 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -53,6 +53,8 @@ #define TXSIZE_P2PKHASH 25 /* size of a p2sh script (hash, push, 20 scripthash, equal) */ #define TXSIZE_P2SCRIPT 23 +/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block index */ +#define TXSIZE_DECRED_WITNESS 16 static const uint8_t segwit_header[2] = {0,1}; @@ -677,7 +679,7 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -uint32_t tx_input_weight(const TxInputType *txinput) { +static uint32_t tx_input_script_size(const TxInputType *txinput) { uint32_t input_script_size; if (txinput->has_multisig) { uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT @@ -688,6 +690,16 @@ uint32_t tx_input_weight(const TxInputType *txinput) { } else { input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); } + + return input_script_size; +} + +uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) { + if (coin->decred) { + return 4 * (TXSIZE_INPUT + 1); // Decred tree + } + + uint32_t input_script_size = tx_input_script_size(txinput); uint32_t weight = 4 * TXSIZE_INPUT; if (txinput->script_type == InputScriptType_SPENDADDRESS || txinput->script_type == InputScriptType_SPENDMULTISIG) { @@ -740,5 +752,18 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { } } output_script_size += ser_length_size(output_script_size); - return 4 * (TXSIZE_OUTPUT + output_script_size); + + uint32_t size = TXSIZE_OUTPUT; + if (coin->decred) { + size += 2; // Decred script version + } + + return 4 * (size + output_script_size); +} + +uint32_t tx_decred_witness_weight(const TxInputType *txinput) { + uint32_t input_script_size = tx_input_script_size(txinput); + uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; + + return 4 * size; } diff --git a/firmware/transaction.h b/firmware/transaction.h index 3695cfc4cc..cd344093ff 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -76,7 +76,8 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -uint32_t tx_input_weight(const TxInputType *txinput); +uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput); uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput); +uint32_t tx_decred_witness_weight(const TxInputType *txinput); #endif From e7703a16fef30c33e9f5fa12ff3f2021da7b8975 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 16:25:01 +0000 Subject: [PATCH 0810/1154] crypto: Remove hardcoded instances of secp256k1 --- firmware/crypto.c | 10 +++++----- firmware/crypto.h | 4 ++-- firmware/signing.c | 14 +++++++------- firmware/transaction.c | 20 ++++++++++---------- firmware/transaction.h | 6 +++--- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 349116bef9..4ff322c250 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -163,7 +163,7 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // check if signature verifies the digest and recover the public key uint8_t pubkey[65]; - if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) { + if (ecdsa_verify_digest_recover(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { return 3; } // convert public key to compressed pubkey if necessary @@ -327,11 +327,11 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le } */ -uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) { + if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, coin->curve_name, &node) == 0) { return 0; } layoutProgressUpdate(true); @@ -344,10 +344,10 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) return node.public_key; } -int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) +int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { for (size_t i = 0; i < multisig->pubkeys_count; i++) { - const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { return i; } diff --git a/firmware/crypto.h b/firmware/crypto.h index 7744c2909d..2f72a48bcf 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -51,9 +51,9 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath); -int cryptoMultisigPubkeyIndex(const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); +int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); diff --git a/firmware/signing.c b/firmware/signing.c index 2aff6bd21c..5cccaff4ab 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -460,7 +460,7 @@ bool compile_input_script_sig(TxInputType *tinput) } hdnode_fill_public_key(&node); if (tinput->has_multisig) { - tinput->script_sig.size = compile_script_multisig(&(tinput->multisig), tinput->script_sig.bytes); + tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS uint8_t hash[20]; ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_type, hash); @@ -759,7 +759,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(&secp256k1, private_key, hash, sig, NULL, NULL) != 0) { + if (ecdsa_sign_digest(coin->curve->params, private_key, hash, sig, NULL, NULL) != 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); signing_abort(); return false; @@ -769,7 +769,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, uint8_t sighash = signing_hash_type() & 0xff; if (txinput->has_multisig) { // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(&(txinput->multisig), public_key); + int pubkey_idx = cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); if (pubkey_idx < 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); signing_abort(); @@ -777,7 +777,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, } memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - txinput->script_sig.size = serialize_script_multisig(&(txinput->multisig), sighash, txinput->script_sig.bytes); + txinput->script_sig.size = serialize_script_multisig(coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); if (txinput->script_sig.size == 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); signing_abort(); @@ -845,9 +845,9 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = sighash; r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); } - uint32_t script_len = compile_script_multisig(&txinput->multisig, 0); + uint32_t script_len = compile_script_multisig(coin, &txinput->multisig, 0); r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); - r += compile_script_multisig(&txinput->multisig, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(coin, &txinput->multisig, resp.serialized.serialized_tx.bytes + r); resp.serialized.serialized_tx.bytes[0] = nwitnesses; resp.serialized.serialized_tx.size = r; } else { // single signature @@ -1207,7 +1207,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script - if (!compile_script_multisig_hash(&tx->inputs[0].multisig, coin->curve->hasher_type, tx->inputs[0].script_sig.bytes + 3)) { + if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; diff --git a/firmware/transaction.c b/firmware/transaction.c index e99dc75786..cee79124d9 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -106,10 +106,10 @@ bool compute_address(const CoinInfo *coin, size_t prelen; if (has_multisig) { - if (cryptoMultisigPubkeyIndex(multisig, node->public_key) < 0) { + if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) { return 0; } - if (compile_script_multisig_hash(multisig, coin->curve->hasher_type, digest) == 0) { + if (compile_script_multisig_hash(coin, multisig, digest) == 0) { return 0; } if (script_type == InputScriptType_SPENDWITNESS) { @@ -294,7 +294,7 @@ uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, ui } // if out == NULL just compute the length -uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out) +uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out) { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; @@ -306,7 +306,7 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 out[r] = 0x50 + m; r++; for (uint32_t i = 0; i < n; i++) { out[r] = 33; r++; // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); if (!pubkey) return 0; memcpy(out + r, pubkey, 33); r += 33; } @@ -318,7 +318,7 @@ uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8 return r; } -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash) +uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash) { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; @@ -327,13 +327,13 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, if (n < 1 || n > 15) return 0; Hasher hasher; - hasher_Init(&hasher, hasher_type); + hasher_Init(&hasher, coin->curve->hasher_type); uint8_t d[2]; d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); for (uint32_t i = 0; i < n; i++) { d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(&(multisig->pubkeys[i])); + const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); if (!pubkey) return 0; hasher_Update(&hasher, pubkey, 33); } @@ -357,7 +357,7 @@ uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, return r; } -uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) +uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) { uint32_t r = 0; out[r] = 0x00; r++; @@ -369,12 +369,12 @@ uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uin memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; out[r] = sighash; r++; } - uint32_t script_len = compile_script_multisig(multisig, 0); + uint32_t script_len = compile_script_multisig(coin, multisig, 0); if (script_len == 0) { return 0; } r += op_push(script_len, out + r); - r += compile_script_multisig(multisig, out + r); + r += compile_script_multisig(coin, multisig, out + r); return r; } diff --git a/firmware/transaction.h b/firmware/transaction.h index cd344093ff..8177a9655a 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -51,10 +51,10 @@ typedef struct { bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); -uint32_t compile_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t *out); -uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig, HasherType hasher_type, uint8_t *hash); +uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out); +uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); -uint32_t serialize_script_multisig(const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); +uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); From f0875285b214f4efbc62308ee715c03d4ca2d96c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 20:38:36 +0000 Subject: [PATCH 0811/1154] transaction: Fix Decred multisig --- firmware/transaction.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index cee79124d9..1237da7d05 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -360,7 +360,10 @@ uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) { uint32_t r = 0; - out[r] = 0x00; r++; + if (!coin->decred) { + // Decred fixed the off-by-one bug + out[r] = 0x00; r++; + } for (uint32_t i = 0; i < multisig->signatures_count; i++) { if (multisig->signatures[i].size == 0) { continue; From 0df9404054167d3ccf6c414dc92ab66d57f392d3 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Wed, 20 Dec 2017 20:51:45 +0000 Subject: [PATCH 0812/1154] signing: Check decred_script_version for txinput --- firmware/signing.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/firmware/signing.c b/firmware/signing.c index 5cccaff4ab..bf5d87e0ce 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -559,6 +559,12 @@ static bool signing_check_input(TxInputType *txinput) { tx_prevout_hash(&hashers[0], txinput); tx_sequence_hash(&hashers[1], txinput); if (coin->decred) { + if (txinput->decred_script_version > 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); + signing_abort(); + return false; + } + // serialize Decred prefix in Phase 1 resp.has_serialized = true; resp.serialized.has_serialized_tx = true; @@ -1037,6 +1043,11 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } + if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Decred script version does not match previous output")); + signing_abort(); + return; + } to_spend += tx->bin_outputs[0].amount; } if (idx2 < tp.outputs_len - 1) { From 95e5f15bde101490f146bb5d4c066deb824f2673 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 3 Apr 2018 15:25:06 +0100 Subject: [PATCH 0813/1154] vendor: Update trezor-crypto --- firmware/coins.c | 2 +- firmware/crypto.c | 18 +++++++++--------- firmware/signing.c | 30 +++++++++++++++--------------- firmware/transaction.c | 28 ++++++++++++---------------- firmware/transaction.h | 2 +- vendor/trezor-crypto | 2 +- 6 files changed, 39 insertions(+), 43 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 1600f9acbc..1acd8f5221 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -58,7 +58,7 @@ bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *ad { if (!addr) return false; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int len = base58_decode_check(addr, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); if (len >= 21) { return coinExtractAddressTypeRaw(coin, addr_raw, address_type); } diff --git a/firmware/crypto.c b/firmware/crypto.c index 4ff322c250..2830f7b010 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -92,7 +92,7 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out) int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) { signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign(node, message, message_len, signature + 1, NULL, NULL); + return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, NULL, NULL); } int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) @@ -101,7 +101,7 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); if (ed25519_curve_info && node->curve == ed25519_curve_info) { // GPG supports variable size digest for Ed25519 signatures - return hdnode_sign(node, message, message_len, signature + 1, NULL, NULL); + return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL); } else { // Ensure 256-bit digest before proceeding if (message_len != 32) { @@ -113,13 +113,13 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_type); + hasher_Init(&hasher, coin->curve->hasher_sign); hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); uint8_t varint[5]; uint32_t l = ser_length(message_len, varint); hasher_Update(&hasher, varint, l); hasher_Update(&hasher, message, message_len); - hasher_Double(&hasher, hash); + hasher_Final(&hasher, hash); } int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) @@ -177,8 +177,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - size_t len = base58_decode_check(address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_type, recovered_raw); + size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_pubkey, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type) + 20) { return 2; @@ -186,8 +186,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes } else // segwit-in-p2sh if (signature[0] >= 35 && signature[0] <= 38) { - size_t len = base58_decode_check(address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_type, recovered_raw); + size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_pubkey, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { return 2; @@ -201,7 +201,7 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { return 4; } - ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_type, addr_raw); + ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) { return 2; diff --git a/firmware/signing.c b/firmware/signing.c index bf5d87e0ce..8b34e10b83 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -362,8 +362,8 @@ void phase1_request_next_input(void) send_req_1_input(); } else { // compute segwit hashPrevouts & hashSequence - hasher_Double(&hashers[0], hash_prevouts); - hasher_Double(&hashers[1], hash_sequence); + hasher_Final(&hashers[0], hash_prevouts); + hasher_Final(&hashers[1], hash_sequence); hasher_Final(&hashers[2], hash_check); // init hashOutputs hasher_Reset(&hashers[0]); @@ -463,7 +463,7 @@ bool compile_input_script_sig(TxInputType *tinput) tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), tinput->script_sig.bytes); } else { // SPENDADDRESS uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_type, hash); + ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_pubkey, hash); tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); } return tinput->script_sig.size > 0; @@ -506,23 +506,23 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; to.decred_expiry = msg->decred_expiry; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; ti.decred_expiry = msg->decred_expiry; } // segwit hashes for hashPrevouts and hashSequence - hasher_Init(&hashers[0], coin->curve->hasher_type); - hasher_Init(&hashers[1], coin->curve->hasher_type); - hasher_Init(&hashers[2], coin->curve->hasher_type); + hasher_Init(&hashers[0], coin->curve->hasher_sign); + hasher_Init(&hashers[1], coin->curve->hasher_sign); + hasher_Init(&hashers[2], coin->curve->hasher_sign); layoutProgressSwipe(_("Signing transaction"), 0); @@ -718,7 +718,7 @@ static void phase1_request_next_output(void) { // compute Decred hashPrefix tx_hash_final(&ti, hash_prefix, false); } - hasher_Double(&hashers[0], hash_outputs); + hasher_Final(&hashers[0], hash_outputs); if (!signing_check_fee()) { return; } @@ -748,7 +748,7 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { hasher_Update(&hashers[0], hash_outputs, 32); hasher_Update(&hashers[0], (const uint8_t*) &lock_time, 4); hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); - hasher_Double(&hashers[0], hash); + hasher_Final(&hashers[0], hash); } static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { @@ -797,7 +797,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, static bool signing_sign_input(void) { uint8_t hash[32]; - hasher_Double(&hashers[0], hash); + hasher_Final(&hashers[0], hash); if (memcmp(hash, hash_outputs, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); @@ -1000,7 +1000,7 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_META: - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_type); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_sign); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; @@ -1084,7 +1084,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); hasher_Reset(&hashers[0]); } // check prevouts and script type @@ -1279,12 +1279,12 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx1 == 0) { // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); to.is_decred = true; } // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_type); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 1237da7d05..5a544a9271 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -131,11 +131,11 @@ bool compute_address(const CoinInfo *coin, raw[0] = 0; // push version raw[1] = 32; // push 32 bytes memcpy(raw+2, digest, 32); // push hash - hasher_Raw(coin->curve->hasher_type, raw, 34, digest); + hasher_Raw(coin->curve->hasher_pubkey, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_type, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { return 0; } } else { @@ -143,7 +143,7 @@ bool compute_address(const CoinInfo *coin, prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_type, address, MAX_ADDR_SIZE)) { + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { return 0; } } @@ -152,7 +152,7 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_segwit || !coin->bech32_prefix) { return 0; } - ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_type, digest); + ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest); if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { return 0; } @@ -164,9 +164,9 @@ bool compute_address(const CoinInfo *coin, if (!coin->has_address_type_p2sh) { return 0; } - ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_type, address, MAX_ADDR_SIZE); + ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); } else { - ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_type, address, MAX_ADDR_SIZE); + ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); } return 1; } @@ -232,7 +232,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T return 0; // failed to compile output } - addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); size_t prefix_len; if (coin->has_address_type // p2pkh && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) @@ -327,7 +327,7 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem if (n < 1 || n > 15) return 0; Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_type); + hasher_Init(&hasher, coin->curve->hasher_pubkey); uint8_t d[2]; d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); @@ -650,7 +650,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_type) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_sign) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; @@ -664,16 +664,12 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->is_segwit = false; tx->is_decred = false; tx->decred_expiry = 0; - hasher_Init(&(tx->hasher), hasher_type); + hasher_Init(&(tx->hasher), hasher_sign); } void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { - if (t->is_decred) { - hasher_Final(&(t->hasher), hash); - } else { - hasher_Double(&(t->hasher), hash); - } + hasher_Final(&(t->hasher), hash); if (!reverse) return; for (uint8_t i = 0; i < 16; i++) { uint8_t k = hash[31 - i]; @@ -744,7 +740,7 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { output_script_size = 2 + addr_raw_len; } else { - addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_type, addr_raw, MAX_ADDR_RAW_SIZE); + addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { output_script_size = TXSIZE_P2PKHASH; diff --git a/firmware/transaction.h b/firmware/transaction.h index 8177a9655a..4363a3b2c4 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -68,7 +68,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_type); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_sign); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index bb4c3d0525..b9043659c5 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit bb4c3d052561bd31856a03d975ca226571f6a893 +Subproject commit b9043659c5c91180c4abfb3ebb603f7b0385f201 From 8bdf338f32a881d5712a138e6c2d667c035264cc Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 3 Apr 2018 15:27:53 +0100 Subject: [PATCH 0814/1154] coins-gen: Remove obsolete script --- firmware/coins-gen.py | 75 ------------------------------------------- 1 file changed, 75 deletions(-) delete mode 100755 firmware/coins-gen.py diff --git a/firmware/coins-gen.py b/firmware/coins-gen.py deleted file mode 100755 index a184ccd96a..0000000000 --- a/firmware/coins-gen.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import json, sys - -coins_json = json.load(open('coins.json', 'r')) - -coins_stable, coins_debug = [], [] - -if len(sys.argv) != 2 or sys.argv[1] not in ("count", "array"): - print("usage: coins-gen.py [count|array]\n", file=sys.stderr) - sys.exit(1) - - -def get_fields(coin): - return [ - '"%s"' % coin['coin_name'] if coin['coin_name'] is not None else 'NULL', - '" %s"' % coin['coin_shortcut'] if coin['coin_shortcut'] is not None else 'NULL', - '%d' % coin['maxfee_kb'] if coin['maxfee_kb'] is not None else '0', - '"\\x%02x" "%s"' % (len(coin['signed_message_header']), coin['signed_message_header'].replace('\n', '\\n')) if coin['signed_message_header'] is not None else 'NULL', - 'true' if coin['address_type'] is not None else 'false', - 'true' if coin['address_type_p2sh'] is not None else 'false', - 'true' if coin['segwit'] else 'false', - 'true' if coin['forkid'] is not None else 'false', - 'true' if coin['force_bip143'] else 'false', - '%d' % coin['address_type'] if coin['address_type'] is not None else '0', - '%d' % coin['address_type_p2sh'] if coin['address_type_p2sh'] is not None else '0', - '0x%s' % coin['xpub_magic'] if coin['xpub_magic'] is not None else '0x00000000', - '0x%s' % coin['xprv_magic'] if coin['xprv_magic'] is not None else '0x00000000', - '%d' % coin['forkid'] if coin['forkid'] else '0', - '"%s"' % coin['bech32_prefix'] if coin.get('bech32_prefix') is not None else 'NULL', - '0x%08x' % (0x80000000 + coin['bip44']), - '%s_NAME' % 'secp256k1'.upper(), - '&%s_info' % 'secp256k1', - ] - - -def justify_width(coins): - for j in range(len(coins[0])): - l = max([len(x[j]) for x in coins]) + 1 - for i in range(len(coins)): - if coins[i][j][0] in '0123456789': - coins[i][j] = (coins[i][j] + ',').rjust(l) - else: - coins[i][j] = (coins[i][j] + ',').ljust(l) - - -for coin in coins_json: - if coin['firmware'] == 'stable': - coins_stable.append(get_fields(coin)) - if coin['firmware'] == 'debug': - coins_debug.append(get_fields(coin)) - -justify_width(coins_stable) -justify_width(coins_debug) - -print("// THIS IS A GENERATED FILE - DO NOT HAND EDIT\n\n") - -if sys.argv[1] == "array": - for row in coins_stable: - print('\t{' + ' '.join(row) + ' },') - - print('#if DEBUG_LINK') - - for row in coins_debug: - print('\t{' + ' '.join(row) + ' },') - - print('#endif') - - -if sys.argv[1] == "count": - print('#if DEBUG_LINK') - print('#define COINS_COUNT %d' % (len(coins_stable) + len(coins_debug))) - print('#else') - print('#define COINS_COUNT %d' % (len(coins_stable))) - print('#endif') From 2553fdb11fee7f806a202b3dfcd309cf72d2e7b8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 3 Apr 2018 20:27:24 +0200 Subject: [PATCH 0815/1154] update submodules --- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- vendor/trezor-qrenc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 0924bd6826..66a85673ed 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0924bd6826bb63f66010e2e511356d54ea733df3 +Subproject commit 66a85673ed303f2cf48bdb3d027adbc7e8464364 diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b9043659c5..b0af159096 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b9043659c5c91180c4abfb3ebb603f7b0385f201 +Subproject commit b0af15909649a311c2af3c4d559fcdbbfc21220d diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc index 91115b1806..4da44cacb7 160000 --- a/vendor/trezor-qrenc +++ b/vendor/trezor-qrenc @@ -1 +1 @@ -Subproject commit 91115b1806aa506d819c0063893984a28a5ae3a5 +Subproject commit 4da44cacb7bd69aa297bafe4a41c498a050225a4 From 987b686f63e5713855fbf49a9cc53b86a0448d18 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 13 Mar 2018 12:35:49 +0200 Subject: [PATCH 0816/1154] storage: allow auto-lock delay configuration --- firmware/storage.c | 16 ++++++++++++++-- firmware/storage.h | 4 ++++ firmware/trezor.c | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index fbcd5559fd..9d99f07e33 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -173,8 +173,8 @@ bool storage_from_flash(void) // added flags and needsBackup old_storage_size = OLD_STORAGE_SIZE(flags); } else if (version <= 9) { - // added u2froot - old_storage_size = OLD_STORAGE_SIZE(u2froot); + // added u2froot and auto_lock_delay_ms + old_storage_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); } // erase newly added fields @@ -868,6 +868,18 @@ void storage_setU2FCounter(uint32_t u2fcounter) storageUpdate.u2f_counter = u2fcounter - storage_u2f_offset; } +uint32_t storage_getAutoLockDelayMs() +{ + return storageRom->has_auto_lock_delay_ms ? storageRom->auto_lock_delay_ms : (10*60*1000U); +} + +void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) +{ + storageUpdate.has_auto_lock_delay_ms = true; + auto_lock_delay_ms = MAX(auto_lock_delay_ms, 60*1000U); + storageUpdate.auto_lock_delay_ms = auto_lock_delay_ms; +} + void storage_wipe(void) { session_clear(true); diff --git a/firmware/storage.h b/firmware/storage.h index 8e19153540..a0cf0750ba 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -72,6 +72,7 @@ typedef struct _Storage { STORAGE_BOOL (needs_backup) STORAGE_UINT32 (flags) STORAGE_NODE (u2froot) + STORAGE_UINT32 (auto_lock_delay_ms) } Storage; extern Storage storageUpdate; @@ -141,6 +142,9 @@ void storage_setNeedsBackup(bool needs_backup); void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); +uint32_t storage_getAutoLockDelayMs(void); +void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); + void storage_wipe(void); extern char storage_uuid_str[25]; diff --git a/firmware/trezor.c b/firmware/trezor.c index 7a008d20b8..9737733fed 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -74,9 +74,9 @@ void check_lock_screen(void) } } - // if homescreen is shown for longer than 10 minutes, lock too + // if homescreen is shown for too long if (layoutLast == layoutHome) { - if ((timer_ms() - system_millis_lock_start) >= 600000) { + if ((timer_ms() - system_millis_lock_start) >= storage_getAutoLockDelayMs()) { // lock the screen session_clear(true); layoutScreensaver(); From 159df8d24fef47ab59f5092c576aadcdde3dbf63 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Tue, 13 Mar 2018 14:51:08 +0200 Subject: [PATCH 0817/1154] fsm: allow auto-lock delay configuration --- firmware/fsm.c | 15 ++++++++++++++- vendor/trezor-common | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 6616b9e3e7..9389506055 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -635,7 +635,8 @@ void fsm_msgClearSession(ClearSession *msg) void fsm_msgApplySettings(ApplySettings *msg) { - CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen, _("No setting provided")); + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, + _("No setting provided")); CHECK_PIN @@ -672,6 +673,15 @@ void fsm_msgApplySettings(ApplySettings *msg) } } + if (msg->has_auto_lock_delay_ms) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_label) { storage_setLabel(msg->label); } @@ -684,6 +694,9 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_homescreen) { storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } + if (msg->has_auto_lock_delay_ms) { + storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); + } storage_update(); fsm_sendSuccess(_("Settings applied")); layoutHome(); diff --git a/vendor/trezor-common b/vendor/trezor-common index 66a85673ed..260747dfa4 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 66a85673ed303f2cf48bdb3d027adbc7e8464364 +Subproject commit 260747dfa44ab77cd1e9f27f16db116eed0b45fc From 3a908d7c7da1fd7f64ff0d49f26f75b9bea10803 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Apr 2018 01:08:39 +0200 Subject: [PATCH 0818/1154] fsm: update storage after ApplyFlags --- firmware/fsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 9389506055..5e25533540 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -706,6 +706,7 @@ void fsm_msgApplyFlags(ApplyFlags *msg) { if (msg->has_flags) { storage_applyFlags(msg->flags); + storage_update(); } fsm_sendSuccess(_("Flags applied")); } From 27443a06c82e0c309a88820c97ab3c494f8699f7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Apr 2018 01:13:19 +0200 Subject: [PATCH 0819/1154] protob: add limit for DebugLinkDecision.input --- firmware/protob/messages.options | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index a34b9f9d8a..69aa927297 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -188,6 +188,8 @@ SelfTest skip_message:true # used only in debug firmware +DebugLinkDecision.input max_size:33 + DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 DebugLinkState.matrix max_size:10 From 399706ae22b425c2775e3330ceccdf5ed216521e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Apr 2018 12:42:52 +0200 Subject: [PATCH 0820/1154] storage: implement unfinished_backup flag --- firmware/fsm.c | 1 + firmware/layout2.c | 4 ++++ firmware/reset.c | 3 +++ firmware/storage.c | 14 +++++++++++++- firmware/storage.h | 4 ++++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index 5e25533540..3a9593c8b5 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -313,6 +313,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); + resp->unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); diff --git a/firmware/layout2.c b/firmware/layout2.c index b56f787db9..3c17174d43 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -230,6 +230,10 @@ void layoutHome(void) oledDrawBitmap(40, 0, &bmp_logo64); } } + if (storage_unfinishedBackup()) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD); + } else if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); diff --git a/firmware/reset.c b/firmware/reset.c index e44370ee78..332463b93c 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -113,6 +113,7 @@ void reset_backup(bool separated) return; } + storage_setUnfinishedBackup(true); storage_setNeedsBackup(false); if (separated) { @@ -148,6 +149,8 @@ void reset_backup(bool separated) } } + storage_setUnfinishedBackup(false); + if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { diff --git a/firmware/storage.c b/firmware/storage.c index 9d99f07e33..3aaed0e472 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -173,7 +173,7 @@ bool storage_from_flash(void) // added flags and needsBackup old_storage_size = OLD_STORAGE_SIZE(flags); } else if (version <= 9) { - // added u2froot and auto_lock_delay_ms + // added u2froot, unfinished_backup and auto_lock_delay_ms old_storage_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); } @@ -830,6 +830,18 @@ void storage_setNeedsBackup(bool needs_backup) storageUpdate.needs_backup = needs_backup; } +bool storage_unfinishedBackup(void) +{ + return storageUpdate.has_unfinished_backup ? storageUpdate.unfinished_backup + : storageRom->has_unfinished_backup && storageRom->unfinished_backup; +} + +void storage_setUnfinishedBackup(bool unfinished_backup) +{ + storageUpdate.has_unfinished_backup = true; + storageUpdate.unfinished_backup = unfinished_backup; +} + void storage_applyFlags(uint32_t flags) { if ((storageRom->flags | flags) == storageRom->flags) { diff --git a/firmware/storage.h b/firmware/storage.h index a0cf0750ba..f0aabe9ca6 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -72,6 +72,7 @@ typedef struct _Storage { STORAGE_BOOL (needs_backup) STORAGE_UINT32 (flags) STORAGE_NODE (u2froot) + STORAGE_BOOL (unfinished_backup) STORAGE_UINT32 (auto_lock_delay_ms) } Storage; @@ -139,6 +140,9 @@ void storage_setImported(bool imported); bool storage_needsBackup(void); void storage_setNeedsBackup(bool needs_backup); +bool storage_unfinishedBackup(void); +void storage_setUnfinishedBackup(bool unfinished_backup); + void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); From 7b1b9d306961db7bb6a2873f57a93a9d47d13aae Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 4 Apr 2018 11:21:37 +0200 Subject: [PATCH 0821/1154] nem: IV is not copied The IV copy was moved to trezor-crypto (https://github.com/trezor/trezor-crypto/pull/140) so it is not needed in trezor-mcu anymore --- firmware/nem2.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/firmware/nem2.c b/firmware/nem2.c index d26f9cc2c8..216791a56f 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -264,11 +264,8 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM random_buffer(encrypted, NEM_SALT_SIZE + AES_BLOCK_SIZE); - // hdnode_nem_encrypt mutates the IV - uint8_t iv[AES_BLOCK_SIZE]; - memcpy(iv, &encrypted[NEM_SALT_SIZE], AES_BLOCK_SIZE); - const uint8_t *salt = encrypted; + const uint8_t *iv = &encrypted[NEM_SALT_SIZE]; uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE]; bool ret = hdnode_nem_encrypt(node, From 5633207a4384c7ab90d648a7c3e3604415ccc82d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Apr 2018 14:00:11 +0200 Subject: [PATCH 0822/1154] bump bootloader version to 1.5.0, firmware version to 1.7.0 --- bootloader/bootloader.h | 4 ++-- firmware/trezor.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 064f270ee2..7e79ae1c01 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,14 +21,14 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 4 +#define VERSION_MINOR 5 #define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x04" +#define VERSION_MINOR_CHAR "\x05" #define VERSION_PATCH_CHAR "\x00" #include diff --git a/firmware/trezor.h b/firmware/trezor.h index d40a10e29c..20fcfc481e 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,8 +23,8 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 6 -#define VERSION_PATCH 1 +#define VERSION_MINOR 7 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 8851863f8110e18012f34c26b37d294128dbd087 Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 4 Apr 2018 16:03:12 +0200 Subject: [PATCH 0823/1154] emulator: open a second socket for debuglink, same as T2 --- emulator/emulator.h | 4 +-- emulator/udp.c | 78 +++++++++++++++++++++++++++++++++------------ firmware/udp.c | 25 ++++++++++----- 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/emulator/emulator.h b/emulator/emulator.h index abb41355a9..ae05f6f9ff 100644 --- a/emulator/emulator.h +++ b/emulator/emulator.h @@ -30,8 +30,8 @@ void emulatorPoll(void); void emulatorRandom(void *buffer, size_t size); void emulatorSocketInit(void); -size_t emulatorSocketRead(void *buffer, size_t size); -size_t emulatorSocketWrite(const void *buffer, size_t size); +size_t emulatorSocketRead(int *iface, void *buffer, size_t size); +size_t emulatorSocketWrite(int iface, const void *buffer, size_t size); #endif diff --git a/emulator/udp.c b/emulator/udp.c index b01ec66b67..b7b18a914c 100644 --- a/emulator/udp.c +++ b/emulator/udp.c @@ -26,33 +26,50 @@ #define TREZOR_UDP_PORT 21324 -static int fd = -1; -static struct sockaddr_in from; -static socklen_t fromlen; +struct usb_socket { + int fd; + struct sockaddr_in from; + socklen_t fromlen; +}; -void emulatorSocketInit(void) { - fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); +static struct usb_socket usb_main; +static struct usb_socket usb_debug; + +static int socket_setup(int port) { + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { perror("Failed to create socket"); exit(1); } - fromlen = 0; - struct sockaddr_in addr; addr.sin_family = AF_INET; - addr.sin_port = htons(TREZOR_UDP_PORT); + addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { perror("Failed to bind socket"); exit(1); } + + return fd; } -size_t emulatorSocketRead(void *buffer, size_t size) { - fromlen = sizeof(from); - ssize_t n = recvfrom(fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen); +static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t size) { + if (sock->fromlen > 0) { + ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &sock->from, sock->fromlen); + if (n < 0 || ((size_t) n) != size) { + perror("Failed to write socket"); + return 0; + } + } + + return size; +} + +static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) { + sock->fromlen = sizeof(sock->from); + ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &sock->from, &sock->fromlen); if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { @@ -65,21 +82,42 @@ size_t emulatorSocketRead(void *buffer, size_t size) { static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { - emulatorSocketWrite(msg_pong, sizeof(msg_pong)); + socket_write(sock, msg_pong, sizeof(msg_pong)); return 0; } return n; } -size_t emulatorSocketWrite(const void *buffer, size_t size) { - if (fromlen > 0) { - ssize_t n = sendto(fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &from, fromlen); - if (n < 0 || ((size_t) n) != size) { - perror("Failed to write socket"); - return 0; - } +void emulatorSocketInit(void) { + usb_main.fd = socket_setup(TREZOR_UDP_PORT); + usb_main.fromlen = 0; + usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); + usb_debug.fromlen = 0; +} + +size_t emulatorSocketRead(int *iface, void *buffer, size_t size) { + size_t n = socket_read(&usb_main, buffer, size); + if (n > 0) { + *iface = 0; + return n; } - return size; + n = socket_read(&usb_debug, buffer, size); + if (n > 0) { + *iface = 1; + return n; + } + + return 0; +} + +size_t emulatorSocketWrite(int iface, const void *buffer, size_t size) { + if (iface == 0) { + return socket_write(&usb_main, buffer, size); + } + if (iface == 1) { + return socket_write(&usb_debug, buffer, size); + } + return 0; } diff --git a/firmware/udp.c b/firmware/udp.c index 04959aede4..75c3e08a35 100644 --- a/firmware/udp.c +++ b/firmware/udp.c @@ -23,6 +23,7 @@ #include "messages.h" #include "timer.h" +#include "debug.h" static volatile char tiny = 0; @@ -30,29 +31,37 @@ void usbInit(void) { emulatorSocketInit(); } +#if DEBUG_LINK +#define _ISDBG (((iface == 1) ? 'd' : 'n')) +#else +#define _ISDBG ('n') +#endif + void usbPoll(void) { emulatorPoll(); static uint8_t buffer[64]; - if (emulatorSocketRead(buffer, sizeof(buffer)) > 0) { + + int iface = 0; + if (emulatorSocketRead(&iface, buffer, sizeof(buffer)) > 0) { if (!tiny) { - msg_read(buffer, sizeof(buffer)); + msg_read_common(_ISDBG, buffer, sizeof(buffer)); } else { msg_read_tiny(buffer, sizeof(buffer)); } } const uint8_t *data = msg_out_data(); + if (data != NULL) { + emulatorSocketWrite(0, data, 64); + } #if DEBUG_LINK - if (data == NULL) { - data = msg_debug_out_data(); + data = msg_debug_out_data(); + if (data != NULL) { + emulatorSocketWrite(1, data, 64); } #endif - - if (data != NULL) { - emulatorSocketWrite(data, 64); - } } char usbTiny(char set) { From 9c9b4bf5cb56dedb28f1c447b77922b178918ba1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 4 Apr 2018 16:49:04 +0200 Subject: [PATCH 0824/1154] messages: code cleanup after emulator change --- firmware/messages.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 653ae7f417..4638057a88 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -48,12 +48,7 @@ const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { -#if EMULATOR - (void) type; - if (dir == m->dir && msg_id == m->msg_id) { -#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { -#endif return m->fields; } m++; @@ -65,12 +60,7 @@ void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) { const struct MessagesMap_t *m = MessagesMap; while (m->type) { -#if EMULATOR - (void) type; - if (dir == m->dir && msg_id == m->msg_id) { -#else if (type == m->type && dir == m->dir && msg_id == m->msg_id) { -#endif m->process_func(ptr); return; } From f2163289872875886d73ba32e90cf391b2ffbd10 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 4 Apr 2018 17:50:20 +0200 Subject: [PATCH 0825/1154] Fix initialisation of word_pincode --- firmware/recovery.c | 49 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/firmware/recovery.c b/firmware/recovery.c index b01e510c7d..8990f29092 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -90,6 +90,29 @@ static uint16_t word_pincode; */ static uint8_t word_matrix[9]; +/* The words are stored in two tables. + * + * The low bits of the first table (TABLE1) store the index into the + * second table, for each of the 81 choices for the first two levels + * of the matrix. The final entry points to the final entry of the + * second table. The difference TABLE1(idx+1)-TABLE1(idx) gives the + * number of choices for the third level. The value + * TABLE2(TABLE1(idx)) gives the index of the first word in the range + * and TABLE2(TABLE1(idx+1))-1 gives the index of the last word. + * + * The low bits of the second table (TABLE2) store the index into the + * word list for each of the choices for the first three levels. The + * final entry stores the value 2048 (number of bip39 words). table. + * The difference TABLE2(idx+1)-TABLE2(idx) gives the number of + * choices for the last level. The value TABLE2(idx) gives the index + * of the first word in the range and TABLE2(idx)-1 gives the index of + * the last word. + * + * The high bits in each table is the "prefix length", i.e. the number + * of significant letters for the corresponding choice. There is no + * prefix length or table for the very first level, as the prefix length + * is always one and there are always nine choices on the second level. + */ #define MASK_IDX(x) ((x) & 0xfff) #define TABLE1(x) MASK_IDX(word_table1[x]) #define TABLE2(x) MASK_IDX(word_table2[x]) @@ -199,7 +222,7 @@ static void recovery_done(void) { * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. */ static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { - // assert prefixlen < 4 + // assert 1 <= prefixlen <= 4 char *dest = choice; for (int i = 0; i < prefixlen; i++) { *dest++ = toupper((int) first[i]); @@ -293,17 +316,28 @@ static void next_matrix(void) { uint32_t idx, num; bool last = (word_index % 4) == 3; + /* Build the matrix: + * num: number of choices + * word_choices[][]: the strings containing the choices + */ switch (word_index % 4) { case 3: + /* last level: show up to six words */ + /* idx: index in table2 for the entered choice. */ + /* first: the first word. */ + /* num: the number of words to choose from. */ idx = TABLE1(word_pincode / 9) + word_pincode % 9; - const uint32_t first = word_table2[idx] & 0xfff; - num = (word_table2[idx + 1] & 0xfff) - first; + const uint32_t first = TABLE2(idx); + num = TABLE2(idx + 1) - first; for (uint32_t i = 0; i < num; i++) { strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); } break; case 2: + /* third level: show up to nine ranges (using table2) */ + /* idx: first index in table2 corresponding to pin code. */ + /* num: the number of choices. */ idx = TABLE1(word_pincode); num = TABLE1(word_pincode + 1) - idx; for (uint32_t i = 0; i < num; i++) { @@ -314,6 +348,9 @@ static void next_matrix(void) { break; case 1: + /* second level: exactly nine ranges (using table1) */ + /* idx: first index in table1 corresponding to pin code. */ + /* num: the number of choices. */ idx = word_pincode * 9; num = 9; for (uint32_t i = 0; i < num; i++) { @@ -324,6 +361,8 @@ static void next_matrix(void) { break; case 0: + /* first level: exactly nine ranges */ + /* num: the number of choices. */ num = 9; for (uint32_t i = 0; i < num; i++) { add_choice(word_choices[i], 1, @@ -364,12 +403,15 @@ static void recovery_digit(const char digit) { int choice = word_matrix[digit - '1']; if ((word_index % 4) == 3) { /* received final word */ + + /* Mark the chosen word for 250 ms */ int y = 54 - ((digit - '1')/3)*11; int x = 64 * (((digit - '1') % 3) > 0); oledInvert(x + 1, y, x + 62, y + 9); oledRefresh(); usbSleep(250); + /* index of the chosen word */ int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; uint32_t widx = word_index / 4; @@ -430,6 +472,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { awaiting_word = 2; word_index = 0; + word_pincode = 0; next_matrix(); } else { for (uint32_t i = 0; i < word_count; i++) { From e1ad1512d09590dbcf6c7fdb8893bc71f99d0d26 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 4 Apr 2018 17:51:13 +0200 Subject: [PATCH 0826/1154] Avoid division by zero. Check that there is no overflow in `inputs_count + outputs_count`. Check that previous transaction contains at least the spent output. --- firmware/fsm.c | 1 + firmware/signing.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index 3a9593c8b5..cacf44d1a8 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -534,6 +534,7 @@ void fsm_msgSignTx(SignTx *msg) CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); + CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); CHECK_PIN diff --git a/firmware/signing.c b/firmware/signing.c index 8b34e10b83..9ec43cfd35 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -1000,6 +1000,16 @@ void signing_txack(TransactionType *tx) } return; case STAGE_REQUEST_2_PREV_META: + if (tx->outputs_cnt <= input.prev_index) { + fsm_sendFailure(FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); + signing_abort(); + return; + } + if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_sign); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); From cb6022ce04ea70521ec94a8a62eb4a291e134cad Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 4 Jan 2018 20:18:34 +0100 Subject: [PATCH 0827/1154] Added support for cashaddr. --- firmware/Makefile | 1 + firmware/coin_info.py | 1 + firmware/coins.h | 1 + firmware/transaction.c | 49 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 88fa9ace0b..8aaae3854c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -58,6 +58,7 @@ OBJS += ../vendor/trezor-crypto/pbkdf2.o OBJS += ../vendor/trezor-crypto/base32.o OBJS += ../vendor/trezor-crypto/base58.o OBJS += ../vendor/trezor-crypto/segwit_addr.o +OBJS += ../vendor/trezor-crypto/cash_addr.o OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o diff --git a/firmware/coin_info.py b/firmware/coin_info.py index 509d06c152..a84e8e4588 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -91,6 +91,7 @@ def coin_to_struct(coin): ("xprv_magic", format_hex(coin["xprv_magic"])), ("forkid", format_number(coin["forkid"])), ("bech32_prefix", format_string(coin["bech32_prefix"])), + ("cashaddr_prefix", format_string(coin["cashaddr_prefix"])), ("coin_type", "({} | 0x80000000)".format(format_number(coin["bip44"]))), # noqa: E501 ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 ("curve", "&{}_info".format(coin["curve_name"])), diff --git a/firmware/coins.h b/firmware/coins.h index 2cdd657240..a344c17845 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -44,6 +44,7 @@ typedef struct _CoinInfo { uint32_t xprv_magic; uint32_t forkid; const char *bech32_prefix; + const char *cashaddr_prefix; uint32_t coin_type; const char *curve_name; const curve_info *curve; diff --git a/firmware/transaction.c b/firmware/transaction.c index 5a544a9271..ef025c8b7d 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -32,9 +32,14 @@ #include "messages.pb.h" #include "types.pb.h" #include "segwit_addr.h" +#include "cash_addr.h" #define SEGWIT_VERSION_0 0 +#define CASHADDR_P2KH (0) +#define CASHADDR_P2SH (8) +#define CASHADDR_160 (0) + /* transaction input size (without script): 32 prevhash, 4 idx, 4 sequence */ #define TXSIZE_INPUT 40 /* transaction output size (without script): 8 amount */ @@ -138,6 +143,12 @@ bool compute_address(const CoinInfo *coin, if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { return 0; } + } else if (coin->cashaddr_prefix) { + raw[0] = CASHADDR_P2SH | CASHADDR_160; + ripemd160(digest, 32, raw + 1); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } } else { // non-segwit p2sh multisig prelen = address_prefix_bytes_len(coin->address_type_p2sh); @@ -165,6 +176,11 @@ bool compute_address(const CoinInfo *coin, return 0; } ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); + } else if (coin->cashaddr_prefix) { + ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_type, raw); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } } else { ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); } @@ -252,6 +268,28 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.size = 23; + } else if (coin->cashaddr_prefix + && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) { + if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + + } else if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else { + return 0; + } } else if (coin->bech32_prefix) { int witver; if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { @@ -736,7 +774,16 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; int witver; size_t addr_raw_len; - if (coin->bech32_prefix + if (coin->cashaddr_prefix + && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) { + if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (addr_raw_len == 21 + && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } else if (coin->bech32_prefix && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { output_script_size = 2 + addr_raw_len; } else { From 1e91f922710e7465d45297bb32fc098955fb3fd6 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 4 Jan 2018 20:54:22 +0100 Subject: [PATCH 0828/1154] Increased address size to 130. --- firmware/protob/messages.options | 10 +++++----- firmware/protob/types.options | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 69aa927297..4541c68ed4 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -41,7 +41,7 @@ PublicKey.xpub max_size:113 GetAddress.address_n max_count:8 GetAddress.coin_name max_size:21 -Address.address max_size:76 +Address.address max_size:130 EthereumGetAddress.address_n max_count:8 EthereumAddress.address max_size:20 @@ -65,12 +65,12 @@ SignMessage.address_n max_count:8 SignMessage.message max_size:1024 SignMessage.coin_name max_size:21 -VerifyMessage.address max_size:76 +VerifyMessage.address max_size:130 VerifyMessage.signature max_size:65 VerifyMessage.message max_size:1024 VerifyMessage.coin_name max_size:21 -MessageSignature.address max_size:76 +MessageSignature.address max_size:130 MessageSignature.signature max_size:65 EthereumSignMessage.address_n max_count:8 @@ -105,7 +105,7 @@ DecryptMessage skip_message:true # deprecated DecryptedMessage skip_message:true -# DecryptedMessage.address max_size:76 +# DecryptedMessage.address max_size:130 # DecryptedMessage.message max_size:1024 CipherKeyValue.address_n max_count:8 @@ -141,7 +141,7 @@ SignIdentity.challenge_hidden max_size:256 SignIdentity.challenge_visual max_size:256 SignIdentity.ecdsa_curve_name max_size:32 -SignedIdentity.address max_size:76 +SignedIdentity.address max_size:130 SignedIdentity.public_key max_size:33 SignedIdentity.signature max_size:65 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index e087cb0706..527e4fac73 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -12,7 +12,7 @@ TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 -TxOutputType.address max_size:76 +TxOutputType.address max_size:130 TxOutputType.address_n max_count:8 TxOutputType.op_return_data max_size:80 From 059555039cf5d0960047c7b0e57b4a28b0f44be2 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Wed, 7 Feb 2018 19:56:50 +0100 Subject: [PATCH 0829/1154] cashaddr: Don't show coin prefix on the display. While technically part of the address, the coin prefix, e.g., bitcoincash: is implicit and doesn't need to be checked by the user. We still include it in the QR-code though. Also set case-insensitive flag for QR-code. --- firmware/fsm.c | 16 +++++++++++----- firmware/layout2.c | 10 ++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index cacf44d1a8..d6e653efec 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -217,11 +217,15 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } -static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, const uint32_t *address_n, size_t address_n_count) +static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, size_t prefixlen, const uint32_t *address_n, size_t address_n_count) { bool qrcode = false; for (;;) { - layoutAddress(address, desc, qrcode, ignorecase, address_n, address_n_count); + const char* display_addr = address; + if (prefixlen && !qrcode) { + display_addr += prefixlen; + } + layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { return true; } @@ -835,7 +839,9 @@ void fsm_msgGetAddress(GetAddress *msg) } } - if (!fsm_layoutAddress(address, desc, msg->script_type == InputScriptType_SPENDWITNESS, msg->address_n, msg->address_n_count)) { + bool is_cashaddr = coin->cashaddr_prefix != NULL; + bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; + if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count)) { return; } } @@ -868,7 +874,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) char address[43] = { '0', 'x' }; ethereum_address_checksum(resp->address.bytes, address + 2); - if (!fsm_layoutAddress(address, desc, false, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { return; } } @@ -1293,7 +1299,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) strlcpy(desc, network, sizeof(desc)); strlcat(desc, ":", sizeof(desc)); - if (!fsm_layoutAddress(resp->address, desc, true, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { return; } } diff --git a/firmware/layout2.c b/firmware/layout2.c index 3c17174d43..9dd53368d4 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -250,6 +250,16 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); strlcat(str_out, " to", sizeof(str_out)); const char *addr = out->address; + if (coin->cashaddr_prefix) { + /* If this is a cashaddr address, remove the prefix from the + * string presented to the user + */ + int prefix_len = strlen(coin->cashaddr_prefix); + if (strncmp(addr, coin->cashaddr_prefix, prefix_len) == 0 + && addr[prefix_len] == ':') { + addr += prefix_len + 1; + } + } int addrlen = strlen(addr); int numlines = addrlen <= 42 ? 2 : 3; int linelen = (addrlen - 1) / numlines + 1; From 27702ea26a877290fa7b50dcbc35e13fcc14ba85 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 5 Apr 2018 11:56:25 +0200 Subject: [PATCH 0830/1154] fix build after cashaddr merge --- firmware/transaction.c | 2 +- vendor/trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index ef025c8b7d..03dcbfdac0 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -177,7 +177,7 @@ bool compute_address(const CoinInfo *coin, } ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); } else if (coin->cashaddr_prefix) { - ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_type, raw); + ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_pubkey, raw); if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { return 0; } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b0af159096..e81fb38ab4 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b0af15909649a311c2af3c4d559fcdbbfc21220d +Subproject commit e81fb38ab452f2170769e9c454b10caaf8869974 From 63a549aefbcfb7bec7a3332343364d77009a9cd9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 7 Apr 2018 17:08:03 +0100 Subject: [PATCH 0831/1154] coin_info: Prepend space to coin_shortcut --- firmware/coin_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/coin_info.py b/firmware/coin_info.py index a84e8e4588..6a6b119d6f 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -76,7 +76,7 @@ def prepend_varint(string): def coin_to_struct(coin): return collections.OrderedDict(( ("coin_name", format_string(coin["coin_name"])), - ("coin_shortcut", format_string(coin["coin_shortcut"])), + ("coin_shortcut", format_string(" " + coin["coin_shortcut"])), ("maxfee_kb", format_number(coin["maxfee_kb"])), ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 From 56ff88a08f6d7ec00157b9b0d778d1b7e9bce3b7 Mon Sep 17 00:00:00 2001 From: mcudev <29890609+mcudev@users.noreply.github.com> Date: Sat, 7 Apr 2018 20:13:46 -0400 Subject: [PATCH 0832/1154] update bootloader padding/alignment and integrate build process for bootloader and firmware --- README.md | 17 +++--------- bootloader/firmware_align.py | 2 +- build-bootloader.sh | 30 -------------------- build-firmware.sh | 34 ----------------------- build.sh | 53 ++++++++++++++++++++++++++++++++++++ firmware/bl_check.c | 2 ++ 6 files changed, 60 insertions(+), 78 deletions(-) delete mode 100755 build-bootloader.sh delete mode 100755 build-firmware.sh create mode 100755 build.sh diff --git a/README.md b/README.md index 8e8e1a8a64..75b0a110d4 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# TREZOR Firmware +# TREZOR One Bootloader and Firmware [![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community) https://trezor.io/ -## How to build TREZOR firmware? +## How to build the TREZOR bootloader and firmware? 1. [Install Docker](https://docs.docker.com/engine/installation/) 2. `git clone https://github.com/trezor/trezor-mcu.git` 3. `cd trezor-mcu` -4. `./build-firmware.sh TAG` (where TAG is v1.5.0 for example, if left blank the script builds latest commit in master branch) +4. `./build.sh BOOTLOADER_TAG FIRMWARE_TAG` (where BOOTLOADER_TAG is bl1.5.0 and FIRMWARE_TAG is v1.7.0 for example, if left blank the script builds latest commit in master branch) -This creates file `build/trezor-TAG.bin` and prints its fingerprint and size at the end of the build log. +This creates the files `build/bootloader-BOOTLOADER_TAG.bin` and `build/trezor-FIRMWARE_TAG.bin` and prints their fingerprints and sizes at the end of the build log. ## How to build TREZOR emulator for Linux? @@ -22,15 +22,6 @@ This creates file `build/trezor-TAG.bin` and prints its fingerprint and size at This creates binary file `build/trezor-emulator-TAG`, which can be run and works as a trezor emulator. (Use `TREZOR_OLED_SCALE` env. variable to make screen bigger.) -## How to build TREZOR bootloader? - -1. [Install Docker](https://docs.docker.com/engine/installation/) -2. `git clone https://github.com/trezor/trezor-mcu.git` -3. `cd trezor-mcu` -4. `./build-bootloader.sh TAG` (where TAG is bl1.3.2 for example, if left blank the script builds latest commit in master branch) - -This creates file `build/bootloader-TAG.bin` and prints its fingerprint and size at the end of the build log. - ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? 1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/1/releases.json diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index b07bf0eb26..3d766862fc 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -7,5 +7,5 @@ fs = os.stat(fn).st_size if fs > 32768: raise Exception('bootloader has to be smaller than 32768 bytes') with open(fn, 'ab') as f: - f.write(b'\xFF' * (32768 - fs)) + f.write(b'\x00' * (32768 - fs)) f.close() diff --git a/build-bootloader.sh b/build-bootloader.sh deleted file mode 100755 index fe413566ac..0000000000 --- a/build-bootloader.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -set -e - -IMAGE=trezor-mcu-build -TAG=${1:-master} -BINFILE=build/bootloader-$TAG.bin -ELFFILE=build/bootloader-$TAG.elf - -docker build -t $IMAGE . -docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ - cd trezor-mcu && \ - git checkout $TAG && \ - git submodule update --init && \ - make -C vendor/libopencm3 && \ - make && \ - make -C bootloader align && \ - cp bootloader/bootloader.bin /$BINFILE && \ - cp bootloader/bootloader.elf /$ELFFILE" -/usr/bin/env python -c " -from __future__ import print_function -import hashlib -import sys -fn = sys.argv[1] -data = open(fn, 'rb').read() -print('\n\n') -print('Filename :', fn) -print('Fingerprint :', hashlib.sha256(hashlib.sha256(data).digest()).hexdigest()) -print('Size : %d bytes (out of %d maximum)' % (len(data), 32768)) -" $BINFILE diff --git a/build-firmware.sh b/build-firmware.sh deleted file mode 100755 index 86ae83fe61..0000000000 --- a/build-firmware.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -set -e - -IMAGE=trezor-mcu-build -TAG=${1:-master} -BINFILE=build/trezor-$TAG.bin -ELFFILE=build/trezor-$TAG.elf - -docker build -t $IMAGE . -docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ - cd trezor-mcu && \ - git checkout $TAG && \ - git submodule update --init && \ - make -C vendor/libopencm3 && \ - make -C vendor/nanopb/generator/proto && \ - make -C firmware/protob && \ - make && \ - make -C bootloader && \ - make -C firmware sign && \ - cp firmware/trezor.bin /$BINFILE && \ - cp firmware/trezor.elf /$ELFFILE" - -/usr/bin/env python -c " -from __future__ import print_function -import hashlib -import sys -fn = sys.argv[1] -data = open(fn, 'rb').read() -print('\n\n') -print('Filename :', fn) -print('Fingerprint :', hashlib.sha256(data[256:]).hexdigest()) -print('Size : %d bytes (out of %d maximum)' % (len(data), 491520)) -" $BINFILE diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..b62d226ae6 --- /dev/null +++ b/build.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -e + +IMAGE=trezor-mcu-build + +BOOTLOADER_TAG=${1:-master} +FIRMWARE_TAG=${2:-master} + +BOOTLOADER_BINFILE=build/bootloader-$BOOTLOADER_TAG.bin +BOOTLOADER_ELFFILE=build/bootloader-$BOOTLOADER_TAG.elf + +FIRMWARE_BINFILE=build/trezor-$FIRMWARE_TAG.bin +FIRMWARE_ELFFILE=build/trezor-$FIRMWARE_TAG.elf + +docker build -t $IMAGE . +docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ + cd /tmp && \ + git clone https://github.com/trezor/trezor-mcu.git trezor-mcu-bl && \ + cd trezor-mcu-bl && \ + git checkout $BOOTLOADER_TAG && \ + git submodule update --init --recursive && \ + make -C vendor/libopencm3 && \ + make && \ + make -C bootloader align && \ + cp bootloader/bootloader.bin /$BOOTLOADER_BINFILE && \ + cp bootloader/bootloader.elf /$BOOTLOADER_ELFFILE && \ + cd /tmp && \ + git clone https://github.com/trezor/trezor-mcu.git trezor-mcu-fw && \ + cd trezor-mcu-fw && \ + git checkout $FIRMWARE_TAG && \ + git submodule update --init --recursive && \ + make -C vendor/libopencm3 && \ + make -C vendor/nanopb/generator/proto && \ + make -C firmware/protob && \ + make && \ + cp /tmp/trezor-mcu-bl/bootloader/bootloader.bin bootloader/bootloader.bin + make -C firmware sign && \ + cp firmware/trezor.bin /$FIRMWARE_BINFILE && \ + cp firmware/trezor.elf /$FIRMWARE_ELFFILE + " + +/usr/bin/env python -c " +from __future__ import print_function +import hashlib +import sys +for arg in sys.argv[1:]: + (fn, max_size) = arg.split(':') + data = open(fn, 'rb').read() + print('\n\n') + print('Filename :', fn) + print('Fingerprint :', hashlib.sha256(hashlib.sha256(data).digest()).hexdigest()) + print('Size : %d bytes (out of %d maximum)' % (len(data), int(max_size, 10))) +" $BOOTLOADER_BINFILE:32768 $FIRMWARE_BINFILE:491520 diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 0d6b3bba09..5e945c1946 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -35,6 +35,8 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37", 32)) return 1; // 1.3.0b if (0 == memcmp(hash, "\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15", 32)) return 1; // 1.3.1 if (0 == memcmp(hash, "\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07", 32)) return 1; // 1.3.2 + // note to those verifying these values: bootloader versions above this comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions below are padded with 0x00. + // for more info, refer to "make -C bootloader align" and "firmware/bl_data.py". if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 return 0; From e907cb87bc0187a71588874effd56c0600434c0d Mon Sep 17 00:00:00 2001 From: mcudev <29890609+mcudev@users.noreply.github.com> Date: Sun, 8 Apr 2018 09:37:11 -0400 Subject: [PATCH 0833/1154] check_bootloader: depend on MEMORY_PROTECT --- firmware/bl_check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 5e945c1946..598bac276c 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -44,6 +44,7 @@ int known_bootloader(int r, const uint8_t *hash) { void check_bootloader(void) { +#if MEMORY_PROTECT uint8_t hash[32]; int r = memory_bootloader_hash(hash); @@ -57,7 +58,6 @@ void check_bootloader(void) return; } -#if 0 // ENABLE THIS AT YOUR OWN RISK // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK // YOUR DEVICE. From 14233fcc268f2d16192657420f7ac5df11b1056d Mon Sep 17 00:00:00 2001 From: mcudev <29890609+mcudev@users.noreply.github.com> Date: Mon, 9 Apr 2018 05:16:38 -0400 Subject: [PATCH 0834/1154] mpu_config: depend on MEMORY_PROTECT --- setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.c b/setup.c index f78c8ec619..15d497b4aa 100644 --- a/setup.c +++ b/setup.c @@ -163,6 +163,7 @@ void setupApp(void) // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) void mpu_config(void) { +#if MEMORY_PROTECT // Disable MPU MPU_CTRL = 0; @@ -206,4 +207,5 @@ void mpu_config(void) // Switch to unprivileged software execution to prevent access to MPU set_mode_unprivileged(); +#endif } From 783f1c0323013244a442778ae9b3cbec4e449a5b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Apr 2018 23:46:05 +0200 Subject: [PATCH 0835/1154] storage: refactor default/minimum lock storage, change default values --- firmware/storage.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index 3aaed0e472..743b21a010 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -882,13 +882,15 @@ void storage_setU2FCounter(uint32_t u2fcounter) uint32_t storage_getAutoLockDelayMs() { - return storageRom->has_auto_lock_delay_ms ? storageRom->auto_lock_delay_ms : (10*60*1000U); + const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes + return storageRom->has_auto_lock_delay_ms ? storageRom->auto_lock_delay_ms : default_delay_ms; } void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { + const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds + auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); storageUpdate.has_auto_lock_delay_ms = true; - auto_lock_delay_ms = MAX(auto_lock_delay_ms, 60*1000U); storageUpdate.auto_lock_delay_ms = auto_lock_delay_ms; } From 2a22d9140d9b2c287545ee619344ea42d17e1b4a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 11 Apr 2018 14:17:15 +0200 Subject: [PATCH 0836/1154] startup: shutdown at end instead of loop --- startup.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/startup.s b/startup.s index 5cd3d02608..59a87e1af0 100644 --- a/startup.s +++ b/startup.s @@ -33,8 +33,8 @@ reset_handler: // enter the application code bl main - // loop forever if the application code returns - b . + // shutdown if the application code returns + b shutdown .global shutdown .type shutdown, STT_FUNC From fabfe0661b805c930f0645009eb4946e488b89bc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Apr 2018 14:03:36 +0200 Subject: [PATCH 0837/1154] memory: use 1M for flash storage --- memory.h | 12 ++++++------ setup.c | 17 +++++++++-------- supervise.c | 2 +- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/memory.h b/memory.h index 99415604cf..a10a3b3bd3 100644 --- a/memory.h +++ b/memory.h @@ -39,10 +39,10 @@ Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | application code Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | application code ===========+=========================+============================ - Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | N/A - Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | N/A - Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | N/A - Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | N/A + Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | application code + Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | application code + Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | application code + Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | application code metadata area: @@ -73,7 +73,7 @@ extern uint8_t *emulator_flash_base; #define FLASH_PTR(x) (const uint8_t*) (x) #endif -#define FLASH_TOTAL_SIZE (512 * 1024) +#define FLASH_TOTAL_SIZE (1024 * 1024) #define FLASH_BOOT_START (FLASH_ORIGIN) #define FLASH_BOOT_LEN (0x8000) @@ -105,7 +105,7 @@ extern uint8_t *emulator_flash_base; #define FLASH_META_SECTOR_LAST 3 #define FLASH_CODE_SECTOR_FIRST 4 -#define FLASH_CODE_SECTOR_LAST 7 +#define FLASH_CODE_SECTOR_LAST 11 void memory_protect(void); void memory_write_unlock(void); diff --git a/setup.c b/setup.c index 15d497b4aa..0ab33badb6 100644 --- a/setup.c +++ b/setup.c @@ -142,15 +142,16 @@ void setupApp(void) } #define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_4KB (0x0bUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_8KB (0x0cUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_16KB (0x0dUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_32KB (0x0eUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_64KB (0x0fUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_512MB (0x1cUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html #define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) @@ -168,9 +169,9 @@ void mpu_config(void) MPU_CTRL = 0; // Note: later entries overwrite previous ones - // Flash (0x08000000 - 0x0807FFFF, 512 KiB, read-only, execute never) + // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRO_URO; + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRO_URO; // Metadata in Flash is read-write when unlocked // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) diff --git a/supervise.c b/supervise.c index 4a5967bdd0..3c21ea0e43 100644 --- a/supervise.c +++ b/supervise.c @@ -44,7 +44,7 @@ static void svhandler_flash_program(uint32_t psize) { } static void svhandler_flash_erase_sector(uint16_t sector) { - /* we only allow erasing meta sectors 2 and 3. */ + /* we only allow erasing meta sectors 2 and 3. */ if (sector < FLASH_META_SECTOR_FIRST || sector > FLASH_META_SECTOR_LAST) { return; From 757ab636e77bc2b96177a1005014871a6afff55f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 28 Apr 2018 14:01:33 +0100 Subject: [PATCH 0838/1154] gen: update trezor logo --- gen/bitmaps.c | 8 ++++---- gen/bitmaps/logo48.png | Bin 283 -> 280 bytes gen/bitmaps/logo48_empty.png | Bin 310 -> 312 bytes gen/bitmaps/logo64.png | Bin 317 -> 339 bytes gen/bitmaps/logo64_empty.png | Bin 444 -> 311 bytes 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gen/bitmaps.c b/gen/bitmaps.c index b86073fd2a..49a8691647 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -19,10 +19,10 @@ const uint8_t bmp_icon_info_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3e, const uint8_t bmp_icon_ok_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0xff, 0xef, 0xff, 0xdf, 0xff, 0xbf, 0xf9, 0x3f, 0xf8, 0x7f, 0xfc, 0xff, 0x7e, 0xfe, 0x3f, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, }; const uint8_t bmp_icon_question_data[] = { 0x07, 0xe0, 0x0f, 0xf0, 0x1e, 0x78, 0x3c, 0x3c, 0x79, 0x9e, 0xf3, 0xcf, 0xff, 0xcf, 0xff, 0x9f, 0xff, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0x7f, 0xfe, 0x3e, 0x7c, 0x1e, 0x78, 0x0f, 0xf0, 0x07, 0xe0, }; const uint8_t bmp_icon_warning_data[] = { 0x01, 0x80, 0x01, 0x80, 0x03, 0xc0, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0e, 0x70, 0x0e, 0x70, 0x1e, 0x78, 0x1e, 0x78, 0x3e, 0x7c, 0x3f, 0xfc, 0x7e, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, }; -const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0x81, 0xfc, 0x00, 0x00, 0x3e, 0x00, 0x7c, 0x00, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x00, 0x78, 0x00, 0x1e, 0x00, 0x00, 0xf8, 0x00, 0x1f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x00, 0x01, 0xf0, 0x0f, 0xe0, 0x00, 0x07, 0xf0, 0x0f, 0xfc, 0x00, 0x3f, 0xf0, 0x0f, 0xff, 0x81, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x81, 0x80, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x7e, 0x08, 0x00, 0x00, 0x21, 0x81, 0x84, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x22, 0x00, 0x00, 0x48, 0x00, 0x12, 0x00, 0x00, 0x88, 0x00, 0x11, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x03, 0x9f, 0xff, 0xf9, 0xc0, 0x04, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x3f, 0xff, 0xfc, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x60, 0x00, 0x06, 0x10, 0x08, 0x1c, 0x00, 0x38, 0x10, 0x08, 0x03, 0x81, 0xc0, 0x10, 0x07, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xc3, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x03, 0xf0, 0x0f, 0xf0, 0x00, 0x0f, 0xf0, 0x0f, 0xfc, 0x00, 0x3f, 0xf0, 0x0f, 0xff, 0x00, 0xff, 0xf0, 0x0f, 0xff, 0xc3, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x20, 0x3c, 0x04, 0x00, 0x00, 0x20, 0xc3, 0x04, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x00, 0x41, 0x00, 0x82, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x0f, 0xc3, 0xff, 0xc3, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x7f, 0xff, 0xfe, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x30, 0x00, 0x0c, 0x10, 0x08, 0x0c, 0x00, 0x30, 0x10, 0x08, 0x03, 0x00, 0xc0, 0x10, 0x0c, 0x00, 0xc3, 0x00, 0x30, 0x03, 0x00, 0x3c, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x00, 0x0c, 0x00, 0x30, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xf0, 0x0f, 0xfc, 0x00, 0x00, 0x3f, 0xe0, 0x07, 0xfc, 0x00, 0x00, 0x3f, 0xc0, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xfe, 0x00, 0x00, 0x7f, 0xf8, 0x1f, 0xff, 0x80, 0x01, 0xff, 0xf8, 0x1f, 0xff, 0xe0, 0x07, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0x07, 0xff, 0xfe, 0x7f, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x07, 0xe0, 0x10, 0x00, 0x00, 0x10, 0x08, 0x10, 0x08, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x20, 0x20, 0x04, 0x04, 0x00, 0x00, 0x20, 0x40, 0x02, 0x04, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x1f, 0xc0, 0xff, 0xff, 0x03, 0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3f, 0xff, 0xff, 0xfc, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x18, 0x00, 0x00, 0x18, 0x08, 0x10, 0x06, 0x00, 0x00, 0x60, 0x08, 0x10, 0x01, 0x80, 0x01, 0x80, 0x08, 0x10, 0x00, 0x60, 0x06, 0x00, 0x08, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x06, 0x00, 0x06, 0x60, 0x00, 0x60, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; const uint8_t bmp_u2f_bitfinex_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xa0, 0x00, 0x0f, 0xff, 0x20, 0x00, 0x3f, 0xff, 0x60, 0x00, 0x7f, 0xfe, 0xe0, 0x00, 0xff, 0xfc, 0xe0, 0x01, 0xff, 0xf1, 0xe0, 0x01, 0xff, 0xe3, 0xe0, 0x03, 0xff, 0xc7, 0xe0, 0x03, 0xff, 0x8f, 0xc0, 0x07, 0xfe, 0x0f, 0xc0, 0x07, 0xfc, 0x1f, 0xc0, 0x07, 0xf0, 0x7f, 0x80, 0x07, 0x80, 0xff, 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/gen/bitmaps/logo48.png b/gen/bitmaps/logo48.png index 86ec6867677e5b00585df4da64093b472c4f89bf..e90423ca0896dacdfafa0607dde2346d9447c0a7 100644 GIT binary patch delta 252 zcmVN4#gk{M1lDKzie0Cw3ny@a&0m!n+V4jWkf}! z%fZ$%ob>*Cj;b2=t>_ARP;MX))+*r8F%Tdc2pwxxaHtQfghPC_tf0?JkTs!}4fgyV z1-0t!UG-@@RxdMIn;dQgB;dd8Rn6>3DUr;;EhgY+G)acOD0TlAbBhT`KmrnwfCMDq zcgn51Jc^cGtD2{w0aig#G1j6hF#?UM#PIW*2bv{c-B zptF~3xsekEUA_IscbZ_pSQNS+8pKt-g> z4@=8X())Oisv6d<5ev@1GC?80U9b#LtAaz`wxfCMBU0SQRJ`xn;da+!56^b}?dRqTaDtHqXK1*8QWD%@|?#-oic zo9L%umwj$=405tyUHxqVM`7-H2bcjuv$_@R^T4uBvCMbY{Hzf4bU%}EHCs4aYKfk(U75jG-X z`tTSLNtoAbY^}Wqc!iQccHYrO^L%1vHc#k@AtLG-aOVz6QV0X|!Xc2`pIC#NC)VEG zUFe8%@I0aPJoT8l+llizDvO?>Jw%KBiQS8EFASJ93a|h_SAT9<9EZ45il0x0;jQD) zb8!{F0xk`vRMe=}5Sfg~WD)-{rNII$zyd750xZA+{9!$K?GB)2mo<;M9`u5GB!B%$L_t(o!|j>T4u&8Ig~j#$ugrhdR!x6AfMxA?*PQUFNJo@X zik5}jmSIG-Jx39F7H|jafmr<`O*~tSI*x$CfU4?V5zkl%u;&1YK@@Truw~dAg9zjn zIUtsky+0Bb)dK@>lgKFyuHRw6j6;GzL4c9%$pEf*r5Nuj)_<~iBOn2n)q}m$=E-Fd zrPKTu&&qwC6joP&`5BTO+p=^a zVsA)M9}AJFWN%#=kg-sO^;*QV97ZN&-ir~#k%t`1msv#5ScQm9_!;8v7<9cfJsyJ* hSkL8rI^fLq0~Dd2u3_xemRJA)002ovPDHLkV1no8gAo7# diff --git a/gen/bitmaps/logo64.png b/gen/bitmaps/logo64.png index d07a745fbbab8e2ba847b369c4e376ff3aa74b26..1ea8747a9072cb5addf593098f6deac981411eb8 100644 GIT binary patch delta 312 zcmV-80muHm0@DJJB!3!7L_t(&-tC#e4#OY_hKu3Q_kY_at=+-Hk}kFIgKk-Vt`+zy ziVDj@>5D{^Ypo(z3&(M&>QtcfJT1evZClrMIFOO%?Ld4kiVMX{)3o+|&z~Ux<)U6n zNt>Y{O$(fHo@5S?eLYE#=F^9Fyf0*c^}fqmYuYZeJH|eRfPWtCdee_-4c*1d?hLR{ zmLC%W5r{zZuCQ4rXfV?{xIuMT2X?+gf;j2Bw&6SP|V@pp?JFPhN1!Q*ogbKDY^MUTLatmBI)_3df1LXxf7KBRAd&=Vg0000< KMNUMnLSTXpijxTd delta 290 zcmV+-0p0%70=)u|B!2`+L_t(&-tF4K5`!QN1W=aY|9_btyf_`SWRswDmTL!mPzVGq zjHUh4v3uO$6w~W$Kcx3q!vgZfdmprAb|uD=#R3F<3JvGvYyF9 z+I%at%#;tAuVYLsA~kEC?sAz|eCB#JW-;&i0y`IyIwCMF4@qGWJ}aH6^oB2iowCFa o2~09Nih8$&FB@6L4bH>m1MO^VgSsIKx&QzG07*qoM6N<$f=)7ki~s-t diff --git a/gen/bitmaps/logo64_empty.png b/gen/bitmaps/logo64_empty.png index ec8ba1da415ff5d10e317c8d5d5d39da3eeecd7e..ce7a006fdee68b9bc23a3069d5f5fbc111711c2d 100644 GIT binary patch delta 285 zcmV+&0pk9=1GfT@BYyz?Nklott=qd+#FO3az!A^VB5PkDWV|QYO)WoQ;JsMAcevF3fJXJ&0yAWu0<3>+g5B zSxO0Bp4~^I{#csJN8V;SlD^E<9B2Vjih5#EiUx(((>7NE5r2q4Xv>BL#=j-0wq)#d zr{-f15h(5}n|6*lnsK!=^?7{wd4WAdAOaDHKm;NXfe1vP{~Gc|WSfHhleJPuJLG$? zhGMmU@@-g#G{&wL^jHBedi3_`$UjOaKrR>sn5Em_7lzi1!U|5$BZsK;++IOoO+rDe jLqM#XQ65wks205eyevII=z_b}00000NkvXXu0mjfP?Usv delta 419 zcmV;U0bKsK0=xr|BYy#dNklVXj(2TM7zMx378YprU=dM2m5AS`^EAubI0;FW6tBYrvSL|1y9<5L5DcWTf9l**e z30r@p0@R~BY^W%TXUdJGa`Or`W5_u)4uo2qREN#C44A8hQh&#Jr~wqt))j@s@32i8 z=A~Y&0WmY?4+sTht#!^3k#3#U4-`0@bEg2^_x*R5uEZ+T4>5b-ITZC91=`ZvLeGq- zh)CCy%*%S~RynEH53A>cv0SuzxA)nbKe*hSp9NR|&6G#qRu8>EFVGA00{wF!W+tM= z_nrpO&SE|Xx__?gtdKe9&H{R#XK%bxpzSor1FawV5o7nF>ceXwY%0tr9~_~QRB03JA3tw#Vf{w|*-rof N002ovPDHLkV1hrO#MuA< From 2c56c4de1b4aff82cd4e13ff5c6304f73b87174b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 2 May 2018 13:15:12 +0100 Subject: [PATCH 0839/1154] firmware: use -Os except for crypto/nanopb parts --- firmware/Makefile | 7 +++++++ firmware/fsm.c | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 8aaae3854c..f5341021e2 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,6 +82,13 @@ OBJS += ../vendor/nanopb/pb_encode.o OBJS += protob/messages.pb.o OBJS += protob/types.pb.o +OPTFLAGS ?= -Os + +../vendor/trezor-crypto/%.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/aes/%.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/ed25519-donna/%.o: OPTFLAGS = -O3 +../vendor/nanopb/%.o: OPTFLAGS = -O3 + include ../Makefile.include DEBUG_LINK ?= 0 diff --git a/firmware/fsm.c b/firmware/fsm.c index d6e653efec..72093a0df6 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -1717,7 +1717,8 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) memcpy(&word, msg->memory.bytes + i, 4); flash_write32(msg->address + i, word); } - svc_flash_lock(); + uint32_t dummy = svc_flash_lock(); + (void)dummy; } else { #if !EMULATOR memcpy((void *) msg->address, msg->memory.bytes, length); @@ -1729,6 +1730,7 @@ void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) { svc_flash_unlock(); svc_flash_erase_sector(msg->sector); - svc_flash_lock(); + uint32_t dummy = svc_flash_lock(); + (void)dummy; } #endif From 8e8749dc6826996dd8dbf0fb3332bc817b9de946 Mon Sep 17 00:00:00 2001 From: ZuluCrypto Date: Fri, 6 Apr 2018 15:45:32 -0600 Subject: [PATCH 0840/1154] Add support for Stellar --- firmware/Makefile | 1 + firmware/fsm.c | 275 +++++ firmware/fsm.h | 17 + firmware/protob/messages.options | 62 + firmware/protob/types.options | 3 + firmware/stellar.c | 1850 ++++++++++++++++++++++++++++++ firmware/stellar.h | 99 ++ 7 files changed, 2307 insertions(+) create mode 100644 firmware/stellar.c create mode 100644 firmware/stellar.h diff --git a/firmware/Makefile b/firmware/Makefile index f5341021e2..e760d57f38 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,6 +28,7 @@ OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o +OBJS += stellar.o OBJS += debug.o diff --git a/firmware/fsm.c b/firmware/fsm.c index 72093a0df6..9e150eebd1 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -56,6 +56,7 @@ #include "rfc6979.h" #include "gettext.h" #include "supervise.h" +#include "stellar.h" // message methods @@ -1637,6 +1638,280 @@ void fsm_msgCosiSign(CosiSign *msg) layoutHome(); } +void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) +{ + RESP_INIT(StellarPublicKey); + + CHECK_INITIALIZED + + CHECK_PIN + + // Will exit if the user does not confirm + stellar_layoutGetPublicKey(msg->address_n, msg->address_n_count); + + // Read public key and write it to the response + resp->has_public_key = true; + resp->public_key.size = 32; + stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); + + msg_write(MessageType_MessageType_StellarPublicKey, resp); + + layoutHome(); +} + +void fsm_msgStellarSignMessage(StellarSignMessage *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + RESP_INIT(StellarMessageSignature); + + // Will exit if the user does not confirm + stellar_confirmSignString(msg, resp); + + msg_write(MessageType_MessageType_StellarMessageSignature, resp); + + layoutHome(); +} + +void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg) +{ + if (!stellar_verifySignature(msg)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + return; + } + + fsm_sendSuccess(_("Message verified")); + layoutHome(); +} + +void fsm_msgStellarSignTx(StellarSignTx *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + stellar_signingInit(msg); + + // Confirm transaction basics + stellar_layoutTransactionSummary(msg); + + // Respond with a request for the first operation + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); +} + +void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) +{ + stellar_confirmCreateAccountOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) +{ + // This will display additional dialogs to the user + stellar_confirmPaymentOp(msg); + + // Last operation was confirmed, send a StellarSignedTx + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) +{ + stellar_confirmPathPaymentOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) +{ + stellar_confirmManageOfferOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +{ + stellar_confirmCreatePassiveOfferOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) +{ + stellar_confirmSetOptionsOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) +{ + stellar_confirmChangeTrustOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) +{ + stellar_confirmAllowTrustOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) +{ + stellar_confirmAccountMergeOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) +{ + stellar_confirmManageDataOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) +{ + stellar_confirmBumpSequenceOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm.h b/firmware/fsm.h index 24861a2f07..6bdb22c490 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -80,6 +80,23 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); void fsm_msgCosiCommit(CosiCommit *msg); void fsm_msgCosiSign(CosiSign *msg); +// Stellar +void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg); +void fsm_msgStellarSignTx(StellarSignTx *msg); +void fsm_msgStellarPaymentOp(StellarPaymentOp *msg); +void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg); +void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg); +void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg); +void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); +void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg); +void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg); +void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg); +void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); +void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); +void fsm_msgStellarSignMessage(StellarSignMessage *msg); +void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg); +void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); + // debug message functions #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 4541c68ed4..5e3028ed04 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -176,6 +176,68 @@ CosiSign.global_pubkey max_size:32 CosiSignature.signature max_size:32 + +# Stellar +StellarGetPublicKey.address_n max_count:10 + +StellarPublicKey.public_key max_size:32 + +StellarSignMessage.address_n max_count:10 +StellarSignMessage.message max_size:1024 + +StellarMessageSignature.public_key max_size:32 +StellarMessageSignature.signature max_size:64 + +StellarVerifyMessage.public_key max_size:32 +StellarVerifyMessage.message max_size:1024 +StellarVerifyMessage.signature max_size:64 + +StellarMessageVerification.public_key max_size: 32 + +StellarSignTx.address_n max_count:10 +StellarSignTx.network_passphrase max_size:1024 +StellarSignTx.source_account max_size:32 +StellarSignTx.memo_text max_size:29 +StellarSignTx.memo_hash max_size:32 + +StellarPaymentOp.source_account max_size:32 +StellarPaymentOp.destination_account max_size:32 + +StellarCreateAccountOp.source_account max_size:32 +StellarCreateAccountOp.new_account max_size:32 + +StellarPathPaymentOp.source_account max_size:32 +StellarPathPaymentOp.destination_account max_size:32 +StellarPathPaymentOp.paths max_count:5 + +StellarManageOfferOp.source_account max_size:32 + +StellarCreatePassiveOfferOp.source_account max_size:32 + +StellarSetOptionsOp.source_account max_size:32 +StellarSetOptionsOp.inflation_destination_account max_size:32 +StellarSetOptionsOp.home_domain max_size:33 +StellarSetOptionsOp.signer_key max_size:32 + +StellarChangeTrustOp.source_account max_size:32 + +StellarAllowTrustOp.source_account max_size:32 +StellarAllowTrustOp.trusted_account max_size:32 +StellarAllowTrustOp.asset_code max_size:13 + +StellarAccountMergeOp.source_account max_size:32 +StellarAccountMergeOp.destination_account max_size:32 + +StellarManageDataOp.source_account max_size:32 +StellarManageDataOp.key max_size:65 +StellarManageDataOp.value max_size:65 + +StellarBumpSequenceOp.source_account max_size:32 + +StellarSignedTx.public_key max_size:32 +StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint + + # deprecated SimpleSignTx skip_message:true diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 527e4fac73..ea53f085c7 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -72,3 +72,6 @@ NEMAggregateModification.modifications max_count:16 NEMCosignatoryModification.public_key max_size:32 NEMImportanceTransfer.public_key max_size:32 + +StellarAssetType.code max_size:13 +StellarAssetType.issuer max_size:32 \ No newline at end of file diff --git a/firmware/stellar.c b/firmware/stellar.c new file mode 100644 index 0000000000..e242dee2c9 --- /dev/null +++ b/firmware/stellar.c @@ -0,0 +1,1850 @@ +/* + * This file is part of the TREZOR project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + * + * Stellar signing has the following workflow: + * 1. Client sends first 1024 bytes of the transaction + * 2. Trezor parses the transaction header and confirms the details with the user + * 3. Trezor responds to the client with an offset for where to send the next chunk of bytes + * 4. Client sends next 1024 bytes starting at + * 5. Trezor parses and confirms the next operation + * 6. Trezor responds with either an offset for the next operation or a signature + */ + +#include +#include +#include "messages.h" +#include "messages.pb.h" +#include "stellar.h" +#include "bip32.h" +#include "crypto.h" +#include "layout2.h" +#include "gettext.h" +#include "bignum.h" +#include "oled.h" +#include "base32.h" +#include "storage.h" +#include "fsm.h" +#include "protect.h" +#include "util.h" +#include "layout2.h" +#include "fonts.h" + +static bool stellar_signing = false; +static StellarTransaction stellar_activeTx; + +static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) +{ + static char str[4][32 + 1]; + if (rowlen > 32) { + rowlen = 32; + } + memset(str, 0, sizeof(str)); + strlcpy(str[0], (char *)msg, rowlen + 1); + if (len > rowlen) { + strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); + } + if (len > rowlen * 2) { + strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); + } + if (len > rowlen * 3) { + strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); + } + if (len > rowlen * 4) { + str[3][rowlen - 1] = '.'; + str[3][rowlen - 2] = '.'; + str[3][rowlen - 3] = '.'; + } + static const char *ret[4] = { str[0], str[1], str[2], str[3] }; + return ret; +} + +void stellar_confirmSignString(StellarSignMessage *msg, StellarMessageSignature *resp) +{ + // Max protobuf length is 1024, so string is 1023 + null + int message_len = strnlen(msg->message, 1023); + + // Verify that message only includes printable ascii characters + bool is_valid = true; + for (int i=0; i < message_len; i++) { + if (msg->message[i] < 32) { + is_valid = false; + break; + } + if (msg->message[i] >126) { + is_valid = false; + break; + } + } + if (!is_valid) { + stellar_layoutSigningDialog( + _("Cannot sign message"), + NULL, + _("Message contains"), + _("non-printable ascii"), + _("characters."), + msg->address_n, + msg->address_n_count, + NULL, + false + ); + protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false); + layoutHome(); + return; + } + + // Message can be signed, display as much of it as possible to the user + const char **str_message_lines = split_message((const uint8_t*)(msg->message), message_len, 24); + + stellar_layoutSigningDialog( + _("Sign message?"), + str_message_lines[0], + str_message_lines[1], + str_message_lines[2], + str_message_lines[3], + msg->address_n, + msg->address_n_count, + NULL, + true + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + return; + } + + // Populate response message + stellar_signString((const unsigned char*)(msg->message), msg->address_n, msg->address_n_count, resp->signature.bytes); + resp->has_signature = true; + resp->signature.size = 64; + + stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); + resp->has_public_key = true; + resp->public_key.size = 32; +} + +/* + * Starts the signing process and parses the transaction header + */ +void stellar_signingInit(StellarSignTx *msg) +{ + memset(&stellar_activeTx, 0, sizeof(StellarTransaction)); + stellar_signing = true; + // Initialize signing context + sha256_Init(&(stellar_activeTx.sha256_ctx)); + + // Calculate sha256 for network passphrase + // max length defined in messages.options + uint8_t network_hash[32]; + sha256_Raw((uint8_t *)msg->network_passphrase, strnlen(msg->network_passphrase, 1024), network_hash); + + uint8_t tx_type_bytes[4] = { 0x00, 0x00, 0x00, 0x02 }; + + // Copy some data into the active tx + stellar_activeTx.num_operations = msg->num_operations; + + // Start building what will be signed: + // sha256 of: + // sha256(network passphrase) + // 4-byte unsigned big-endian int type constant (2 for tx) + // remaining bytes are operations added in subsequent messages + stellar_hashupdate_bytes(network_hash, sizeof(network_hash)); + stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); + + // Public key comes from deriving the specified account path (we ignore the one sent by the client) + uint8_t bytes_pubkey[32]; + stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, bytes_pubkey, sizeof(bytes_pubkey)); + memcpy(&(stellar_activeTx.signing_pubkey), bytes_pubkey, sizeof(stellar_activeTx.signing_pubkey)); + + stellar_activeTx.address_n_count = msg->address_n_count; + // todo: fix sizeof check + memcpy(&(stellar_activeTx.address_n), &(msg->address_n), sizeof(stellar_activeTx.address_n)); + + // Hash: public key + stellar_hashupdate_address(bytes_pubkey); + + // Hash: fee + stellar_hashupdate_uint32(msg->fee); + + // Hash: sequence number + stellar_hashupdate_uint64(msg->sequence_number); + + // Timebounds are only present if timebounds_start or timebounds_end is non-zero + uint8_t has_timebounds = (msg->timebounds_start > 0 || msg->timebounds_end > 0); + if (has_timebounds) { + // Hash: the "has timebounds?" boolean + stellar_hashupdate_bool(true); + + // Timebounds are sent as uint32s since that's all we can display, but they must be hashed as + // 64-bit values + stellar_hashupdate_uint32(0); + stellar_hashupdate_uint32(msg->timebounds_start); + + stellar_hashupdate_uint32(0); + stellar_hashupdate_uint32(msg->timebounds_end); + } + // No timebounds, hash a false boolean + else { + stellar_hashupdate_bool(false); + } + + // Hash: memo + stellar_hashupdate_uint32(msg->memo_type); + switch (msg->memo_type) { + // None, nothing else to do + case 0: + break; + // Text: 4 bytes (size) + up to 28 bytes + case 1: + stellar_hashupdate_string((unsigned char*)&(msg->memo_text), strnlen(msg->memo_text, 28)); + break; + // ID (8 bytes, uint64) + case 2: + stellar_hashupdate_uint64(msg->memo_id); + break; + // Hash and return are the same data structure (32 byte tx hash) + case 3: + case 4: + stellar_hashupdate_bytes(msg->memo_hash.bytes, msg->memo_hash.size); + break; + default: + break; + } + + // Hash: number of operations + stellar_hashupdate_uint32(msg->num_operations); + + // Determine what type of network this transaction is for + if (strncmp("Public Global Stellar Network ; September 2015", msg->network_passphrase, 1024) == 0) { + stellar_activeTx.network_type = 1; + } + else if (strncmp("Test SDF Network ; September 2015", msg->network_passphrase, 1024) == 0) { + stellar_activeTx.network_type = 2; + } + else { + stellar_activeTx.network_type = 3; + } +} + +void stellar_confirmSourceAccount(bool has_source_account, uint8_t *bytes) +{ + if (!has_source_account) { + stellar_hashupdate_bool(false); + return; + } + + const char **str_addr_rows = stellar_lineBreakAddress(bytes); + + stellar_layoutTransactionDialog( + _("Op src account OK?"), + NULL, + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: source account + stellar_hashupdate_address(bytes); +} + +void stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(0); + + const char **str_addr_rows = stellar_lineBreakAddress(msg->new_account.bytes); + + // Amount being funded + char str_amount_line[32]; + char str_amount[32]; + stellar_format_stroops(msg->starting_balance, str_amount, sizeof(str_amount)); + + strlcpy(str_amount_line, _("With "), sizeof(str_amount_line)); + strlcat(str_amount_line, str_amount, sizeof(str_amount_line)); + strlcat(str_amount_line, _(" XLM"), sizeof(str_amount_line)); + + stellar_layoutTransactionDialog( + _("Create account: "), + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2], + str_amount_line + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: address + stellar_hashupdate_address(msg->new_account.bytes); + // Hash: starting amount + stellar_hashupdate_uint64(msg->starting_balance); + + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmPaymentOp(StellarPaymentOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(1); + + const char **str_addr_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + + // To: G... + char str_to[32]; + strlcpy(str_to, _("To: "), sizeof(str_to)); + strlcat(str_to, str_addr_rows[0], sizeof(str_to)); + + char str_asset_row[32]; + memset(str_asset_row, 0, sizeof(str_asset_row)); + stellar_format_asset(&(msg->asset), str_asset_row, sizeof(str_asset_row)); + + char str_pay_amount[32]; + char str_amount[32]; + stellar_format_stroops(msg->amount, str_amount, sizeof(str_amount)); + + strlcpy(str_pay_amount, _("Pay "), sizeof(str_pay_amount)); + strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); + + stellar_layoutTransactionDialog( + str_pay_amount, + str_asset_row, + str_to, + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash destination + stellar_hashupdate_address(msg->destination_account.bytes); + // asset + stellar_hashupdate_asset(&(msg->asset)); + // amount (even though amount is signed it doesn't matter for hashing) + stellar_hashupdate_uint64(msg->amount); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(2); + + const char **str_dest_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + + // To: G... + char str_to[32]; + strlcpy(str_to, _("To: "), sizeof(str_to)); + strlcat(str_to, str_dest_rows[0], sizeof(str_to)); + + char str_send_asset[32]; + char str_dest_asset[32]; + stellar_format_asset(&(msg->send_asset), str_send_asset, sizeof(str_send_asset)); + stellar_format_asset(&(msg->destination_asset), str_dest_asset, sizeof(str_dest_asset)); + + char str_pay_amount[32]; + char str_amount[32]; + stellar_format_stroops(msg->destination_amount, str_amount, sizeof(str_amount)); + + strlcpy(str_pay_amount, _("Path Pay "), sizeof(str_pay_amount)); + strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); + + // Confirm what the receiver will get + /* + Path Pay 100 + JPY (G1234ABCDEF) + To: G.... + .... + .... + */ + stellar_layoutTransactionDialog( + str_pay_amount, + str_dest_asset, + str_to, + str_dest_rows[1], + str_dest_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Confirm what the sender is using to pay + char str_source_amount[32]; + char str_source_number[32]; + stellar_format_stroops(msg->send_max, str_source_number, sizeof(str_source_number)); + + strlcpy(str_source_amount, _("Pay Using "), sizeof(str_source_amount)); + strlcat(str_source_amount, str_source_number, sizeof(str_source_amount)); + + stellar_layoutTransactionDialog( + str_source_amount, + str_send_asset, + NULL, + _("This is the amount debited"), + _("from your account.") + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + // Note: no confirmation for intermediate steps since they don't impact the user + + // Hash send asset + stellar_hashupdate_asset(&(msg->send_asset)); + // send max (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->send_max); + // destination account + stellar_hashupdate_address(msg->destination_account.bytes); + // destination asset + stellar_hashupdate_asset(&(msg->destination_asset)); + // destination amount + stellar_hashupdate_uint64(msg->destination_amount); + + // paths are stored as an array so hash the number of elements as a uint32 + stellar_hashupdate_uint32(msg->paths_count); + for (uint8_t i=0; i < msg->paths_count; i++) { + stellar_hashupdate_asset(&(msg->paths[i])); + } + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmManageOfferOp(StellarManageOfferOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(3); + + // New Offer / Delete #123 / Update #123 + char str_offer[32]; + if (msg->offer_id == 0) { + strlcpy(str_offer, _("New Offer"), sizeof(str_offer)); + } + else { + char str_offer_id[20]; + stellar_format_uint64(msg->offer_id, str_offer_id, sizeof(str_offer_id)); + + if (msg->amount == 0) { + strlcpy(str_offer, _("Delete #"), sizeof(str_offer)); + } + else { + strlcpy(str_offer, _("Update #"), sizeof(str_offer)); + } + + strlcat(str_offer, str_offer_id, sizeof(str_offer)); + } + + char str_selling[32]; + char str_sell_amount[32]; + char str_selling_asset[32]; + + stellar_format_asset(&(msg->selling_asset), str_selling_asset, sizeof(str_selling_asset)); + stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); + + /* + Sell 200 + XLM (Native Asset) + */ + strlcpy(str_selling, _("Sell "), sizeof(str_selling)); + strlcat(str_selling, str_sell_amount, sizeof(str_selling)); + + char str_buying[32]; + char str_buying_asset[32]; + char str_price[17]; + + stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); + stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); + + /* + For 0.675952 Per + USD (G12345678) + */ + strlcpy(str_buying, _("For "), sizeof(str_buying)); + strlcat(str_buying, str_price, sizeof(str_buying)); + strlcat(str_buying, _(" Per"), sizeof(str_buying)); + + stellar_layoutTransactionDialog( + str_offer, + str_selling, + str_selling_asset, + str_buying, + str_buying_asset + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash selling asset + stellar_hashupdate_asset(&(msg->selling_asset)); + // buying asset + stellar_hashupdate_asset(&(msg->buying_asset)); + // amount to sell (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->amount); + // numerator + stellar_hashupdate_uint32(msg->price_n); + // denominator + stellar_hashupdate_uint32(msg->price_d); + // offer ID + stellar_hashupdate_uint64(msg->offer_id); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(4); + + // New Offer / Delete #123 / Update #123 + char str_offer[32]; + if (msg->amount == 0) { + strlcpy(str_offer, _("Delete Passive Offer"), sizeof(str_offer)); + } + else { + strlcpy(str_offer, _("New Passive Offer"), sizeof(str_offer)); + } + + char str_selling[32]; + char str_sell_amount[32]; + char str_selling_asset[32]; + + stellar_format_asset(&(msg->selling_asset), str_selling_asset, sizeof(str_selling_asset)); + stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); + + /* + Sell 200 + XLM (Native Asset) + */ + strlcpy(str_selling, _("Sell "), sizeof(str_selling)); + strlcat(str_selling, str_sell_amount, sizeof(str_selling)); + + char str_buying[32]; + char str_buying_asset[32]; + char str_price[17]; + + stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); + stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); + + /* + For 0.675952 Per + USD (G12345678) + */ + strlcpy(str_buying, _("For "), sizeof(str_buying)); + strlcat(str_buying, str_price, sizeof(str_buying)); + strlcat(str_buying, _(" Per"), sizeof(str_buying)); + + stellar_layoutTransactionDialog( + str_offer, + str_selling, + str_selling_asset, + str_buying, + str_buying_asset + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash selling asset + stellar_hashupdate_asset(&(msg->selling_asset)); + // buying asset + stellar_hashupdate_asset(&(msg->buying_asset)); + // amount to sell (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->amount); + // numerator + stellar_hashupdate_uint32(msg->price_n); + // denominator + stellar_hashupdate_uint32(msg->price_d); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(5); + + // Something like Set Inflation Destination + char str_title[32]; + char rows[4][32]; + int row_idx = 0; + memset(rows, 0, sizeof(rows)); + + // Inflation destination + stellar_hashupdate_bool(msg->has_inflation_destination_account); + if (msg->has_inflation_destination_account) { + strlcpy(str_title, _("Set Inflation Destination"), sizeof(str_title)); + const char **str_addr_rows = stellar_lineBreakAddress(msg->inflation_destination_account.bytes); + + stellar_layoutTransactionDialog( + str_title, + NULL, + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // address + stellar_hashupdate_address(msg->inflation_destination_account.bytes); + } + + // Clear flags + stellar_hashupdate_bool(msg->has_clear_flags); + if (msg->has_clear_flags) { + strlcpy(str_title, _("Clear Flag(s)"), sizeof(str_title)); + + // Auth required + if (msg->clear_flags & 0x01) { + strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); + row_idx++; + } + // Auth revocable + if (msg->clear_flags & 0x02) { + strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); + row_idx++; + } + + stellar_layoutTransactionDialog( + str_title, + rows[0], + rows[1], + rows[2], + rows[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + memset(rows, 0, sizeof(rows)); + row_idx = 0; + + // Hash flags + stellar_hashupdate_uint32(msg->clear_flags); + } + + // Set flags + stellar_hashupdate_bool(msg->has_set_flags); + if (msg->has_set_flags) { + strlcpy(str_title, _("Set Flag(s)"), sizeof(str_title)); + + // Auth required + if (msg->set_flags & 0x01) { + strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); + row_idx++; + } + // Auth revocable + if (msg->set_flags & 0x02) { + strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); + row_idx++; + } + + stellar_layoutTransactionDialog( + str_title, + rows[0], + rows[1], + rows[2], + rows[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + memset(rows, 0, sizeof(rows)); + row_idx = 0; + + // Hash flags + stellar_hashupdate_uint32(msg->set_flags); + } + + // Account thresholds + bool show_thresholds_confirm = false; + row_idx = 0; + stellar_hashupdate_bool(msg->has_master_weight); + if (msg->has_master_weight) { + char str_master_weight[10+1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->master_weight, str_master_weight, sizeof(str_master_weight)); + strlcpy(rows[row_idx], _("Master Weight: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_master_weight, sizeof(rows[row_idx])); + row_idx++; + + // Hash master weight + stellar_hashupdate_uint32(msg->master_weight); + } + + stellar_hashupdate_bool(msg->has_low_threshold); + if (msg->has_low_threshold) { + char str_low_threshold[10+1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->low_threshold, str_low_threshold, sizeof(str_low_threshold)); + strlcpy(rows[row_idx], _("Low: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_low_threshold, sizeof(rows[row_idx])); + row_idx++; + + // Hash low threshold + stellar_hashupdate_uint32(msg->low_threshold); + } + stellar_hashupdate_bool(msg->has_medium_threshold); + if (msg->has_medium_threshold) { + char str_med_threshold[10+1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->medium_threshold, str_med_threshold, sizeof(str_med_threshold)); + strlcpy(rows[row_idx], _("Medium: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_med_threshold, sizeof(rows[row_idx])); + row_idx++; + + // Hash medium threshold + stellar_hashupdate_uint32(msg->medium_threshold); + } + stellar_hashupdate_bool(msg->has_high_threshold); + if (msg->has_high_threshold) { + char str_high_threshold[10+1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->high_threshold, str_high_threshold, sizeof(str_high_threshold)); + strlcpy(rows[row_idx], _("High: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_high_threshold, sizeof(rows[row_idx])); + row_idx++; + + // Hash high threshold + stellar_hashupdate_uint32(msg->high_threshold); + } + + if (show_thresholds_confirm) { + strlcpy(str_title, _("Account Thresholds"), sizeof(str_title)); + stellar_layoutTransactionDialog( + str_title, + rows[0], + rows[1], + rows[2], + rows[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + memset(rows, 0, sizeof(rows)); + row_idx = 0; + } + + // Home domain + stellar_hashupdate_bool(msg->has_home_domain); + if (msg->has_home_domain) { + strlcpy(str_title, _("Home Domain"), sizeof(str_title)); + + // Split home domain if longer than 22 characters + int home_domain_len = strnlen(msg->home_domain, 32); + if (home_domain_len > 22) { + strlcpy(rows[0], msg->home_domain, 22); + strlcpy(rows[1], msg->home_domain + 21, sizeof(rows[1])); + } + else { + strlcpy(rows[0], msg->home_domain, sizeof(rows[0])); + } + + stellar_layoutTransactionDialog( + str_title, + rows[0], + rows[1], + NULL, + NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + memset(rows, 0, sizeof(rows)); + row_idx = 0; + + stellar_hashupdate_string((unsigned char*)&(msg->home_domain), strnlen(msg->home_domain, 32)); + } + + // Signer + stellar_hashupdate_bool(msg->has_signer_type); + if (msg->has_signer_type) { + if (msg->signer_weight > 0) { + strlcpy(str_title, _("Add Signer: "), sizeof(str_title)); + } + else { + strlcpy(str_title, _("REMOVE Signer: "), sizeof(str_title)); + } + + // Format weight as a string + char str_weight[16]; + stellar_format_uint32(msg->signer_weight, str_weight, sizeof(str_weight)); + char str_weight_row[32]; + strlcpy(str_weight_row, _("Weight: "), sizeof(str_weight_row)); + strlcat(str_weight_row, str_weight, sizeof(str_weight_row)); + + // 0 = account, 1 = pre-auth, 2 = hash(x) + char str_signer_type[16]; + bool needs_hash_confirm = false; + if (msg->signer_type == 0) { + strlcpy(str_signer_type, _("account"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + const char **str_addr_rows = stellar_lineBreakAddress(msg->signer_key.bytes); + stellar_layoutTransactionDialog( + str_title, + str_weight_row, + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + } + if (msg->signer_type == 1) { + needs_hash_confirm = true; + strlcpy(str_signer_type, _("pre-auth hash"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + stellar_layoutTransactionDialog( + str_title, + str_weight_row, + NULL, + _("(confirm hash on next"), + _("screen)") + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + } + if (msg->signer_type == 2) { + needs_hash_confirm = true; + strlcpy(str_signer_type, _("hash(x)"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + stellar_layoutTransactionDialog( + str_title, + str_weight_row, + NULL, + _("(confirm hash on next"), + _("screen)") + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + } + + // Extra confirmation step for hash signers + if (needs_hash_confirm) { + data2hex(msg->signer_key.bytes + 0, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 8, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 16, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 24, 8, rows[row_idx++]); + + stellar_layoutTransactionDialog( + _("Confirm Hash"), + rows[0], + rows[1], + rows[2], + rows[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + memset(rows, 0, sizeof(rows)); + row_idx = 0; + } + + // Hash: signer type + stellar_hashupdate_uint32(msg->signer_type); + // key + stellar_hashupdate_bytes(msg->signer_key.bytes, msg->signer_key.size); + // weight + stellar_hashupdate_uint32(msg->signer_weight); + } + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(6); + + // Add Trust: USD + char str_title[32]; + if (msg->limit == 0) { + strlcpy(str_title, _("DELETE Trust: "), sizeof(str_title)); + } + else { + strlcpy(str_title, _("Add Trust: "), sizeof(str_title)); + } + strlcat(str_title, msg->asset.code, sizeof(str_title)); + + // Amount: MAX (or a number) + char str_amount_row[32]; + strlcpy(str_amount_row, _("Amount: "), sizeof(str_amount_row)); + + if (msg->limit == 9223372036854775807) { + strlcat(str_amount_row, _("[Maximum]"), sizeof(str_amount_row)); + } + else { + char str_amount[32]; + stellar_format_stroops(msg->limit, str_amount, sizeof(str_amount)); + strlcat(str_amount_row, str_amount, sizeof(str_amount_row)); + } + + // Display full issuer address + const char **str_addr_rows = stellar_lineBreakAddress(msg->asset.issuer.bytes); + + stellar_layoutTransactionDialog( + str_title, + str_amount_row, + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: asset + stellar_hashupdate_asset(&(msg->asset)); + // limit + stellar_hashupdate_uint64(msg->limit); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(7); + + // Add Trust: USD + char str_title[32]; + if (msg->is_authorized) { + strlcpy(str_title, _("Allow Trust of"), sizeof(str_title)); + } + else { + strlcpy(str_title, _("REVOKE Trust of"), sizeof(str_title)); + } + + // Asset code + char str_asset_row[32]; + strlcpy(str_asset_row, msg->asset_code, sizeof(str_asset_row)); + + const char **str_trustor_rows = stellar_lineBreakAddress(msg->trusted_account.bytes); + + // By: G... + char str_by[32]; + strlcpy(str_by, _("By: "), sizeof(str_by)); + strlcat(str_by, str_trustor_rows[0], sizeof(str_by)); + + stellar_layoutTransactionDialog( + str_title, + str_asset_row, + str_by, + str_trustor_rows[1], + str_trustor_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: trustor account (the account being allowed to access the asset) + stellar_hashupdate_address(msg->trusted_account.bytes); + // asset type + stellar_hashupdate_uint32(msg->asset_type); + // asset code + if (msg->asset_type == 1) { + char code4[4+1]; + memset(code4, 0, sizeof(code4)); + strlcpy(code4, msg->asset_code, sizeof(code4)); + stellar_hashupdate_bytes((uint8_t *)code4, 4); + } + if (msg->asset_type == 2) { + char code12[12+1]; + memset(code12, 0, sizeof(code12)); + strlcpy(code12, msg->asset_code, sizeof(code12)); + stellar_hashupdate_bytes((uint8_t *)code12, 12); + } + // is authorized + stellar_hashupdate_bool(msg->is_authorized); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(8); + + const char **str_destination_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + + stellar_layoutTransactionDialog( + _("Merge Account"), + _("All XLM will be sent to:"), + str_destination_rows[0], + str_destination_rows[1], + str_destination_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: destination account + stellar_hashupdate_address(msg->destination_account.bytes); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmManageDataOp(StellarManageDataOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(10); + + char str_title[32]; + if (msg->has_value) { + strlcpy(str_title, _("Set data value key:"), sizeof(str_title)); + } + else { + strlcpy(str_title, _("CLEAR data value key:"), sizeof(str_title)); + } + + // Confirm key + const char **str_key_lines = split_message((const uint8_t*)(msg->key), strnlen(msg->key, 64), 16); + + stellar_layoutTransactionDialog( + str_title, + str_key_lines[0], + str_key_lines[1], + str_key_lines[2], + str_key_lines[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Confirm value by displaying sha256 hash since this can contain non-printable characters + if (msg->has_value) { + strlcpy(str_title, _("Confirm sha256 of value:"), sizeof(str_title)); + + char str_hash_digest[SHA256_DIGEST_STRING_LENGTH]; + sha256_Data(msg->value.bytes, msg->value.size, str_hash_digest); + const char **str_hash_lines = split_message((const uint8_t*)str_hash_digest, sizeof(str_hash_digest), 16); + + stellar_layoutTransactionDialog( + str_title, + str_hash_lines[0], + str_hash_lines[1], + str_hash_lines[2], + str_hash_lines[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + } + + // Hash: key + stellar_hashupdate_string((unsigned char*)&(msg->key), strnlen(msg->key, 64)); + // value + if (msg->has_value) { + stellar_hashupdate_bool(true); + // Variable opaque field is length + raw bytes + stellar_hashupdate_uint32(msg->value.size); + stellar_hashupdate_bytes(msg->value.bytes, msg->value.size); + } + else { + stellar_hashupdate_bool(false); + } + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) +{ + stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + // Hash: operation type + stellar_hashupdate_uint32(11); + + char str_bump_to[20]; + stellar_format_uint64(msg->bump_to, str_bump_to, sizeof(str_bump_to)); + + stellar_layoutTransactionDialog( + _("Bump Sequence"), + _("Set sequence to:"), + str_bump_to, + NULL, + NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Hash: bump to + stellar_hashupdate_uint64(msg->bump_to); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; +} + +void stellar_signingAbort() +{ + stellar_signing = false; + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); +} + +/** + * Populates the fields of resp with the signature of the active transaction + */ +void stellar_fillSignedTx(StellarSignedTx *resp) +{ + StellarTransaction *activeTx = stellar_getActiveTx(); + + // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union + stellar_hashupdate_uint32(0); + + // Add the public key for verification that the right account was used for signing + memcpy(resp->public_key.bytes, &(activeTx->signing_pubkey), 32); + resp->public_key.size = 32; + resp->has_public_key = true; + + // Add the signature (note that this does not include the 4-byte hint since it can be calculated from the public key) + uint8_t signature[64]; + // Note: this calls sha256_Final on the hash context + stellar_getSignatureForActiveTx(signature); + memcpy(resp->signature.bytes, signature, sizeof(signature)); + resp->signature.size = sizeof(signature); + resp->has_signature = true; +} + +uint8_t stellar_allOperationsConfirmed() +{ + return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; +} + +StellarTransaction *stellar_getActiveTx() +{ + return &stellar_activeTx; +} + +/* + * Calculates and sets the signature for the active transaction + */ +void stellar_getSignatureForActiveTx(uint8_t *out_signature) +{ + HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); + + // Signature is the ed25519 detached signature of the sha256 of all the bytes + // that have been read so far + uint8_t to_sign[32]; + sha256_Final(&(stellar_activeTx.sha256_ctx), to_sign); + + uint8_t signature[64]; + ed25519_sign(to_sign, sizeof(to_sign), node->private_key, node->public_key + 1, signature); + + memcpy(out_signature, signature, sizeof(signature)); +} + +void stellar_signString(const uint8_t *str_to_sign, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature) +{ + HDNode *node = stellar_deriveNode(address_n, address_n_count); + + uint8_t signature[64]; + // Maximum field size in protobuf message is 1024, so strlen of 1023 + null + ed25519_sign(str_to_sign, strnlen((const char *)str_to_sign, 1023), node->private_key, node->public_key + 1, signature); + + memcpy(out_signature, signature, sizeof(signature)); +} + +bool stellar_verifySignature(StellarVerifyMessage *msg) +{ + // returns 0 if signature is valid + return ed25519_sign_open( + msg->message.bytes, + msg->message.size, + msg->public_key.bytes, + msg->signature.bytes + ) == 0; +} + +/* + * Returns number (representing stroops) formatted as XLM + * For example, if number has value 1000000000 then it will be returned as "100.0" + */ +void stellar_format_stroops(uint64_t number, char *out, size_t outlen) +{ + bn_format_uint64(number, NULL, NULL, 7, 0, false, out, outlen); +} + +/* + * Formats a price represented as a uint32 numerator and uint32 denominator + * + * Note that there may be a loss of precision between the real price value and what + * is shown to the user + * + * Smallest possible price is 1 / 4294967296 which is: + * 0.00000000023283064365386962890625 + * + * largest possible price is: + * 4294967296 + */ +void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen) +{ + memset(out, 0, outlen); + + // early exist for invalid denominator + if (denominator == 0) { + strlcpy(out, _("[Invalid Price]"), outlen); + return; + } + + int scale = 0; + double dbl_value = (double)numerator / (double)denominator; + + // Multiply by 10 until the value is larger than the largest possible offer size + // Largest possible offer size is UINT32_MAX (4294967296) + while (dbl_value < UINT32_MAX) { + dbl_value *= (double)10; + scale++; + } + + // Cast back to an integer + uint64_t scaled_value = (uint64_t) dbl_value; + + // Format with bn_format_uint64 + bn_format_uint64(scaled_value, NULL, NULL, scale, 0, false, out, outlen); +} + +/* + * Returns a uint32 formatted as a string + */ +void stellar_format_uint32(uint32_t number, char *out, size_t outlen) +{ + bignum256 bn_number; + bn_read_uint32(number, &bn_number); + bn_format(&bn_number, NULL, NULL, 0, 0, false, out, outlen); +} + +/* + * Returns a uint64 formatted as a string + */ +void stellar_format_uint64(uint64_t number, char *out, size_t outlen) +{ + bn_format_uint64(number, NULL, NULL, 0, 0, false, out, outlen); +} + +/* + * Breaks a 56 character address into 3 lines of lengths 16, 20, 20 + * This is to allow a small label to be prepended to the first line + */ +const char **stellar_lineBreakAddress(uint8_t *addrbytes) +{ + char str_fulladdr[56+1]; + static char rows[3][20+1]; + + memset(rows, 0, sizeof(rows)); + + // get full address string + stellar_publicAddressAsStr(addrbytes, str_fulladdr, sizeof(str_fulladdr)); + + // Break it into 3 lines + strlcpy(rows[0], str_fulladdr + 0, 17); + strlcpy(rows[1], str_fulladdr + 16, 21); + strlcpy(rows[2], str_fulladdr + 16 + 20, 21); + + static const char *ret[3] = { rows[0], rows[1], rows[2] }; + return ret; +} + +/* + * Returns the asset formatted to fit in a single row + * + * Examples: + * XLM (Native Asset) + * MOBI (G1234) + * ALPHA12EXAMP (G0987) + */ +void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len) +{ + char str_asset_code[12 + 1]; + // Full asset issuer string + char str_asset_issuer[56+1]; + // truncated asset issuer, final length depends on length of asset code + char str_asset_issuer_trunc[13 + 1]; + + memset(str_formatted, 0, len); + memset(str_asset_code, 0, sizeof(str_asset_code)); + memset(str_asset_issuer_trunc, 0, sizeof(str_asset_issuer_trunc)); + + // Get string representation of address + stellar_publicAddressAsStr(asset->issuer.bytes, str_asset_issuer, sizeof(str_asset_issuer)); + + // Native asset + if (asset->type == 0) { + strlcpy(str_formatted, _("XLM (native asset)"), len); + } + // 4-character custom + if (asset->type == 1) { + memcpy(str_asset_code, asset->code, 4); + strlcpy(str_formatted, str_asset_code, len); + + // Truncate issuer to 13 chars + memcpy(str_asset_issuer_trunc, str_asset_issuer, 13); + } + // 12-character custom + if (asset->type == 2) { + memcpy(str_asset_code, asset->code, 12); + strlcpy(str_formatted, str_asset_code, len); + + // Truncate issuer to 5 characters + memcpy(str_asset_issuer_trunc, str_asset_issuer, 5); + } + // Issuer is read the same way for both types of custom assets + if (asset->type == 1 || asset->type == 2) { + strlcat(str_formatted, _(" ("), len); + strlcat(str_formatted, str_asset_issuer_trunc, len); + strlcat(str_formatted, _(")"), len); + } +} + +size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen) +{ + // version + key bytes + checksum + uint8_t keylen = 1 + 32 + 2; + uint8_t bytes_full[keylen]; + bytes_full[0] = 6 << 3; // 'G' + + memcpy(bytes_full + 1, bytes, 32); + + // Last two bytes are the checksum + uint16_t checksum = stellar_crc16(bytes_full, 33); + bytes_full[keylen-2] = checksum & 0x00ff; + bytes_full[keylen-1] = (checksum>>8) & 0x00ff; + + base32_encode(bytes_full, keylen, out, outlen, BASE32_ALPHABET_RFC4648); + + // Public key will always be 56 characters + return 56; +} + +/* + * CRC16 implementation compatible with the Stellar version + * Ported from this implementation: http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java.html + * Initial value changed to 0x0000 to match Stellar + */ +uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) +{ + // Calculate checksum for existing bytes + uint16_t crc = 0x0000; + uint16_t polynomial = 0x1021; + uint32_t i; + uint8_t bit; + uint8_t byte; + uint8_t bitidx; + uint8_t c15; + + for (i=0; i < length; i++) { + byte = bytes[i]; + for (bitidx=0; bitidx < 8; bitidx++) { + bit = ((byte >> (7 - bitidx) & 1) == 1); + c15 = ((crc >> 15 & 1) == 1); + crc <<= 1; + if (c15 ^ bit) crc ^= polynomial; + } + } + + return crc & 0xffff; +} + +/* + * Writes 32-byte public key to out + */ +void stellar_getPubkeyAtAddress(uint32_t *address_n, size_t address_n_count, uint8_t *out, size_t outlen) +{ + if (outlen < 32) return; + + HDNode *node = stellar_deriveNode(address_n, address_n_count); + + if (node == 0) { + stellar_signingAbort(); + return; + } + + memcpy(out, node->public_key + 1, outlen); +} + +/* + * Derives the HDNode at the given index + * Standard Stellar prefix is m/44'/148'/ and the default account is m/44'/148'/0' + * + * All paths must be hardened + */ +HDNode *stellar_deriveNode(uint32_t *address_n, size_t address_n_count) +{ + static CONFIDENTIAL HDNode node; + const char *curve = "ed25519"; + + // Device not initialized, passphrase request cancelled, or unsupported curve + if (!storage_getRootNode(&node, curve, true)) { + return 0; + } + // Failed to derive private key + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { + return 0; + } + + hdnode_fill_public_key(&node); + + return &node; +} + +void stellar_hashupdate_uint32(uint32_t value) +{ + // Ensure uint32 is big endian +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE32(value, value); +#endif + + // Byte values must be hashed as big endian + uint8_t data[4]; + data[3] = (value >> 24) & 0xFF; + data[2] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[0] = value & 0xFF; + + stellar_hashupdate_bytes(data, sizeof(data)); +} + +void stellar_hashupdate_uint64(uint64_t value) +{ + // Ensure uint64 is big endian +#if BYTE_ORDER == LITTLE_ENDIAN + REVERSE64(value, value); +#endif + + // Byte values must be hashed as big endian + uint8_t data[8]; + data[7] = (value >> 56) & 0xFF; + data[6] = (value >> 48) & 0xFF; + data[5] = (value >> 40) & 0xFF; + data[4] = (value >> 32) & 0xFF; + data[3] = (value >> 24) & 0xFF; + data[2] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[0] = value & 0xFF; + + stellar_hashupdate_bytes(data, sizeof(data)); +} + +void stellar_hashupdate_bool(bool value) +{ + if (value) { + stellar_hashupdate_uint32(1); + } + else { + stellar_hashupdate_uint32(0); + } +} + +void stellar_hashupdate_string(uint8_t *data, size_t len) +{ + // Hash the length of the string + stellar_hashupdate_uint32((uint32_t)len); + + // Hash the raw bytes of the string + stellar_hashupdate_bytes(data, len); + + // If len isn't a multiple of 4, add padding bytes + int remainder = len % 4; + uint8_t null_byte[1] = { 0x00 }; + if (remainder) { + while (remainder < 4) { + stellar_hashupdate_bytes(null_byte, 1); + remainder++; + } + } +} + +void stellar_hashupdate_address(uint8_t *address_bytes) +{ + // First 4 bytes of an address are the type. There's only one type (0) + stellar_hashupdate_uint32(0); + + // Remaining part of the address is 32 bytes + stellar_hashupdate_bytes(address_bytes, 32); +} + +/* + * Note about string handling below: this field is an XDR "opaque" field and not a typical string, + * so if "TEST" is the asset code then the hashed value needs to be 4 bytes and not include the null + * at the end of the string + */ +void stellar_hashupdate_asset(StellarAssetType *asset) +{ + stellar_hashupdate_uint32(asset->type); + + // 4-character asset code + if (asset->type == 1) { + char code4[4+1]; + memset(code4, 0, sizeof(code4)); + strlcpy(code4, asset->code, sizeof(code4)); + + stellar_hashupdate_bytes((uint8_t *)code4, 4); + stellar_hashupdate_address(asset->issuer.bytes); + } + + // 12-character asset code + if (asset->type == 2) { + char code12[12+1]; + memset(code12, 0, sizeof(code12)); + strlcpy(code12, asset->code, sizeof(code12)); + + stellar_hashupdate_bytes((uint8_t *)code12, 12); + stellar_hashupdate_address(asset->issuer.bytes); + } +} + +void stellar_hashupdate_bytes(uint8_t *data, size_t len) +{ + sha256_Update(&(stellar_activeTx.sha256_ctx), data, len); +} + +/* + * Displays a summary of the overall transaction + */ +void stellar_layoutTransactionSummary(StellarSignTx *msg) +{ + char str_lines[5][32]; + memset(str_lines, 0, sizeof(str_lines)); + + char str_fee[12]; + char str_num_ops[12]; + + // Will be set to true for some large hashes that don't fit on one screen + uint8_t needs_memo_hash_confirm = 0; + + // Format the fee + stellar_format_stroops(msg->fee, str_fee, sizeof(str_fee)); + + strlcpy(str_lines[0], _("Fee: "), sizeof(str_lines[0])); + strlcat(str_lines[0], str_fee, sizeof(str_lines[0])); + strlcat(str_lines[0], _(" XLM"), sizeof(str_lines[0])); + + // add in numOperations + stellar_format_uint32(msg->num_operations, str_num_ops, sizeof(str_num_ops)); + + strlcat(str_lines[0], _(" ("), sizeof(str_lines[0])); + strlcat(str_lines[0], str_num_ops, sizeof(str_lines[0])); + if (msg->num_operations == 1) { + strlcat(str_lines[0], _(" op)"), sizeof(str_lines[0])); + } else { + strlcat(str_lines[0], _(" ops)"), sizeof(str_lines[0])); + } + + // Display full address being used to sign transaction + const char **str_addr_rows = stellar_lineBreakAddress(stellar_activeTx.signing_pubkey); + + stellar_layoutTransactionDialog( + str_lines[0], + _("Signing with:"), + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Reset lines for displaying memo + memset(str_lines, 0, sizeof(str_lines)); + + // Memo: none + if (msg->memo_type == 0) { + strlcpy(str_lines[0], _("[No Memo Set]"), sizeof(str_lines[0])); + strlcpy(str_lines[1], _("Important:"), sizeof(str_lines[0])); + strlcpy(str_lines[2], _("Many exchanges require"), sizeof(str_lines[0])); + strlcpy(str_lines[3], _("a memo when depositing."), sizeof(str_lines[0])); + } + // Memo: text + if (msg->memo_type == 1) { + strlcpy(str_lines[0], _("Memo (TEXT)"), sizeof(str_lines[0])); + + // Split 28-character string into two lines of 19 / 9 + // todo: word wrap method? + strlcpy(str_lines[1], (const char*)msg->memo_text, 19 + 1); + strlcpy(str_lines[2], (const char*)(msg->memo_text + 19), 9 + 1); + } + // Memo: ID + if (msg->memo_type == 2) { + strlcpy(str_lines[0], _("Memo (ID)"), sizeof(str_lines[0])); + stellar_format_uint64(msg->memo_id, str_lines[1], sizeof(str_lines[1])); + } + // Memo: hash + if (msg->memo_type == 3) { + needs_memo_hash_confirm = 1; + strlcpy(str_lines[0], _("Memo (HASH)"), sizeof(str_lines[0])); + } + // Memo: return + if (msg->memo_type == 4) { + needs_memo_hash_confirm = 1; + strlcpy(str_lines[0], _("Memo (RETURN)"), sizeof(str_lines[0])); + } + + if (needs_memo_hash_confirm) { + data2hex(msg->memo_hash.bytes + 0, 8, str_lines[1]); + data2hex(msg->memo_hash.bytes + 8, 8, str_lines[2]); + data2hex(msg->memo_hash.bytes + 16, 8, str_lines[3]); + data2hex(msg->memo_hash.bytes + 24, 8, str_lines[4]); + } + + stellar_layoutTransactionDialog( + str_lines[0], + str_lines[1], + str_lines[2], + str_lines[3], + str_lines[4] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + + // Verify timebounds, if present + memset(str_lines, 0, sizeof(str_lines)); + + // Timebound: lower + if (msg->timebounds_start || msg->timebounds_end) { + time_t timebound; + char str_timebound[32]; + const struct tm *tm; + + timebound = (time_t)msg->timebounds_start; + strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); + if (timebound) { + tm = gmtime(&timebound); + strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); + strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); + } + else { + strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); + } + + // Reset for timebound_max + memset(str_timebound, 0, sizeof(str_timebound)); + + timebound = (time_t)msg->timebounds_end; + strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); + if (timebound) { + tm = gmtime(&timebound); + strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); + strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); + } + else { + strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); + } + } + + if (msg->timebounds_start || msg->timebounds_end) { + stellar_layoutTransactionDialog( + _("Confirm Time Bounds"), + str_lines[0], + str_lines[1], + str_lines[2], + str_lines[3] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(); + return; + } + } +} + +/* + * Most basic dialog used for signing + * - Header indicating which key is being used for signing + * - 5 rows for content + * - Cancel / Next buttons + * - Warning message can appear between cancel/next buttons + */ +void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step) +{ + // Start with some initial padding and use these to track position as rendering moves down the screen + int offset_x = 1; + int offset_y = 1; + int line_height = 9; + + uint8_t public_key[32]; + stellar_getPubkeyAtAddress(address_n, address_n_count, public_key, sizeof(public_key)); + + char str_pubaddr_truncated[12]; // G???? + null + memset(str_pubaddr_truncated, 0, sizeof(str_pubaddr_truncated)); + + layoutLast = layoutDialogSwipe; + layoutSwipe(); + oledClear(); + + // Load up public address + char str_pubaddr[56+1]; + memset(str_pubaddr, 0, sizeof(str_pubaddr)); + stellar_publicAddressAsStr(public_key, str_pubaddr, sizeof(str_pubaddr)); + memcpy(str_pubaddr_truncated, str_pubaddr, sizeof(str_pubaddr_truncated) - 1); + + // Header + // Ends up as: Signing with GABCDEFGHIJKL + char str_header[32]; + memset(str_header, 0, sizeof(str_header)); + strlcpy(str_header, _("Signing with "), sizeof(str_header)); + strlcat(str_header, str_pubaddr_truncated, sizeof(str_header)); + + oledDrawString(offset_x, offset_y, str_header, FONT_STANDARD); + offset_y += line_height; + // Invert color on header + oledInvert(0, 0, OLED_WIDTH, offset_y - 2); + + // Dialog contents begin + if (line1) { + oledDrawString(offset_x, offset_y, line1, FONT_STANDARD); + } + offset_y += line_height; + if (line2) { + oledDrawString(offset_x, offset_y, line2, FONT_STANDARD); + } + offset_y += line_height; + if (line3) { + oledDrawString(offset_x, offset_y, line3, FONT_STANDARD); + } + offset_y += line_height; + if (line4) { + oledDrawString(offset_x, offset_y, line4, FONT_STANDARD); + } + offset_y += line_height; + if (line5) { + oledDrawString(offset_x, offset_y, line5, FONT_STANDARD); + } + offset_y += line_height; + + // Cancel button + oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); + oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, "Cancel", FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth("Cancel", FONT_STANDARD) + 2, OLED_HEIGHT - 1); + + // Warnings (drawn centered between the buttons + if (warning) { + oledDrawStringCenter(OLED_HEIGHT - 8, warning, FONT_STANDARD); + } + + // Next / sign button + char str_next_label[8]; + if (is_final_step) { + strlcpy(str_next_label, _("SIGN"), sizeof(str_next_label)); + } + else { + strlcpy(str_next_label, _("Next"), sizeof(str_next_label)); + } + + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawString(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, str_next_label, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + + oledRefresh(); +} + +/* + * Main dialog helper method. Allows displaying 5 lines. + * A title showing the account being used to sign is always displayed. + */ +void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5) +{ + char str_warning[16]; + memset(str_warning, 0, sizeof(str_warning)); + + if (stellar_activeTx.network_type == 2) { + // Warning: testnet + strlcpy(str_warning, _("WRN:TN"), sizeof(str_warning)); + } + if (stellar_activeTx.network_type == 3) { + // Warning: private network + strlcpy(str_warning, _("WRN:PN"), sizeof(str_warning)); + } + + stellar_layoutSigningDialog( + line1, + line2, + line3, + line4, + line5, + stellar_activeTx.address_n, + stellar_activeTx.address_n_count, + str_warning, + false + ); +} + +void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count) +{ + // Derive node and calculate address + uint8_t pubkey_bytes[32]; + stellar_getPubkeyAtAddress(address_n, address_n_count, pubkey_bytes, sizeof(pubkey_bytes)); + const char **str_addr_rows = stellar_lineBreakAddress(pubkey_bytes); + + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2], + NULL, + NULL, NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } +} \ No newline at end of file diff --git a/firmware/stellar.h b/firmware/stellar.h new file mode 100644 index 0000000000..4e01ae9df9 --- /dev/null +++ b/firmware/stellar.h @@ -0,0 +1,99 @@ +/* + * This file is part of the TREZOR project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __STELLAR_H__ +#define __STELLAR_H__ + +#include +#include "bip32.h" +#include "crypto.h" +#include "messages.pb.h" +#include "fsm.h" + +typedef struct { + // BIP32 path to the address being used for signing + uint32_t address_n[10]; + size_t address_n_count; + uint8_t signing_pubkey[32]; + + // 1 - public network, 2 - official testnet, 3 - other private network + uint8_t network_type; + + // Total number of operations expected + uint8_t num_operations; + // Number that have been confirmed by the user + uint8_t confirmed_operations; + + // sha256 context that will eventually be signed + SHA256_CTX sha256_ctx; +} StellarTransaction; + +// Signing process +void stellar_signingInit(StellarSignTx *tx); +void stellar_signingAbort(void); +void stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); +void stellar_confirmPaymentOp(StellarPaymentOp *msg); +void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); +void stellar_confirmManageOfferOp(StellarManageOfferOp *msg); +void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); +void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg); +void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg); +void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg); +void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); +void stellar_confirmManageDataOp(StellarManageDataOp *msg); +void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); + +void stellar_confirmSignString(StellarSignMessage *msg, StellarMessageSignature *resp); + +void stellar_signString(const uint8_t *str_to_sign, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature); +bool stellar_verifySignature(StellarVerifyMessage *msg); + +// Layout +void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count); +void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); +void stellar_layoutTransactionSummary(StellarSignTx *msg); +void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); + +// Helpers +HDNode *stellar_deriveNode(uint32_t *address_n, size_t address_n_count); + +size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen); +const char **stellar_lineBreakAddress(uint8_t *addrbytes); +void stellar_getPubkeyAtAddress(uint32_t *address_n, size_t address_n_count, uint8_t *out, size_t outlen); + +void stellar_hashupdate_uint32(uint32_t value); +void stellar_hashupdate_uint64(uint64_t value); +void stellar_hashupdate_bool(bool value); +void stellar_hashupdate_string(uint8_t *data, size_t len); +void stellar_hashupdate_address(uint8_t *address_bytes); +void stellar_hashupdate_asset(StellarAssetType *asset); +void stellar_hashupdate_bytes(uint8_t *data, size_t len); + +StellarTransaction *stellar_getActiveTx(void); +void stellar_fillSignedTx(StellarSignedTx *resp); +uint8_t stellar_allOperationsConfirmed(void); +void stellar_getSignatureForActiveTx(uint8_t *out_signature); + +void stellar_format_uint32(uint32_t number, char *out, size_t outlen); +void stellar_format_uint64(uint64_t number, char *out, size_t outlen); +void stellar_format_stroops(uint64_t number, char *out, size_t outlen); +void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len); +void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); + +uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); + +#endif \ No newline at end of file From a1cde6e0cecc9992593797481f4431b6525b2252 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 2 May 2018 15:24:37 +0100 Subject: [PATCH 0841/1154] vendor: update trezor-common (disable Lisk messages for now) --- firmware/protob/Makefile | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 5a3327f96e..09643feb54 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -12,7 +12,7 @@ PYTHON ?= python protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py types_pb2.py - $(PYTHON) $< > $@ + $(PYTHON) $< | grep -v MessageType_Lisk > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/vendor/trezor-common b/vendor/trezor-common index 260747dfa4..b466b721a2 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 260747dfa44ab77cd1e9f27f16db116eed0b45fc +Subproject commit b466b721a213a354ff7d8feacb27d2be80f61312 From 78ece6631f9eb93694fc8e67f37a32040cac370a Mon Sep 17 00:00:00 2001 From: Peter van Mourik Date: Wed, 2 May 2018 16:33:22 +0200 Subject: [PATCH 0842/1154] Wanchain support (#313) --- firmware/ethereum.c | 52 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index d2aff49dde..a71e41a88d 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -43,6 +43,7 @@ static uint32_t data_total, data_left; static EthereumTxRequest msg_tx_request; static CONFIDENTIAL uint8_t privkey[32]; static uint32_t chain_id; +static uint32_t tx_type; struct SHA3_CTX keccak_ctx; static inline void hash_data(const uint8_t *buf, size_t size) @@ -180,7 +181,7 @@ static void send_signature(void) layoutProgress(_("Signing"), 1000); /* eip-155 replay protection */ - if (chain_id != 0) { + if (chain_id) { /* hash v=chain_id, r=0, s=0 */ hash_rlp_number(chain_id); hash_rlp_length(0, 0); @@ -240,19 +241,23 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, suffix = " Wei"; decimals = 0; } else { - switch (chain_id) { - case 1: suffix = " ETH"; break; // Ethereum Mainnet - case 61: suffix = " ETC"; break; // Ethereum Classic Mainnet - case 62: suffix = " tETC"; break; // Ethereum Classic Testnet - case 30: suffix = " RSK"; break; // Rootstock Mainnet - case 31: suffix = " tRSK"; break; // Rootstock Testnet - case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten - case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby - case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan - case 2: suffix = " EXP"; break; // Expanse - case 8: suffix = " UBQ"; break; // UBIQ - default: suffix = " UNKN"; break; // unknown chain - } + if (tx_type == 1 || tx_type == 6) { + suffix = " WAN"; + } else { + switch (chain_id) { + case 1: suffix = " ETH"; break; // Ethereum Mainnet + case 61: suffix = " ETC"; break; // Ethereum Classic Mainnet + case 62: suffix = " tETC"; break; // Ethereum Classic Testnet + case 30: suffix = " RSK"; break; // Rootstock Mainnet + case 31: suffix = " tRSK"; break; // Rootstock Testnet + case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten + case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby + case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan + case 2: suffix = " EXP"; break; // Expanse + case 8: suffix = " UBQ"; break; // UBIQ + default: suffix = " UNKN"; break; // unknown chain + } + } } bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); } @@ -450,6 +455,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) chain_id = 0; } + /* Wanchain txtype */ + if (msg->has_tx_type) { + if (msg->tx_type == 1 || msg->tx_type == 6) { + tx_type = msg->tx_type; + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); + ethereum_signing_abort(); + return; + } + } else { + tx_type = 0; + } + if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); @@ -530,6 +548,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); + if (tx_type) { + rlp_length += rlp_calculate_length(1, tx_type); + } if (chain_id) { rlp_length += rlp_calculate_length(1, chain_id); rlp_length += rlp_calculate_length(0, 0); @@ -541,6 +562,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress(_("Signing"), 100); + if (tx_type) { + hash_rlp_number(tx_type); + } hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); From c4beba839bda036ab068499f334da97f22c2d9db Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 2 May 2018 17:24:17 +0200 Subject: [PATCH 0843/1154] nem: mosaics are generated from nem_mosaics.json in trezor-common closes #344 --- firmware/Makefile | 2 +- firmware/nem_mosaics.json | 57 --------------------------------------- firmware/nem_mosaics.py | 2 +- 3 files changed, 2 insertions(+), 59 deletions(-) delete mode 100644 firmware/nem_mosaics.json diff --git a/firmware/Makefile b/firmware/Makefile index e760d57f38..a91a09c3f0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -120,5 +120,5 @@ clean:: endef $(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,nem_mosaics,,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json deleted file mode 100644 index c547e93af1..0000000000 --- a/firmware/nem_mosaics.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "name": "XEM", - "ticker": " XEM", - "namespace": "nem", - "mosaic": "xem", - "divisibility": 6 - }, - { - "name": "DIMCOIN", - "ticker": " DIM", - "namespace": "dim", - "mosaic": "coin", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 10, - "levy_namespace": "dim", - "levy_mosaic": "coin", - "networks": [ 104 ] - }, - { - "name": "DIM TOKEN", - "ticker": " DIMTOK", - "namespace": "dim", - "mosaic": "token", - "divisibility": 6, - "networks": [ 104 ] - }, - { - "name": "Breeze Token", - "ticker": " BREEZE", - "namespace": "breeze", - "mosaic": "breeze-token", - "divisibility": 0, - "networks": [ 104 ] - }, - { - "name": "PacNEM Game Credits", - "ticker": " PAC:HRT", - "namespace": "pacnem", - "mosaic": "heart", - "divisibility": 0, - "networks": [ 104 ] - }, - { - "name": "PacNEM Score Tokens", - "ticker": " PAC:CHS", - "namespace": "pacnem", - "mosaic": "cheese", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 100, - "levy_namespace": "nem", - "levy_mosaic": "xem", - "networks": [ 104 ] - } -] diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index 7b9f259996..bd02fdbffb 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -109,7 +109,7 @@ if __name__ == "__main__": sys.path.insert(0, "protob") import types_pb2 as types - messages = json.load(open("nem_mosaics.json")) + messages = json.load(open("../vendor/trezor-common/defs/nem/nem_mosaics.json")) with open("nem_mosaics.h", "w+") as f: f.write(HEADER_TEMPLATE.format( From fb3e468ea2a4f667978e022d768cf966d6cb7c42 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 May 2018 16:47:37 +0200 Subject: [PATCH 0844/1154] fsm: split fsm_msg functions into various topic include files --- firmware/fsm.c | 1777 +---------------------------------- firmware/fsm_msg_coin.h | 272 ++++++ firmware/fsm_msg_common.h | 399 ++++++++ firmware/fsm_msg_crypto.h | 337 +++++++ firmware/fsm_msg_debug.h | 97 ++ firmware/fsm_msg_ethereum.h | 99 ++ firmware/fsm_msg_nem.h | 287 ++++++ firmware/fsm_msg_stellar.h | 273 ++++++ 8 files changed, 1771 insertions(+), 1770 deletions(-) create mode 100644 firmware/fsm_msg_coin.h create mode 100644 firmware/fsm_msg_common.h create mode 100644 firmware/fsm_msg_crypto.h create mode 100644 firmware/fsm_msg_debug.h create mode 100644 firmware/fsm_msg_ethereum.h create mode 100644 firmware/fsm_msg_nem.h create mode 100644 firmware/fsm_msg_stellar.h diff --git a/firmware/fsm.c b/firmware/fsm.c index 9e150eebd1..c707600e20 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -239,1773 +239,10 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore } } -void fsm_msgInitialize(Initialize *msg) -{ - recovery_abort(); - signing_abort(); - if (msg && msg->has_state && msg->state.size == 64) { - uint8_t i_state[64]; - if (!session_getState(msg->state.bytes, i_state, NULL)) { - session_clear(false); // do not clear PIN - } else { - if (0 != memcmp(msg->state.bytes, i_state, 64)) { - session_clear(false); // do not clear PIN - } - } - } else { - session_clear(false); // do not clear PIN - } - layoutHome(); - fsm_msgGetFeatures(0); -} - -void fsm_msgGetFeatures(GetFeatures *msg) -{ - (void)msg; - RESP_INIT(Features); - resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); - resp->has_major_version = true; resp->major_version = VERSION_MAJOR; - resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; - resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; - resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); - resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); - resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); -#ifdef SCM_REVISION - int len = sizeof(SCM_REVISION) - 1; - resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; -#endif - resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (storage_getLanguage()) { - resp->has_language = true; - strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); - } - if (storage_getLabel()) { - resp->has_label = true; - strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); - } - - _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); - - resp->coins_count = COINS_COUNT; - for (int i = 0; i < COINS_COUNT; i++) { - if (coins[i].coin_name) { - resp->coins[i].has_coin_name = true; - strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); - } - if (coins[i].coin_shortcut) { - resp->coins[i].has_coin_shortcut = true; - strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut + 1, sizeof(resp->coins[i].coin_shortcut)); - } - resp->coins[i].has_address_type = coins[i].has_address_type; - resp->coins[i].address_type = coins[i].address_type; - resp->coins[i].has_maxfee_kb = true; - resp->coins[i].maxfee_kb = coins[i].maxfee_kb; - resp->coins[i].has_address_type_p2sh = coins[i].has_address_type_p2sh; - resp->coins[i].address_type_p2sh = coins[i].address_type_p2sh; - resp->coins[i].has_xpub_magic = coins[i].xpub_magic != 0; - resp->coins[i].xpub_magic = coins[i].xpub_magic; - resp->coins[i].has_xprv_magic = coins[i].xprv_magic != 0; - resp->coins[i].xprv_magic = coins[i].xprv_magic; - resp->coins[i].has_segwit = true; - resp->coins[i].segwit = coins[i].has_segwit; - resp->coins[i].has_forkid = coins[i].has_forkid; - resp->coins[i].forkid = coins[i].forkid; - resp->coins[i].has_force_bip143 = true; - resp->coins[i].force_bip143 = coins[i].force_bip143; - } - resp->has_initialized = true; resp->initialized = storage_isInitialized(); - resp->has_imported = true; resp->imported = storage_isImported(); - resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); - resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); - resp->unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); - resp->has_flags = true; resp->flags = storage_getFlags(); - resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); - - msg_write(MessageType_MessageType_Features, resp); -} - -void fsm_msgPing(Ping *msg) -{ - RESP_INIT(Success); - - if (msg->has_button_protection && msg->button_protection) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if (msg->has_pin_protection && msg->pin_protection) { - CHECK_PIN - } - - if (msg->has_passphrase_protection && msg->passphrase_protection) { - if (!protectPassphrase()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - return; - } - } - - if (msg->has_message) { - resp->has_message = true; - memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); - } - msg_write(MessageType_MessageType_Success, resp); - layoutHome(); -} - -void fsm_msgChangePin(ChangePin *msg) -{ - bool removal = msg->has_remove && msg->remove; - if (removal) { - if (storage_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); - } else { - fsm_sendSuccess(_("PIN removed")); - return; - } - } else { - if (storage_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); - } else { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); - } - } - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN_UNCACHED - - if (removal) { - storage_setPin(""); - storage_update(); - fsm_sendSuccess(_("PIN removed")); - } else { - if (protectChangePin()) { - fsm_sendSuccess(_("PIN changed")); - } else { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - } - } - layoutHome(); -} - -void fsm_msgWipeDevice(WipeDevice *msg) -{ - (void)msg; - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - storage_wipe(); - // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed - // usbReconnect(); // force re-enumeration because of the serial number change - fsm_sendSuccess(_("Device wiped")); - layoutHome(); -} - -void fsm_msgGetEntropy(GetEntropy *msg) -{ -#if !DEBUG_RNG - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } -#endif - RESP_INIT(Entropy); - uint32_t len = msg->size; - if (len > 1024) { - len = 1024; - } - resp->entropy.size = len; - random_buffer(resp->entropy.bytes, len); - msg_write(MessageType_MessageType_Entropy, resp); - layoutHome(); -} - -void fsm_msgGetPublicKey(GetPublicKey *msg) -{ - RESP_INIT(PublicKey); - - CHECK_INITIALIZED - - CHECK_PIN - - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - - const char *curve = coin->curve_name; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - uint32_t fingerprint; - HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); - if (!node) return; - hdnode_fill_public_key(node); - - if (msg->has_show_display && msg->show_display) { - layoutPublicKey(node->public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - resp->node.depth = node->depth; - resp->node.fingerprint = fingerprint; - resp->node.child_num = node->child_num; - resp->node.chain_code.size = 32; - memcpy(resp->node.chain_code.bytes, node->chain_code, 32); - resp->node.has_private_key = false; - resp->node.has_public_key = true; - resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->node.public_key.bytes[0] = 0; - } - resp->has_xpub = true; - hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); - msg_write(MessageType_MessageType_PublicKey, resp); - layoutHome(); -} - -void fsm_msgLoadDevice(LoadDevice *msg) -{ - CHECK_NOT_INITIALIZED - - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { - if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); - layoutHome(); - return; - } - } - - storage_loadDevice(msg); - fsm_sendSuccess(_("Device loaded")); - layoutHome(); -} - -void fsm_msgResetDevice(ResetDevice *msg) -{ - CHECK_NOT_INITIALIZED - - CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); - - reset_init( - msg->has_display_random && msg->display_random, - msg->has_strength ? msg->strength : 128, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0, - msg->has_skip_backup ? msg->skip_backup : false - ); -} - -void fsm_msgBackupDevice(BackupDevice *msg) -{ - CHECK_INITIALIZED - - CHECK_PIN_UNCACHED - - (void)msg; - reset_backup(true); -} - -void fsm_msgSignTx(SignTx *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); - CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); - CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); - - CHECK_PIN - - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); - if (!node) return; - - signing_init(msg, coin, node); -} - -void fsm_msgTxAck(TxAck *msg) -{ - CHECK_PARAM(msg->has_tx, _("No transaction provided")); - - signing_txack(&(msg->tx)); -} - -void fsm_msgCancel(Cancel *msg) -{ - (void)msg; - recovery_abort(); - signing_abort(); - ethereum_signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); -} - -void fsm_msgEthereumSignTx(EthereumSignTx *msg) -{ - CHECK_INITIALIZED - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - ethereum_signing_init(msg, node); -} - -void fsm_msgEthereumTxAck(EthereumTxAck *msg) -{ - ethereum_signing_txack(msg); -} - -void fsm_msgCipherKeyValue(CipherKeyValue *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_key, _("No key provided")); - CHECK_PARAM(msg->has_value, _("No value provided")); - CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - bool encrypt = msg->has_encrypt && msg->encrypt; - bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; - bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; - if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { - layoutCipherKeyValue(encrypt, msg->key); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - uint8_t data[256 + 4]; - strlcpy((char *)data, msg->key, sizeof(data)); - strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); - strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); - - hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); - - RESP_INIT(CipheredKeyValue); - if (encrypt) { - aes_encrypt_ctx ctx; - aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); - } else { - aes_decrypt_ctx ctx; - aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); - } - resp->has_value = true; - resp->value.size = msg->value.size; - msg_write(MessageType_MessageType_CipheredKeyValue, resp); - layoutHome(); -} - -void fsm_msgClearSession(ClearSession *msg) -{ - (void)msg; - session_clear(true); // clear PIN as well - layoutScreensaver(); - fsm_sendSuccess(_("Session cleared")); -} - -void fsm_msgApplySettings(ApplySettings *msg) -{ - CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, - _("No setting provided")); - - CHECK_PIN - - if (msg->has_label) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_language) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_use_passphrase) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("encryption?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_homescreen) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if (msg->has_auto_lock_delay_ms) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - if (msg->has_label) { - storage_setLabel(msg->label); - } - if (msg->has_language) { - storage_setLanguage(msg->language); - } - if (msg->has_use_passphrase) { - storage_setPassphraseProtection(msg->use_passphrase); - } - if (msg->has_homescreen) { - storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); - } - if (msg->has_auto_lock_delay_ms) { - storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); - } - storage_update(); - fsm_sendSuccess(_("Settings applied")); - layoutHome(); -} - -void fsm_msgApplyFlags(ApplyFlags *msg) -{ - if (msg->has_flags) { - storage_applyFlags(msg->flags); - storage_update(); - } - fsm_sendSuccess(_("Flags applied")); -} - -static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) -{ - bool mismatch = false; - - // m : no path - if (msg->address_n_count == 0) { - return false; - } - - // m/44' : BIP44 Legacy - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 44)) { - mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/45' - BIP45 Copay Abandoned Multisig P2SH - // m / purpose' / cosigner_index / change / address_index - if (msg->address_n[0] == (0x80000000 + 45)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count != 4); - mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/48' - BIP48 Copay Multisig P2SH - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 48)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/49' : BIP49 SegWit - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 49)) { - mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); - mismatch |= !coin->has_segwit; - mismatch |= !coin->has_address_type_p2sh; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - // m/84' : BIP84 Native SegWit - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 84)) { - mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); - mismatch |= !coin->has_segwit; - mismatch |= !coin->bech32_prefix; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } - - return false; -} - -void fsm_msgGetAddress(GetAddress *msg) -{ - RESP_INIT(Address); - - CHECK_INITIALIZED - - CHECK_PIN - - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); - - char address[MAX_ADDR_SIZE]; - layoutProgress(_("Computing address"), 0); - if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); - layoutHome(); - return; - } - - if (msg->has_show_display && msg->show_display) { - char desc[20]; - if (msg->has_multisig) { - strlcpy(desc, "Multisig __ of __:", sizeof(desc)); - const uint32_t m = msg->multisig.m; - const uint32_t n = msg->multisig.pubkeys_count; - desc[9] = (m < 10) ? ' ': ('0' + (m / 10)); - desc[10] = '0' + (m % 10); - desc[15] = (n < 10) ? ' ': ('0' + (n / 10)); - desc[16] = '0' + (n % 10); - } else { - strlcpy(desc, _("Address:"), sizeof(desc)); - } - - bool mismatch = path_mismatched(coin, msg); - - if (mismatch) { - layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - - bool is_cashaddr = coin->cashaddr_prefix != NULL; - bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; - if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count)) { - return; - } - } - - strlcpy(resp->address, address, sizeof(resp->address)); - msg_write(MessageType_MessageType_Address, resp); - layoutHome(); -} - -void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) -{ - RESP_INIT(EthereumAddress); - - CHECK_INITIALIZED - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - resp->address.size = 20; - - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) - return; - - if (msg->has_show_display && msg->show_display) { - char desc[16]; - strlcpy(desc, "Address:", sizeof(desc)); - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2); - - if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { - return; - } - } - - msg_write(MessageType_MessageType_EthereumAddress, resp); - layoutHome(); -} - -void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) -{ - RESP_INIT(EthereumMessageSignature); - - CHECK_INITIALIZED - - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - ethereum_message_sign(msg, node, resp); - layoutHome(); -} - -void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - - if (ethereum_message_verify(msg) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - return; - } - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(msg->address.bytes, address + 2); - layoutVerifyAddress(address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); - - layoutHome(); -} - -void fsm_msgEntropyAck(EntropyAck *msg) -{ - if (msg->has_entropy) { - reset_entropy(msg->entropy.bytes, msg->entropy.size); - } else { - reset_entropy(0, 0); - } -} - -void fsm_msgSignMessage(SignMessage *msg) -{ - RESP_INIT(MessageSignature); - - CHECK_INITIALIZED - - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - layoutProgressSwipe(_("Signing"), 0); - if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { - resp->has_address = true; - hdnode_fill_public_key(node); - if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); - layoutHome(); - return; - } - resp->has_signature = true; - resp->signature.size = 65; - msg_write(MessageType_MessageType_MessageSignature, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); - } - layoutHome(); -} - -void fsm_msgVerifyMessage(VerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - layoutProgressSwipe(_("Verifying"), 0); - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { - layoutVerifyAddress(msg->address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - } - layoutHome(); -} - -void fsm_msgSignIdentity(SignIdentity *msg) -{ - RESP_INIT(SignedIdentity); - - CHECK_INITIALIZED - - layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - uint8_t hash[32]; - if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); - layoutHome(); - return; - } - - uint32_t address_n[5]; - address_n[0] = 0x80000000 | 13; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); - - const char *curve = SECP256K1_NAME; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); - if (!node) return; - - bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); - bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); - - int result = 0; - layoutProgressSwipe(_("Signing"), 0); - if (sign_ssh) { // SSH does not sign visual challenge - result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); - } else if (sign_gpg) { // GPG should sign a message digest - result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); - } else { - uint8_t digest[64]; - sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); - sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); - } - - if (result == 0) { - hdnode_fill_public_key(node); - if (strcmp(curve, SECP256K1_NAME) != 0) { - resp->has_address = false; - } else { - resp->has_address = true; - hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type - } - resp->has_public_key = true; - resp->public_key.size = 33; - memcpy(resp->public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->public_key.bytes[0] = 0; - } - resp->has_signature = true; - resp->signature.size = 65; - msg_write(MessageType_MessageType_SignedIdentity, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); - } - layoutHome(); -} - -void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) -{ - RESP_INIT(ECDHSessionKey); - - CHECK_INITIALIZED - - layoutDecryptIdentity(&msg->identity); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - uint8_t hash[32]; - if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); - layoutHome(); - return; - } - - uint32_t address_n[5]; - address_n[0] = 0x80000000 | 17; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); - - const char *curve = SECP256K1_NAME; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - - const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); - if (!node) return; - - int result_size = 0; - if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { - resp->has_session_key = true; - resp->session_key.size = result_size; - msg_write(MessageType_MessageType_ECDHSessionKey, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); - } - layoutHome(); -} - -/* ECIES disabled -void fsm_msgEncryptMessage(EncryptMessage *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_pubkey, _("No public key provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - CHECK_PARAM(msg->pubkey.size == 33, _("Invalid public key provided")); - curve_point pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, _("Invalid public key provided")); - - bool display_only = msg->has_display_only && msg->display_only; - bool signing = msg->address_n_count > 0; - RESP_INIT(EncryptedMessage); - const HDNode *node = 0; - uint8_t address_raw[MAX_ADDR_RAW_SIZE]; - if (signing) { - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - - CHECK_PIN - - node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_get_address_raw(node, coin->address_type, address_raw); - } - layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutProgressSwipe(_("Encrypting"), 0); - if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); - layoutHome(); - return; - } - resp->has_nonce = true; - resp->has_message = true; - resp->has_hmac = true; - msg_write(MessageType_MessageType_EncryptedMessage, resp); - layoutHome(); -} - -void fsm_msgDecryptMessage(DecryptMessage *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_nonce, _("No nonce provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - CHECK_PARAM(msg->has_hmac, _("No message hmac provided")); - - CHECK_PARAM(msg->nonce.size == 33, _("Invalid nonce key provided")); - curve_point nonce_pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, _("Invalid nonce provided")); - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - layoutProgressSwipe(_("Decrypting"), 0); - RESP_INIT(DecryptedMessage); - bool display_only = false; - bool signing = false; - uint8_t address_raw[MAX_ADDR_RAW_SIZE]; - if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - if (signing) { - base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); - } - layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - if (display_only) { - resp->has_address = false; - resp->has_message = false; - memset(resp->address, 0, sizeof(resp->address)); - memset(&(resp->message), 0, sizeof(resp->message)); - } else { - resp->has_address = signing; - resp->has_message = true; - } - msg_write(MessageType_MessageType_DecryptedMessage, resp); - layoutHome(); -} -*/ - -void fsm_msgRecoveryDevice(RecoveryDevice *msg) -{ - const bool dry_run = msg->has_dry_run ? msg->dry_run : false; - if (dry_run) { - CHECK_PIN - } else { - CHECK_NOT_INITIALIZED - } - - CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); - - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - recovery_init( - msg->has_word_count ? msg->word_count : 12, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist && msg->enforce_wordlist, - msg->has_type ? msg->type : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0, - dry_run - ); -} - -void fsm_msgWordAck(WordAck *msg) -{ - recovery_word(msg->word); -} - -void fsm_msgSetU2FCounter(SetU2FCounter *msg) -{ - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - storage_setU2FCounter(msg->u2f_counter); - storage_update(); - fsm_sendSuccess(_("U2F counter set")); - layoutHome(); -} - -void fsm_msgNEMGetAddress(NEMGetAddress *msg) -{ - if (!msg->has_network) { - msg->network = NEM_NETWORK_MAINNET; - } - - const char *network; - CHECK_PARAM((network = nem_network_name(msg->network)), _("Invalid NEM network")); - - CHECK_INITIALIZED - CHECK_PIN - - RESP_INIT(NEMAddress); - - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - if (!hdnode_get_nem_address(node, msg->network, resp->address)) - return; - - if (msg->has_show_display && msg->show_display) { - char desc[16]; - strlcpy(desc, network, sizeof(desc)); - strlcat(desc, ":", sizeof(desc)); - - if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { - return; - } - } - - msg_write(MessageType_MessageType_NEMAddress, resp); - layoutHome(); -} - -void fsm_msgNEMSignTx(NEMSignTx *msg) { - const char *reason; - -#define NEM_CHECK_PARAM(s) CHECK_PARAM( (reason = (s)) == NULL, reason) -#define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) - - CHECK_PARAM(msg->has_transaction, _("No common provided")); - - // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer + - msg->has_provision_namespace + - msg->has_mosaic_creation + - msg->has_supply_change + - msg->has_aggregate_modification + - msg->has_importance_transfer; - CHECK_PARAM(provided != 0, _("No transaction provided")); - CHECK_PARAM(provided == 1, _("More than one transaction provided")); - - NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); - NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); - NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); - NEM_CHECK_PARAM_WHEN(msg->has_importance_transfer, nem_validate_importance_transfer(&msg->importance_transfer)); - - bool cosigning = msg->has_cosigning && msg->cosigning; - if (msg->has_multisig) { - NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); - - CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); - } else { - CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); - } - - CHECK_INITIALIZED - CHECK_PIN - - const char *network = nem_network_name(msg->transaction.network); - - if (msg->has_multisig) { - char address[NEM_ADDRESS_SIZE + 1]; - nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); - - if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - } - - RESP_INIT(NEMSignedTx); - - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); - if (!node) return; - - hdnode_fill_public_key(node); - - const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; - - char address[NEM_ADDRESS_SIZE + 1]; - hdnode_get_nem_address(node, common->network, address); - - if (msg->has_transfer) { - msg->transfer.mosaics_count = nem_canonicalizeMosaics(msg->transfer.mosaics, msg->transfer.mosaics_count); - } - - if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - - nem_transaction_ctx context; - nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); - - if (msg->has_multisig) { - uint8_t buffer[sizeof(resp->data.bytes)]; - - nem_transaction_ctx inner; - nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer)); - - if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { - layoutHome(); - return; - } - - if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&inner, &msg->multisig, &msg->provision_namespace)) { - layoutHome(); - return; - } - - if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { - layoutHome(); - return; - } - - if (msg->has_supply_change && !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { - layoutHome(); - return; - } - - if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&inner, &msg->multisig, &msg->aggregate_modification)) { - layoutHome(); - return; - } - - if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&inner, &msg->multisig, &msg->importance_transfer)) { - layoutHome(); - return; - } - - if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { - layoutHome(); - return; - } - } else { - if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { - layoutHome(); - return; - } - - if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&context, &msg->transaction, &msg->provision_namespace)) { - layoutHome(); - return; - } - - if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&context, &msg->transaction, &msg->mosaic_creation)) { - layoutHome(); - return; - } - - if (msg->has_supply_change && !nem_fsmSupplyChange(&context, &msg->transaction, &msg->supply_change)) { - layoutHome(); - return; - } - - if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&context, &msg->transaction, &msg->aggregate_modification)) { - layoutHome(); - return; - } - - if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&context, &msg->transaction, &msg->importance_transfer)) { - layoutHome(); - return; - } - } - - resp->has_data = true; - resp->data.size = nem_transaction_end(&context, node->private_key, resp->signature.bytes); - - resp->has_signature = true; - resp->signature.size = sizeof(ed25519_signature); - - msg_write(MessageType_MessageType_NEMSignedTx, resp); - layoutHome(); -} - -void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) -{ - RESP_INIT(NEMDecryptedMessage); - - CHECK_INITIALIZED - - CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); - CHECK_PARAM(msg->has_payload, _("No payload provided")); - CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), _("Invalid encrypted payload")); - CHECK_PARAM(msg->has_public_key, _("No public key provided")); - CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); - - char address[NEM_ADDRESS_SIZE + 1]; - nem_get_address(msg->public_key.bytes, msg->network, address); - - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - _("Decrypt message"), - _("Confirm address?"), - address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - const uint8_t *salt = msg->payload.bytes; - uint8_t *iv = &msg->payload.bytes[NEM_SALT_SIZE]; - - const uint8_t *payload = &msg->payload.bytes[NEM_SALT_SIZE + AES_BLOCK_SIZE]; - size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; - - // hdnode_nem_decrypt mutates the IV, so this will modify msg - bool ret = hdnode_nem_decrypt(node, - msg->public_key.bytes, - iv, - salt, - payload, - size, - resp->payload.bytes); - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); - layoutHome(); - return; - } - - resp->has_payload = true; - resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); - - layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); - layoutHome(); -} - -void fsm_msgCosiCommit(CosiCommit *msg) -{ - RESP_INIT(CosiCommitment); - - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_data, _("No data provided")); - - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, &rng); - generate_rfc6979(nonce, &rng); - - resp->has_commitment = true; - resp->has_pubkey = true; - resp->commitment.size = 32; - resp->pubkey.size = 32; - - ed25519_publickey(nonce, resp->commitment.bytes); - ed25519_publickey(node->private_key, resp->pubkey.bytes); - - msg_write(MessageType_MessageType_CosiCommitment, resp); - layoutHome(); -} - -void fsm_msgCosiSign(CosiSign *msg) -{ - RESP_INIT(CosiSignature); - - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_data, _("No data provided")); - CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); - CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); - - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, &rng); - generate_rfc6979(nonce, &rng); - - resp->has_signature = true; - resp->signature.size = 32; - - ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); - - msg_write(MessageType_MessageType_CosiSignature, resp); - layoutHome(); -} - -void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) -{ - RESP_INIT(StellarPublicKey); - - CHECK_INITIALIZED - - CHECK_PIN - - // Will exit if the user does not confirm - stellar_layoutGetPublicKey(msg->address_n, msg->address_n_count); - - // Read public key and write it to the response - resp->has_public_key = true; - resp->public_key.size = 32; - stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); - - msg_write(MessageType_MessageType_StellarPublicKey, resp); - - layoutHome(); -} - -void fsm_msgStellarSignMessage(StellarSignMessage *msg) -{ - CHECK_INITIALIZED - CHECK_PIN - - RESP_INIT(StellarMessageSignature); - - // Will exit if the user does not confirm - stellar_confirmSignString(msg, resp); - - msg_write(MessageType_MessageType_StellarMessageSignature, resp); - - layoutHome(); -} - -void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg) -{ - if (!stellar_verifySignature(msg)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - return; - } - - fsm_sendSuccess(_("Message verified")); - layoutHome(); -} - -void fsm_msgStellarSignTx(StellarSignTx *msg) -{ - CHECK_INITIALIZED - CHECK_PIN - - stellar_signingInit(msg); - - // Confirm transaction basics - stellar_layoutTransactionSummary(msg); - - // Respond with a request for the first operation - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); -} - -void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) -{ - stellar_confirmCreateAccountOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) -{ - // This will display additional dialogs to the user - stellar_confirmPaymentOp(msg); - - // Last operation was confirmed, send a StellarSignedTx - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) -{ - stellar_confirmPathPaymentOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) -{ - stellar_confirmManageOfferOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) -{ - stellar_confirmCreatePassiveOfferOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) -{ - stellar_confirmSetOptionsOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) -{ - stellar_confirmChangeTrustOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) -{ - stellar_confirmAllowTrustOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) -{ - stellar_confirmAccountMergeOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) -{ - stellar_confirmManageDataOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) -{ - stellar_confirmBumpSequenceOp(msg); - - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); - - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); - - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } -} - -#if DEBUG_LINK - -void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) -{ - (void)msg; - - // Do not use RESP_INIT because it clears msg_resp, but another message - // might be being handled - DebugLinkState resp; - memset(&resp, 0, sizeof(resp)); - - resp.has_layout = true; - resp.layout.size = OLED_BUFSIZE; - memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - - if (storage_hasPin()) { - resp.has_pin = true; - strlcpy(resp.pin, storage_getPin(), sizeof(resp.pin)); - } - - resp.has_matrix = true; - strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); - - resp.has_reset_entropy = true; - resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); - - resp.has_reset_word = true; - strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); - - resp.has_recovery_fake_word = true; - strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); - - resp.has_recovery_word_pos = true; - resp.recovery_word_pos = recovery_get_word_pos(); - - if (storage_hasMnemonic()) { - resp.has_mnemonic = true; - strlcpy(resp.mnemonic, storage_getMnemonic(), sizeof(resp.mnemonic)); - } - - if (storage_hasNode()) { - resp.has_node = true; - storage_dumpNode(&(resp.node)); - } - - resp.has_passphrase_protection = true; - resp.passphrase_protection = storage_hasPassphraseProtection(); - - msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); -} - -void fsm_msgDebugLinkStop(DebugLinkStop *msg) -{ - (void)msg; -} - -void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) -{ - RESP_INIT(DebugLinkMemory); - - uint32_t length = 1024; - if (msg->has_length && msg->length < length) - length = msg->length; - resp->has_memory = true; - memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); - resp->memory.size = length; - msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); -} - -void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) -{ - uint32_t length = msg->memory.size; - if (msg->flash) { - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - for (uint32_t i = 0; i < length; i += 4) { - uint32_t word; - memcpy(&word, msg->memory.bytes + i, 4); - flash_write32(msg->address + i, word); - } - uint32_t dummy = svc_flash_lock(); - (void)dummy; - } else { -#if !EMULATOR - memcpy((void *) msg->address, msg->memory.bytes, length); -#endif - } -} - -void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) -{ - svc_flash_unlock(); - svc_flash_erase_sector(msg->sector); - uint32_t dummy = svc_flash_lock(); - (void)dummy; -} -#endif +#include "fsm_msg_common.h" +#include "fsm_msg_coin.h" +#include "fsm_msg_ethereum.h" +#include "fsm_msg_crypto.h" +#include "fsm_msg_nem.h" +#include "fsm_msg_stellar.h" +#include "fsm_msg_debug.h" diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h new file mode 100644 index 0000000000..c482fe8f65 --- /dev/null +++ b/firmware/fsm_msg_coin.h @@ -0,0 +1,272 @@ +void fsm_msgGetPublicKey(GetPublicKey *msg) +{ + RESP_INIT(PublicKey); + + CHECK_INITIALIZED + + CHECK_PIN + + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + + const char *curve = coin->curve_name; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + uint32_t fingerprint; + HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); + + if (msg->has_show_display && msg->show_display) { + layoutPublicKey(node->public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + resp->node.depth = node->depth; + resp->node.fingerprint = fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } + resp->has_xpub = true; + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); + msg_write(MessageType_MessageType_PublicKey, resp); + layoutHome(); +} + +void fsm_msgSignTx(SignTx *msg) +{ + CHECK_INITIALIZED + + CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); + CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); + CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); + + CHECK_PIN + + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); + if (!node) return; + + signing_init(msg, coin, node); +} + +void fsm_msgTxAck(TxAck *msg) +{ + CHECK_PARAM(msg->has_tx, _("No transaction provided")); + + signing_txack(&(msg->tx)); +} + +static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) +{ + bool mismatch = false; + + // m : no path + if (msg->address_n_count == 0) { + return false; + } + + // m/44' : BIP44 Legacy + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 44)) { + mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/45' - BIP45 Copay Abandoned Multisig P2SH + // m / purpose' / cosigner_index / change / address_index + if (msg->address_n[0] == (0x80000000 + 45)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count != 4); + mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/48' - BIP48 Copay Multisig P2SH + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 48)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/49' : BIP49 SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 49)) { + mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + // m/84' : BIP84 Native SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 84)) { + mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->bech32_prefix; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } + + return false; +} + +void fsm_msgGetAddress(GetAddress *msg) +{ + RESP_INIT(Address); + + CHECK_INITIALIZED + + CHECK_PIN + + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); + + char address[MAX_ADDR_SIZE]; + layoutProgress(_("Computing address"), 0); + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); + layoutHome(); + return; + } + + if (msg->has_show_display && msg->show_display) { + char desc[20]; + if (msg->has_multisig) { + strlcpy(desc, "Multisig __ of __:", sizeof(desc)); + const uint32_t m = msg->multisig.m; + const uint32_t n = msg->multisig.pubkeys_count; + desc[9] = (m < 10) ? ' ': ('0' + (m / 10)); + desc[10] = '0' + (m % 10); + desc[15] = (n < 10) ? ' ': ('0' + (n / 10)); + desc[16] = '0' + (n % 10); + } else { + strlcpy(desc, _("Address:"), sizeof(desc)); + } + + bool mismatch = path_mismatched(coin, msg); + + if (mismatch) { + layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + bool is_cashaddr = coin->cashaddr_prefix != NULL; + bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; + if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count)) { + return; + } + } + + strlcpy(resp->address, address, sizeof(resp->address)); + msg_write(MessageType_MessageType_Address, resp); + layoutHome(); +} + +void fsm_msgSignMessage(SignMessage *msg) +{ + RESP_INIT(MessageSignature); + + CHECK_INITIALIZED + + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + layoutProgressSwipe(_("Signing"), 0); + if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { + resp->has_address = true; + hdnode_fill_public_key(node); + if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); + layoutHome(); + return; + } + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_MessageSignature, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); + } + layoutHome(); +} + +void fsm_msgVerifyMessage(VerifyMessage *msg) +{ + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + layoutProgressSwipe(_("Verifying"), 0); + if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { + layoutVerifyAddress(msg->address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + } + layoutHome(); +} diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h new file mode 100644 index 0000000000..0cee17d56e --- /dev/null +++ b/firmware/fsm_msg_common.h @@ -0,0 +1,399 @@ +void fsm_msgInitialize(Initialize *msg) +{ + recovery_abort(); + signing_abort(); + if (msg && msg->has_state && msg->state.size == 64) { + uint8_t i_state[64]; + if (!session_getState(msg->state.bytes, i_state, NULL)) { + session_clear(false); // do not clear PIN + } else { + if (0 != memcmp(msg->state.bytes, i_state, 64)) { + session_clear(false); // do not clear PIN + } + } + } else { + session_clear(false); // do not clear PIN + } + layoutHome(); + fsm_msgGetFeatures(0); +} + +void fsm_msgGetFeatures(GetFeatures *msg) +{ + (void)msg; + RESP_INIT(Features); + resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); + resp->has_major_version = true; resp->major_version = VERSION_MAJOR; + resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; + resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; + resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); + resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); + resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); +#ifdef SCM_REVISION + int len = sizeof(SCM_REVISION) - 1; + resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; +#endif + resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); + if (storage_getLanguage()) { + resp->has_language = true; + strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); + } + if (storage_getLabel()) { + resp->has_label = true; + strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); + } + + _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); + + resp->coins_count = COINS_COUNT; + for (int i = 0; i < COINS_COUNT; i++) { + if (coins[i].coin_name) { + resp->coins[i].has_coin_name = true; + strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); + } + if (coins[i].coin_shortcut) { + resp->coins[i].has_coin_shortcut = true; + strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut + 1, sizeof(resp->coins[i].coin_shortcut)); + } + resp->coins[i].has_address_type = coins[i].has_address_type; + resp->coins[i].address_type = coins[i].address_type; + resp->coins[i].has_maxfee_kb = true; + resp->coins[i].maxfee_kb = coins[i].maxfee_kb; + resp->coins[i].has_address_type_p2sh = coins[i].has_address_type_p2sh; + resp->coins[i].address_type_p2sh = coins[i].address_type_p2sh; + resp->coins[i].has_xpub_magic = coins[i].xpub_magic != 0; + resp->coins[i].xpub_magic = coins[i].xpub_magic; + resp->coins[i].has_xprv_magic = coins[i].xprv_magic != 0; + resp->coins[i].xprv_magic = coins[i].xprv_magic; + resp->coins[i].has_segwit = true; + resp->coins[i].segwit = coins[i].has_segwit; + resp->coins[i].has_forkid = coins[i].has_forkid; + resp->coins[i].forkid = coins[i].forkid; + resp->coins[i].has_force_bip143 = true; + resp->coins[i].force_bip143 = coins[i].force_bip143; + } + resp->has_initialized = true; resp->initialized = storage_isInitialized(); + resp->has_imported = true; resp->imported = storage_isImported(); + resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); + resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); + resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); + resp->unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); + resp->has_flags = true; resp->flags = storage_getFlags(); + resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); + + msg_write(MessageType_MessageType_Features, resp); +} + +void fsm_msgPing(Ping *msg) +{ + RESP_INIT(Success); + + if (msg->has_button_protection && msg->button_protection) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if (msg->has_pin_protection && msg->pin_protection) { + CHECK_PIN + } + + if (msg->has_passphrase_protection && msg->passphrase_protection) { + if (!protectPassphrase()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return; + } + } + + if (msg->has_message) { + resp->has_message = true; + memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Success, resp); + layoutHome(); +} + +void fsm_msgChangePin(ChangePin *msg) +{ + bool removal = msg->has_remove && msg->remove; + if (removal) { + if (storage_hasPin()) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); + } else { + fsm_sendSuccess(_("PIN removed")); + return; + } + } else { + if (storage_hasPin()) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); + } else { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); + } + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN_UNCACHED + + if (removal) { + storage_setPin(""); + storage_update(); + fsm_sendSuccess(_("PIN removed")); + } else { + if (protectChangePin()) { + fsm_sendSuccess(_("PIN changed")); + } else { + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + } + } + layoutHome(); +} + +void fsm_msgWipeDevice(WipeDevice *msg) +{ + (void)msg; + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + storage_wipe(); + // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed + // usbReconnect(); // force re-enumeration because of the serial number change + fsm_sendSuccess(_("Device wiped")); + layoutHome(); +} + +void fsm_msgGetEntropy(GetEntropy *msg) +{ +#if !DEBUG_RNG + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } +#endif + RESP_INIT(Entropy); + uint32_t len = msg->size; + if (len > 1024) { + len = 1024; + } + resp->entropy.size = len; + random_buffer(resp->entropy.bytes, len); + msg_write(MessageType_MessageType_Entropy, resp); + layoutHome(); +} + +void fsm_msgLoadDevice(LoadDevice *msg) +{ + CHECK_NOT_INITIALIZED + + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { + if (!mnemonic_check(msg->mnemonic)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); + layoutHome(); + return; + } + } + + storage_loadDevice(msg); + fsm_sendSuccess(_("Device loaded")); + layoutHome(); +} + +void fsm_msgResetDevice(ResetDevice *msg) +{ + CHECK_NOT_INITIALIZED + + CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); + + reset_init( + msg->has_display_random && msg->display_random, + msg->has_strength ? msg->strength : 128, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_u2f_counter ? msg->u2f_counter : 0, + msg->has_skip_backup ? msg->skip_backup : false + ); +} + +void fsm_msgEntropyAck(EntropyAck *msg) +{ + if (msg->has_entropy) { + reset_entropy(msg->entropy.bytes, msg->entropy.size); + } else { + reset_entropy(0, 0); + } +} + +void fsm_msgBackupDevice(BackupDevice *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN_UNCACHED + + (void)msg; + reset_backup(true); +} + +void fsm_msgCancel(Cancel *msg) +{ + (void)msg; + recovery_abort(); + signing_abort(); + ethereum_signing_abort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); +} + +void fsm_msgClearSession(ClearSession *msg) +{ + (void)msg; + session_clear(true); // clear PIN as well + layoutScreensaver(); + fsm_sendSuccess(_("Session cleared")); +} + +void fsm_msgApplySettings(ApplySettings *msg) +{ + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, + _("No setting provided")); + + CHECK_PIN + + if (msg->has_label) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_language) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_use_passphrase) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("encryption?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_homescreen) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if (msg->has_auto_lock_delay_ms) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + if (msg->has_label) { + storage_setLabel(msg->label); + } + if (msg->has_language) { + storage_setLanguage(msg->language); + } + if (msg->has_use_passphrase) { + storage_setPassphraseProtection(msg->use_passphrase); + } + if (msg->has_homescreen) { + storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); + } + if (msg->has_auto_lock_delay_ms) { + storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); + } + storage_update(); + fsm_sendSuccess(_("Settings applied")); + layoutHome(); +} + +void fsm_msgApplyFlags(ApplyFlags *msg) +{ + if (msg->has_flags) { + storage_applyFlags(msg->flags); + storage_update(); + } + fsm_sendSuccess(_("Flags applied")); +} + +void fsm_msgRecoveryDevice(RecoveryDevice *msg) +{ + const bool dry_run = msg->has_dry_run ? msg->dry_run : false; + if (dry_run) { + CHECK_PIN + } else { + CHECK_NOT_INITIALIZED + } + + CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); + + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + recovery_init( + msg->has_word_count ? msg->word_count : 12, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_enforce_wordlist && msg->enforce_wordlist, + msg->has_type ? msg->type : 0, + msg->has_u2f_counter ? msg->u2f_counter : 0, + dry_run + ); +} + +void fsm_msgWordAck(WordAck *msg) +{ + recovery_word(msg->word); +} + +void fsm_msgSetU2FCounter(SetU2FCounter *msg) +{ + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + storage_setU2FCounter(msg->u2f_counter); + storage_update(); + fsm_sendSuccess(_("U2F counter set")); + layoutHome(); +} \ No newline at end of file diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h new file mode 100644 index 0000000000..c7fbc5cce8 --- /dev/null +++ b/firmware/fsm_msg_crypto.h @@ -0,0 +1,337 @@ +void fsm_msgCipherKeyValue(CipherKeyValue *msg) +{ + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_key, _("No key provided")); + CHECK_PARAM(msg->has_value, _("No value provided")); + CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + bool encrypt = msg->has_encrypt && msg->encrypt; + bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; + bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; + if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { + layoutCipherKeyValue(encrypt, msg->key); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + uint8_t data[256 + 4]; + strlcpy((char *)data, msg->key, sizeof(data)); + strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); + strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); + + hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); + + RESP_INIT(CipheredKeyValue); + if (encrypt) { + aes_encrypt_ctx ctx; + aes_encrypt_key256(data, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); + } else { + aes_decrypt_ctx ctx; + aes_decrypt_key256(data, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); + } + resp->has_value = true; + resp->value.size = msg->value.size; + msg_write(MessageType_MessageType_CipheredKeyValue, resp); + layoutHome(); +} + +void fsm_msgSignIdentity(SignIdentity *msg) +{ + RESP_INIT(SignedIdentity); + + CHECK_INITIALIZED + + layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + uint8_t hash[32]; + if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + layoutHome(); + return; + } + + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 13; + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); + + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); + if (!node) return; + + bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); + bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); + + int result = 0; + layoutProgressSwipe(_("Signing"), 0); + if (sign_ssh) { // SSH does not sign visual challenge + result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); + } else if (sign_gpg) { // GPG should sign a message digest + result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); + } else { + uint8_t digest[64]; + sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); + sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); + result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); + } + + if (result == 0) { + hdnode_fill_public_key(node); + if (strcmp(curve, SECP256K1_NAME) != 0) { + resp->has_address = false; + } else { + resp->has_address = true; + hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type + } + resp->has_public_key = true; + resp->public_key.size = 33; + memcpy(resp->public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->public_key.bytes[0] = 0; + } + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_SignedIdentity, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); + } + layoutHome(); +} + +void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) +{ + RESP_INIT(ECDHSessionKey); + + CHECK_INITIALIZED + + layoutDecryptIdentity(&msg->identity); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + uint8_t hash[32]; + if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + layoutHome(); + return; + } + + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 17; + address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); + address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); + address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); + + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + + const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); + if (!node) return; + + int result_size = 0; + if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { + resp->has_session_key = true; + resp->session_key.size = result_size; + msg_write(MessageType_MessageType_ECDHSessionKey, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); + } + layoutHome(); +} + +/* ECIES disabled +void fsm_msgEncryptMessage(EncryptMessage *msg) +{ + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_pubkey, _("No public key provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + CHECK_PARAM(msg->pubkey.size == 33, _("Invalid public key provided")); + curve_point pubkey; + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, _("Invalid public key provided")); + + bool display_only = msg->has_display_only && msg->display_only; + bool signing = msg->address_n_count > 0; + RESP_INIT(EncryptedMessage); + const HDNode *node = 0; + uint8_t address_raw[MAX_ADDR_RAW_SIZE]; + if (signing) { + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + + CHECK_PIN + + node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + hdnode_get_address_raw(node, coin->address_type, address_raw); + } + layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutProgressSwipe(_("Encrypting"), 0); + if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); + layoutHome(); + return; + } + resp->has_nonce = true; + resp->has_message = true; + resp->has_hmac = true; + msg_write(MessageType_MessageType_EncryptedMessage, resp); + layoutHome(); +} + +void fsm_msgDecryptMessage(DecryptMessage *msg) +{ + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_nonce, _("No nonce provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + CHECK_PARAM(msg->has_hmac, _("No message hmac provided")); + + CHECK_PARAM(msg->nonce.size == 33, _("Invalid nonce key provided")); + curve_point nonce_pubkey; + CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, _("Invalid nonce provided")); + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + layoutProgressSwipe(_("Decrypting"), 0); + RESP_INIT(DecryptedMessage); + bool display_only = false; + bool signing = false; + uint8_t address_raw[MAX_ADDR_RAW_SIZE]; + if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + if (signing) { + base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); + } + layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + if (display_only) { + resp->has_address = false; + resp->has_message = false; + memset(resp->address, 0, sizeof(resp->address)); + memset(&(resp->message), 0, sizeof(resp->message)); + } else { + resp->has_address = signing; + resp->has_message = true; + } + msg_write(MessageType_MessageType_DecryptedMessage, resp); + layoutHome(); +} +*/ + +void fsm_msgCosiCommit(CosiCommit *msg) +{ + RESP_INIT(CosiCommitment); + + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_data, _("No data provided")); + + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); + + resp->has_commitment = true; + resp->has_pubkey = true; + resp->commitment.size = 32; + resp->pubkey.size = 32; + + ed25519_publickey(nonce, resp->commitment.bytes); + ed25519_publickey(node->private_key, resp->pubkey.bytes); + + msg_write(MessageType_MessageType_CosiCommitment, resp); + layoutHome(); +} + +void fsm_msgCosiSign(CosiSign *msg) +{ + RESP_INIT(CosiSignature); + + CHECK_INITIALIZED + + CHECK_PARAM(msg->has_data, _("No data provided")); + CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); + CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); + + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); + + resp->has_signature = true; + resp->signature.size = 32; + + ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); + + msg_write(MessageType_MessageType_CosiSignature, resp); + layoutHome(); +} \ No newline at end of file diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h new file mode 100644 index 0000000000..3a84a87153 --- /dev/null +++ b/firmware/fsm_msg_debug.h @@ -0,0 +1,97 @@ +#if DEBUG_LINK + +void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) +{ + (void)msg; + + // Do not use RESP_INIT because it clears msg_resp, but another message + // might be being handled + DebugLinkState resp; + memset(&resp, 0, sizeof(resp)); + + resp.has_layout = true; + resp.layout.size = OLED_BUFSIZE; + memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + + if (storage_hasPin()) { + resp.has_pin = true; + strlcpy(resp.pin, storage_getPin(), sizeof(resp.pin)); + } + + resp.has_matrix = true; + strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); + + resp.has_reset_entropy = true; + resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); + + resp.has_reset_word = true; + strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); + + resp.has_recovery_fake_word = true; + strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); + + resp.has_recovery_word_pos = true; + resp.recovery_word_pos = recovery_get_word_pos(); + + if (storage_hasMnemonic()) { + resp.has_mnemonic = true; + strlcpy(resp.mnemonic, storage_getMnemonic(), sizeof(resp.mnemonic)); + } + + if (storage_hasNode()) { + resp.has_node = true; + storage_dumpNode(&(resp.node)); + } + + resp.has_passphrase_protection = true; + resp.passphrase_protection = storage_hasPassphraseProtection(); + + msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); +} + +void fsm_msgDebugLinkStop(DebugLinkStop *msg) +{ + (void)msg; +} + +void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) +{ + RESP_INIT(DebugLinkMemory); + + uint32_t length = 1024; + if (msg->has_length && msg->length < length) + length = msg->length; + resp->has_memory = true; + memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); + resp->memory.size = length; + msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); +} + +void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) +{ + uint32_t length = msg->memory.size; + if (msg->flash) { + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); + for (uint32_t i = 0; i < length; i += 4) { + uint32_t word; + memcpy(&word, msg->memory.bytes + i, 4); + flash_write32(msg->address + i, word); + } + uint32_t dummy = svc_flash_lock(); + (void)dummy; + } else { +#if !EMULATOR + memcpy((void *) msg->address, msg->memory.bytes, length); +#endif + } +} + +void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) +{ + svc_flash_unlock(); + svc_flash_erase_sector(msg->sector); + uint32_t dummy = svc_flash_lock(); + (void)dummy; +} +#endif diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h new file mode 100644 index 0000000000..0c9420e3fe --- /dev/null +++ b/firmware/fsm_msg_ethereum.h @@ -0,0 +1,99 @@ +void fsm_msgEthereumSignTx(EthereumSignTx *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + ethereum_signing_init(msg, node); +} + +void fsm_msgEthereumTxAck(EthereumTxAck *msg) +{ + ethereum_signing_txack(msg); +} + +void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) +{ + RESP_INIT(EthereumAddress); + + CHECK_INITIALIZED + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + resp->address.size = 20; + + if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) + return; + + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, "Address:", sizeof(desc)); + + char address[43] = { '0', 'x' }; + ethereum_address_checksum(resp->address.bytes, address + 2); + + if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { + return; + } + } + + msg_write(MessageType_MessageType_EthereumAddress, resp); + layoutHome(); +} + +void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) +{ + RESP_INIT(EthereumMessageSignature); + + CHECK_INITIALIZED + + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + ethereum_message_sign(msg, node, resp); + layoutHome(); +} + +void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) +{ + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); + + if (ethereum_message_verify(msg) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + return; + } + + char address[43] = { '0', 'x' }; + ethereum_address_checksum(msg->address.bytes, address + 2); + layoutVerifyAddress(address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + + layoutHome(); +} \ No newline at end of file diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h new file mode 100644 index 0000000000..25fae20cc8 --- /dev/null +++ b/firmware/fsm_msg_nem.h @@ -0,0 +1,287 @@ +void fsm_msgNEMGetAddress(NEMGetAddress *msg) +{ + if (!msg->has_network) { + msg->network = NEM_NETWORK_MAINNET; + } + + const char *network; + CHECK_PARAM((network = nem_network_name(msg->network)), _("Invalid NEM network")); + + CHECK_INITIALIZED + CHECK_PIN + + RESP_INIT(NEMAddress); + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + if (!hdnode_get_nem_address(node, msg->network, resp->address)) + return; + + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, network, sizeof(desc)); + strlcat(desc, ":", sizeof(desc)); + + if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { + return; + } + } + + msg_write(MessageType_MessageType_NEMAddress, resp); + layoutHome(); +} + +void fsm_msgNEMSignTx(NEMSignTx *msg) { + const char *reason; + +#define NEM_CHECK_PARAM(s) CHECK_PARAM( (reason = (s)) == NULL, reason) +#define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) + + CHECK_PARAM(msg->has_transaction, _("No common provided")); + + // Ensure exactly one transaction is provided + unsigned int provided = msg->has_transfer + + msg->has_provision_namespace + + msg->has_mosaic_creation + + msg->has_supply_change + + msg->has_aggregate_modification + + msg->has_importance_transfer; + CHECK_PARAM(provided != 0, _("No transaction provided")); + CHECK_PARAM(provided == 1, _("More than one transaction provided")); + + NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); + NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); + NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); + NEM_CHECK_PARAM_WHEN(msg->has_importance_transfer, nem_validate_importance_transfer(&msg->importance_transfer)); + + bool cosigning = msg->has_cosigning && msg->cosigning; + if (msg->has_multisig) { + NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); + + CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); + } else { + CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); + } + + CHECK_INITIALIZED + CHECK_PIN + + const char *network = nem_network_name(msg->transaction.network); + + if (msg->has_multisig) { + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); + + if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + } + + RESP_INIT(NEMSignedTx); + + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); + if (!node) return; + + hdnode_fill_public_key(node); + + const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + + char address[NEM_ADDRESS_SIZE + 1]; + hdnode_get_nem_address(node, common->network, address); + + if (msg->has_transfer) { + msg->transfer.mosaics_count = nem_canonicalizeMosaics(msg->transfer.mosaics, msg->transfer.mosaics_count); + } + + if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + layoutHome(); + return; + } + + nem_transaction_ctx context; + nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); + + if (msg->has_multisig) { + uint8_t buffer[sizeof(resp->data.bytes)]; + + nem_transaction_ctx inner; + nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer)); + + if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { + layoutHome(); + return; + } + + if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&inner, &msg->multisig, &msg->provision_namespace)) { + layoutHome(); + return; + } + + if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { + layoutHome(); + return; + } + + if (msg->has_supply_change && !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { + layoutHome(); + return; + } + + if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&inner, &msg->multisig, &msg->aggregate_modification)) { + layoutHome(); + return; + } + + if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&inner, &msg->multisig, &msg->importance_transfer)) { + layoutHome(); + return; + } + + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { + layoutHome(); + return; + } + } else { + if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { + layoutHome(); + return; + } + + if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&context, &msg->transaction, &msg->provision_namespace)) { + layoutHome(); + return; + } + + if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&context, &msg->transaction, &msg->mosaic_creation)) { + layoutHome(); + return; + } + + if (msg->has_supply_change && !nem_fsmSupplyChange(&context, &msg->transaction, &msg->supply_change)) { + layoutHome(); + return; + } + + if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&context, &msg->transaction, &msg->aggregate_modification)) { + layoutHome(); + return; + } + + if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&context, &msg->transaction, &msg->importance_transfer)) { + layoutHome(); + return; + } + } + + resp->has_data = true; + resp->data.size = nem_transaction_end(&context, node->private_key, resp->signature.bytes); + + resp->has_signature = true; + resp->signature.size = sizeof(ed25519_signature); + + msg_write(MessageType_MessageType_NEMSignedTx, resp); + layoutHome(); +} + +void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) +{ + RESP_INIT(NEMDecryptedMessage); + + CHECK_INITIALIZED + + CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); + CHECK_PARAM(msg->has_payload, _("No payload provided")); + CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), _("Invalid encrypted payload")); + CHECK_PARAM(msg->has_public_key, _("No public key provided")); + CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); + + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->public_key.bytes, msg->network, address); + + layoutNEMDialog(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + _("Decrypt message"), + _("Confirm address?"), + address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + const uint8_t *salt = msg->payload.bytes; + uint8_t *iv = &msg->payload.bytes[NEM_SALT_SIZE]; + + const uint8_t *payload = &msg->payload.bytes[NEM_SALT_SIZE + AES_BLOCK_SIZE]; + size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; + + // hdnode_nem_decrypt mutates the IV, so this will modify msg + bool ret = hdnode_nem_decrypt(node, + msg->public_key.bytes, + iv, + salt, + payload, + size, + resp->payload.bytes); + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); + layoutHome(); + return; + } + + resp->has_payload = true; + resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); + + layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); + layoutHome(); +} \ No newline at end of file diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h new file mode 100644 index 0000000000..d60191da47 --- /dev/null +++ b/firmware/fsm_msg_stellar.h @@ -0,0 +1,273 @@ +void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) +{ + RESP_INIT(StellarPublicKey); + + CHECK_INITIALIZED + + CHECK_PIN + + // Will exit if the user does not confirm + stellar_layoutGetPublicKey(msg->address_n, msg->address_n_count); + + // Read public key and write it to the response + resp->has_public_key = true; + resp->public_key.size = 32; + stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); + + msg_write(MessageType_MessageType_StellarPublicKey, resp); + + layoutHome(); +} + +void fsm_msgStellarSignMessage(StellarSignMessage *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + RESP_INIT(StellarMessageSignature); + + // Will exit if the user does not confirm + stellar_confirmSignString(msg, resp); + + msg_write(MessageType_MessageType_StellarMessageSignature, resp); + + layoutHome(); +} + +void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg) +{ + if (!stellar_verifySignature(msg)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + return; + } + + fsm_sendSuccess(_("Message verified")); + layoutHome(); +} + +void fsm_msgStellarSignTx(StellarSignTx *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + stellar_signingInit(msg); + + // Confirm transaction basics + stellar_layoutTransactionSummary(msg); + + // Respond with a request for the first operation + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); +} + +void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) +{ + stellar_confirmCreateAccountOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) +{ + // This will display additional dialogs to the user + stellar_confirmPaymentOp(msg); + + // Last operation was confirmed, send a StellarSignedTx + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) +{ + stellar_confirmPathPaymentOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) +{ + stellar_confirmManageOfferOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +{ + stellar_confirmCreatePassiveOfferOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) +{ + stellar_confirmSetOptionsOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) +{ + stellar_confirmChangeTrustOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) +{ + stellar_confirmAllowTrustOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) +{ + stellar_confirmAccountMergeOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) +{ + stellar_confirmManageDataOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} + +void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) +{ + stellar_confirmBumpSequenceOp(msg); + + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); + + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); + + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } +} \ No newline at end of file From aa6405e23c5708e3a774c2359cc0219914ebcb4c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 3 May 2018 17:42:47 +0200 Subject: [PATCH 0845/1154] firmware: reintroduce dep into Makefile --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index a91a09c3f0..7204ebdc82 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -120,5 +120,5 @@ clean:: endef $(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,nem_mosaics,../vendor/trezor-common/defs/nem/nem_mosaics.json,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) From 975c8c61ed01b121e5be4abafdf053d022855155 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 5 May 2018 22:12:02 +0100 Subject: [PATCH 0846/1154] Revert "firmware: reintroduce dep into Makefile" This reverts commit aa6405e23c5708e3a774c2359cc0219914ebcb4c. --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 7204ebdc82..a91a09c3f0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -120,5 +120,5 @@ clean:: endef $(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,../vendor/trezor-common/defs/nem/nem_mosaics.json,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,nem_mosaics,,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) From 7e407b467e21b7b133a223eaa1b4324dcd592516 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 5 May 2018 22:12:12 +0100 Subject: [PATCH 0847/1154] Revert "nem: mosaics are generated from nem_mosaics.json in trezor-common" This reverts commit c4beba839bda036ab068499f334da97f22c2d9db. --- firmware/Makefile | 2 +- firmware/nem_mosaics.json | 57 +++++++++++++++++++++++++++++++++++++++ firmware/nem_mosaics.py | 2 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 firmware/nem_mosaics.json diff --git a/firmware/Makefile b/firmware/Makefile index a91a09c3f0..e760d57f38 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -120,5 +120,5 @@ clean:: endef $(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json new file mode 100644 index 0000000000..c547e93af1 --- /dev/null +++ b/firmware/nem_mosaics.json @@ -0,0 +1,57 @@ +[ + { + "name": "XEM", + "ticker": " XEM", + "namespace": "nem", + "mosaic": "xem", + "divisibility": 6 + }, + { + "name": "DIMCOIN", + "ticker": " DIM", + "namespace": "dim", + "mosaic": "coin", + "divisibility": 6, + "levy": "MosaicLevy_Percentile", + "fee": 10, + "levy_namespace": "dim", + "levy_mosaic": "coin", + "networks": [ 104 ] + }, + { + "name": "DIM TOKEN", + "ticker": " DIMTOK", + "namespace": "dim", + "mosaic": "token", + "divisibility": 6, + "networks": [ 104 ] + }, + { + "name": "Breeze Token", + "ticker": " BREEZE", + "namespace": "breeze", + "mosaic": "breeze-token", + "divisibility": 0, + "networks": [ 104 ] + }, + { + "name": "PacNEM Game Credits", + "ticker": " PAC:HRT", + "namespace": "pacnem", + "mosaic": "heart", + "divisibility": 0, + "networks": [ 104 ] + }, + { + "name": "PacNEM Score Tokens", + "ticker": " PAC:CHS", + "namespace": "pacnem", + "mosaic": "cheese", + "divisibility": 6, + "levy": "MosaicLevy_Percentile", + "fee": 100, + "levy_namespace": "nem", + "levy_mosaic": "xem", + "networks": [ 104 ] + } +] diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index bd02fdbffb..7b9f259996 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -109,7 +109,7 @@ if __name__ == "__main__": sys.path.insert(0, "protob") import types_pb2 as types - messages = json.load(open("../vendor/trezor-common/defs/nem/nem_mosaics.json")) + messages = json.load(open("nem_mosaics.json")) with open("nem_mosaics.h", "w+") as f: f.write(HEADER_TEMPLATE.format( From 21d147ac47900f577872d4cb54ae671e49e009b6 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Sat, 5 May 2018 22:13:19 +0100 Subject: [PATCH 0848/1154] nem_mosaics: Add symlink to trezor-common --- firmware/nem_mosaics.json | 58 +-------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) mode change 100644 => 120000 firmware/nem_mosaics.json diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json deleted file mode 100644 index c547e93af1..0000000000 --- a/firmware/nem_mosaics.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "name": "XEM", - "ticker": " XEM", - "namespace": "nem", - "mosaic": "xem", - "divisibility": 6 - }, - { - "name": "DIMCOIN", - "ticker": " DIM", - "namespace": "dim", - "mosaic": "coin", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 10, - "levy_namespace": "dim", - "levy_mosaic": "coin", - "networks": [ 104 ] - }, - { - "name": "DIM TOKEN", - "ticker": " DIMTOK", - "namespace": "dim", - "mosaic": "token", - "divisibility": 6, - "networks": [ 104 ] - }, - { - "name": "Breeze Token", - "ticker": " BREEZE", - "namespace": "breeze", - "mosaic": "breeze-token", - "divisibility": 0, - "networks": [ 104 ] - }, - { - "name": "PacNEM Game Credits", - "ticker": " PAC:HRT", - "namespace": "pacnem", - "mosaic": "heart", - "divisibility": 0, - "networks": [ 104 ] - }, - { - "name": "PacNEM Score Tokens", - "ticker": " PAC:CHS", - "namespace": "pacnem", - "mosaic": "cheese", - "divisibility": 6, - "levy": "MosaicLevy_Percentile", - "fee": 100, - "levy_namespace": "nem", - "levy_mosaic": "xem", - "networks": [ 104 ] - } -] diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json new file mode 120000 index 0000000000..e0481bfc7a --- /dev/null +++ b/firmware/nem_mosaics.json @@ -0,0 +1 @@ +../vendor/trezor-common/defs/nem/nem_mosaics.json \ No newline at end of file From cb9eefdce64d8298a6d0f3db31f1001fced523a5 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 11 May 2018 14:03:28 +0200 Subject: [PATCH 0849/1154] Recovery: Don't ask for confirmation on dry run. (#347) The message is very confusing, as it is not recovering the device. Since dry-run recovery does not change anything, there is no need to ask for confirmation. --- firmware/fsm_msg_common.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 0cee17d56e..bd1e13c44e 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -359,11 +359,13 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; + if (!dry_run) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } } recovery_init( @@ -396,4 +398,4 @@ void fsm_msgSetU2FCounter(SetU2FCounter *msg) storage_update(); fsm_sendSuccess(_("U2F counter set")); layoutHome(); -} \ No newline at end of file +} From fc45d0c39b3d867d539f79fa44149c8f5db3ffd4 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 11 May 2018 14:20:21 +0200 Subject: [PATCH 0850/1154] travis: use pipenv to ensure stable environment for python tests --- .travis.yml | 8 +-- Pipfile | 11 ++++ Pipfile.lock | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock diff --git a/.travis.yml b/.travis.yml index 1d4298d8aa..d5038918d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,12 +30,10 @@ matrix: - EMULATOR=1 HEADLESS=1 - DEBUG_LINK=1 before_script: - - $PYTHON -m pip install --user pytest - - $PYTHON -m pip install --user ecdsa mnemonic - - $PYTHON -m pip install --user rlp - - $PYTHON -m pip install --user --no-deps git+https://github.com/trezor/python-trezor@master + - $PYTHON -m pip install --user pipenv + - pipenv install script: - - script/cibuild && script/test -k 'not skip_t1' + - script/cibuild && pipenv run script/test install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000000..fa6c235957 --- /dev/null +++ b/Pipfile @@ -0,0 +1,11 @@ +[[source]] +url = "https://pypi.org/simple" +name = "pypi" +verify_ssl = true + +[packages] +setuptools = ">=24.2.0" +trezor = {git = "https://github.com/trezor/python-trezor", editable = true, ref = "master"} +pytest = "*" +mock = "*" +typing = "*" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000000..e9c200aaa4 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,174 @@ +{ + "_meta": { + "hash": { + "sha256": "83b71604a8624c27e2076b38af223d180479f5511661e7642fe9faf00d4e53f3" + }, + "pipfile-spec": 6, + "requires": {}, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "attrs": { + "hashes": [ + "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", + "sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b" + ], + "version": "==18.1.0" + }, + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", + "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" + ], + "version": "==6.7" + }, + "ecdsa": { + "hashes": [ + "sha256:40d002cf360d0e035cf2cb985e1308d41aaa087cbfc135b2dc2d844296ea546c", + "sha256:64cf1ee26d1cde3c73c6d7d107f835fed7c6a2904aef9eac223d57ad800c43fa" + ], + "version": "==0.13" + }, + "idna": { + "hashes": [ + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + ], + "version": "==2.6" + }, + "libusb1": { + "hashes": [ + "sha256:8c930d9c1d037d9c83924c82608aa6a1adcaa01ca0e4a23ee0e8e18d7eee670d" + ], + "version": "==1.6.4" + }, + "mnemonic": { + "hashes": [ + "sha256:02a7306a792370f4a0c106c2cf1ce5a0c84b9dbd7e71c6792fdb9ad88a727f1d" + ], + "version": "==0.18" + }, + "mock": { + "hashes": [ + "sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1", + "sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba" + ], + "index": "pypi", + "version": "==2.0.0" + }, + "more-itertools": { + "hashes": [ + "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea", + "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e", + "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44" + ], + "version": "==4.1.0" + }, + "pbkdf2": { + "hashes": [ + "sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979" + ], + "version": "==1.3" + }, + "pbr": { + "hashes": [ + "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19", + "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f" + ], + "version": "==4.0.2" + }, + "pluggy": { + "hashes": [ + "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", + "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", + "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + ], + "version": "==0.6.0" + }, + "py": { + "hashes": [ + "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881", + "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a" + ], + "version": "==1.5.3" + }, + "pyblake2": { + "hashes": [ + "sha256:3757f7ad709b0e1b2a6b3919fa79fe3261f166fc375cd521f2be480f8319dde9", + "sha256:407e02c7f8f36fcec1b7aa114ddca0c1060c598142ea6f6759d03710b946a7e3", + "sha256:4d47b4a2c1d292b1e460bde1dda4d13aa792ed2ed70fcc263b6bc24632c8e902", + "sha256:5ccc7eb02edb82fafb8adbb90746af71460fbc29aa0f822526fc976dff83e93f", + "sha256:8043267fbc0b2f3748c6920591cd0b8b5609dcce60c504c32858aa36206386f2", + "sha256:982295a87907d50f4723db6bc724660da76b6547826d52160171d54f95b919ac", + "sha256:baa2190bfe549e36163aa44664d4ee3a9080b236fc5d42f50dc6fd36bbdc749e", + "sha256:c53417ee0bbe77db852d5fd1036749f03696ebc2265de359fe17418d800196c4", + "sha256:fbc9fcde75713930bc2a91b149e97be2401f7c9c56d735b46a109210f58d7358" + ], + "version": "==1.1.2" + }, + "pytest": { + "hashes": [ + "sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8", + "sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526" + ], + "index": "pypi", + "version": "==3.5.1" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "version": "==2.18.4" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "trezor": { + "editable": true, + "git": "https://github.com/trezor/python-trezor", + "ref": "master" + }, + "typing": { + "hashes": [ + "sha256:3a887b021a77b292e151afb75323dea88a7bc1b3dfa92176cff8e44c8b68bddf", + "sha256:b2c689d54e1144bbcfd191b0832980a21c2dbcf7b5ff7a66248a60c90e951eb8", + "sha256:d400a9344254803a2368533e4533a4200d21eb7b6b729c173bc38201a74db3f2" + ], + "index": "pypi", + "version": "==3.6.4" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + } + }, + "develop": {} +} From e859e2835453ff69819160533caa0969569e22d0 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 11 May 2018 14:33:31 +0200 Subject: [PATCH 0851/1154] script: set TREZOR_PATH so that test can reliably run locally --- script/test | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/script/test b/script/test index 69e098d9b5..56fc7d818f 100755 --- a/script/test +++ b/script/test @@ -10,6 +10,8 @@ if [ "$EMULATOR" = 1 ]; then trap "kill %1" EXIT firmware/trezor.elf & + export TREZOR_PATH=udp:127.0.0.1:21324 fi -TREZOR_TRANSPORT_V1=1 "${PYTHON:-python}" -m pytest --pyarg trezorlib.tests.device_tests "$@" +export TREZOR_TRANSPORT_V1=1 +"${PYTHON:-python}" -m pytest --pyarg trezorlib.tests.device_tests "$@" From 29664c4218478a41b063637fc59081534c283a5c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 14 May 2018 16:05:35 +0200 Subject: [PATCH 0852/1154] firmware: refactor Stellar Sign Message --- firmware/fsm_msg_stellar.h | 26 ++++++++++---- firmware/stellar.c | 73 ++------------------------------------ firmware/stellar.h | 6 ++-- vendor/trezor-common | 2 +- 4 files changed, 26 insertions(+), 81 deletions(-) diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index d60191da47..de92b76b65 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -21,13 +21,27 @@ void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) void fsm_msgStellarSignMessage(StellarSignMessage *msg) { - CHECK_INITIALIZED - CHECK_PIN - RESP_INIT(StellarMessageSignature); - // Will exit if the user does not confirm - stellar_confirmSignString(msg, resp); + CHECK_INITIALIZED + + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + CHECK_PIN + + // Populate response message + stellar_signMessage(msg->message.bytes, msg->message.size, msg->address_n, msg->address_n_count, resp->signature.bytes); + resp->has_signature = true; + resp->signature.size = 64; + + stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); + resp->has_public_key = true; + resp->public_key.size = 32; msg_write(MessageType_MessageType_StellarMessageSignature, resp); @@ -36,7 +50,7 @@ void fsm_msgStellarSignMessage(StellarSignMessage *msg) void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg) { - if (!stellar_verifySignature(msg)) { + if (!stellar_verifyMessage(msg)) { fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); return; } diff --git a/firmware/stellar.c b/firmware/stellar.c index e242dee2c9..80dd1eb13c 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -71,68 +71,6 @@ static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t row return ret; } -void stellar_confirmSignString(StellarSignMessage *msg, StellarMessageSignature *resp) -{ - // Max protobuf length is 1024, so string is 1023 + null - int message_len = strnlen(msg->message, 1023); - - // Verify that message only includes printable ascii characters - bool is_valid = true; - for (int i=0; i < message_len; i++) { - if (msg->message[i] < 32) { - is_valid = false; - break; - } - if (msg->message[i] >126) { - is_valid = false; - break; - } - } - if (!is_valid) { - stellar_layoutSigningDialog( - _("Cannot sign message"), - NULL, - _("Message contains"), - _("non-printable ascii"), - _("characters."), - msg->address_n, - msg->address_n_count, - NULL, - false - ); - protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false); - layoutHome(); - return; - } - - // Message can be signed, display as much of it as possible to the user - const char **str_message_lines = split_message((const uint8_t*)(msg->message), message_len, 24); - - stellar_layoutSigningDialog( - _("Sign message?"), - str_message_lines[0], - str_message_lines[1], - str_message_lines[2], - str_message_lines[3], - msg->address_n, - msg->address_n_count, - NULL, - true - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - return; - } - - // Populate response message - stellar_signString((const unsigned char*)(msg->message), msg->address_n, msg->address_n_count, resp->signature.bytes); - resp->has_signature = true; - resp->signature.size = 64; - - stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); - resp->has_public_key = true; - resp->public_key.size = 32; -} - /* * Starts the signing process and parses the transaction header */ @@ -1192,18 +1130,13 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature) memcpy(out_signature, signature, sizeof(signature)); } -void stellar_signString(const uint8_t *str_to_sign, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature) +void stellar_signMessage(const uint8_t *message, uint32_t message_len, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature) { HDNode *node = stellar_deriveNode(address_n, address_n_count); - - uint8_t signature[64]; - // Maximum field size in protobuf message is 1024, so strlen of 1023 + null - ed25519_sign(str_to_sign, strnlen((const char *)str_to_sign, 1023), node->private_key, node->public_key + 1, signature); - - memcpy(out_signature, signature, sizeof(signature)); + ed25519_sign(message, message_len, node->private_key, node->public_key + 1, out_signature); } -bool stellar_verifySignature(StellarVerifyMessage *msg) +bool stellar_verifyMessage(StellarVerifyMessage *msg) { // returns 0 if signature is valid return ed25519_sign_open( diff --git a/firmware/stellar.h b/firmware/stellar.h index 4e01ae9df9..d94bfb6ab8 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -57,10 +57,8 @@ void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); void stellar_confirmManageDataOp(StellarManageDataOp *msg); void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); -void stellar_confirmSignString(StellarSignMessage *msg, StellarMessageSignature *resp); - -void stellar_signString(const uint8_t *str_to_sign, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature); -bool stellar_verifySignature(StellarVerifyMessage *msg); +void stellar_signMessage(const uint8_t *message, uint32_t message_len, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature); +bool stellar_verifyMessage(StellarVerifyMessage *msg); // Layout void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count); diff --git a/vendor/trezor-common b/vendor/trezor-common index b466b721a2..b91db285ba 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit b466b721a213a354ff7d8feacb27d2be80f61312 +Subproject commit b91db285ba8947d6c65a6a807fba87ebc1d43f5d From b9db28beb2dc6bbfe94b00070da9fd241c269fa3 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 16 May 2018 11:19:05 +0200 Subject: [PATCH 0853/1154] stellar: typo in comment removed see discussion at https://github.com/trezor/trezor-mcu/commit/8e8749dc6826996dd8dbf0fb3332bc817b9de946#r28978964 --- firmware/stellar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index 80dd1eb13c..fbb449c4e5 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -99,7 +99,7 @@ void stellar_signingInit(StellarSignTx *msg) stellar_hashupdate_bytes(network_hash, sizeof(network_hash)); stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); - // Public key comes from deriving the specified account path (we ignore the one sent by the client) + // Public key comes from deriving the specified account path uint8_t bytes_pubkey[32]; stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, bytes_pubkey, sizeof(bytes_pubkey)); memcpy(&(stellar_activeTx.signing_pubkey), bytes_pubkey, sizeof(stellar_activeTx.signing_pubkey)); From f302b04f311d2a4d0bc2cd3e21eab807857b4a53 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 16 May 2018 18:00:14 +0200 Subject: [PATCH 0854/1154] fsm: don't show progress bar in GetAddress --- firmware/fsm_msg_coin.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index c482fe8f65..dbf48ab346 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -161,10 +161,8 @@ void fsm_msgGetAddress(GetAddress *msg) hdnode_fill_public_key(node); char address[MAX_ADDR_SIZE]; - layoutProgress(_("Computing address"), 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); - layoutHome(); return; } From 1bb068d18f04c48345e94afbb68a8810ee3b5bb3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 17 May 2018 13:08:04 +0200 Subject: [PATCH 0855/1154] Revert "fsm: don't show progress bar in GetAddress" This reverts commit f302b04f311d2a4d0bc2cd3e21eab807857b4a53. --- firmware/fsm_msg_coin.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index dbf48ab346..c482fe8f65 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -161,8 +161,10 @@ void fsm_msgGetAddress(GetAddress *msg) hdnode_fill_public_key(node); char address[MAX_ADDR_SIZE]; + layoutProgress(_("Computing address"), 0); if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); + layoutHome(); return; } From 233f2f1cfddde95562b731f46dc35bdf7d122127 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 17 May 2018 13:17:46 +0200 Subject: [PATCH 0856/1154] fsm: don't show progress bar in GetAddress unless multisig is used --- firmware/fsm_msg_coin.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index c482fe8f65..15942e2be0 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -161,7 +161,9 @@ void fsm_msgGetAddress(GetAddress *msg) hdnode_fill_public_key(node); char address[MAX_ADDR_SIZE]; - layoutProgress(_("Computing address"), 0); + if (msg->has_multisig) { // use progress bar only for multisig + layoutProgress(_("Computing address"), 0); + } if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); layoutHome(); From 370c58929c306ec179210ef0651dcadecb49c55d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 21 May 2018 15:50:53 +0200 Subject: [PATCH 0857/1154] fsm: use passphrase protection instead of passphrase encryption --- firmware/fsm_msg_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index bd1e13c44e..828cd0cedf 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -294,7 +294,7 @@ void fsm_msgApplySettings(ApplySettings *msg) } } if (msg->has_use_passphrase) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("encryption?"), NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); From 59c8b66ba4f868c9a5251eab604556157b4316a6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 21 May 2018 16:33:41 +0200 Subject: [PATCH 0858/1154] protob: update trezor-common --- firmware/protob/messages.options | 367 ++++++++++++++++--------------- firmware/protob/types.options | 12 +- vendor/trezor-common | 2 +- 3 files changed, 199 insertions(+), 182 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 5e3028ed04..8e21a7d8d4 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -1,267 +1,276 @@ -Initialize.state max_size:64 +Initialize.state max_size:64 -Features.vendor max_size:33 -Features.device_id max_size:25 -Features.language max_size:17 -Features.label max_size:33 -Features.coins max_count:16 -Features.revision max_size:20 -Features.bootloader_hash max_size:32 -Features.model max_size:17 -Features.fw_vendor max_size:256 -Features.fw_vendor_keys max_size:32 +Features.vendor max_size:33 +Features.device_id max_size:25 +Features.language max_size:17 +Features.label max_size:33 +Features.coins max_count:16 +Features.revision max_size:20 +Features.bootloader_hash max_size:32 +Features.model max_size:17 +Features.fw_vendor max_size:256 +Features.fw_vendor_keys max_size:32 -ApplySettings.language max_size:17 -ApplySettings.label max_size:33 -ApplySettings.homescreen max_size:1024 +ApplySettings.language max_size:17 +ApplySettings.label max_size:33 +ApplySettings.homescreen max_size:1024 -Ping.message max_size:256 +Ping.message max_size:256 -Success.message max_size:256 +Success.message max_size:256 -Failure.message max_size:256 +Failure.message max_size:256 -ButtonRequest.data max_size:256 +ButtonRequest.data max_size:256 -PinMatrixAck.pin max_size:10 +PinMatrixAck.pin max_size:10 -PassphraseAck.passphrase max_size:51 -PassphraseAck.state max_size:64 +PassphraseAck.passphrase max_size:51 +PassphraseAck.state max_size:64 -PassphraseStateRequest.state max_size:64 +PassphraseStateRequest.state max_size:64 -Entropy.entropy max_size:1024 +Entropy.entropy max_size:1024 -GetPublicKey.address_n max_count:8 -GetPublicKey.ecdsa_curve_name max_size:32 -GetPublicKey.coin_name max_size:21 +GetPublicKey.address_n max_count:8 +GetPublicKey.ecdsa_curve_name max_size:32 +GetPublicKey.coin_name max_size:21 -PublicKey.xpub max_size:113 +PublicKey.xpub max_size:113 -GetAddress.address_n max_count:8 -GetAddress.coin_name max_size:21 +GetAddress.address_n max_count:8 +GetAddress.coin_name max_size:21 -Address.address max_size:130 +Address.address max_size:130 -EthereumGetAddress.address_n max_count:8 -EthereumAddress.address max_size:20 +EthereumGetAddress.address_n max_count:8 +EthereumAddress.address max_size:20 -LoadDevice.mnemonic max_size:241 -LoadDevice.pin max_size:10 -LoadDevice.language max_size:17 -LoadDevice.label max_size:33 +LoadDevice.mnemonic max_size:241 +LoadDevice.pin max_size:10 +LoadDevice.language max_size:17 +LoadDevice.label max_size:33 -ResetDevice.language max_size:17 -ResetDevice.label max_size:33 +ResetDevice.language max_size:17 +ResetDevice.label max_size:33 -EntropyAck.entropy max_size:128 +EntropyAck.entropy max_size:128 -RecoveryDevice.language max_size:17 -RecoveryDevice.label max_size:33 +RecoveryDevice.language max_size:17 +RecoveryDevice.label max_size:33 -WordAck.word max_size:12 +WordAck.word max_size:12 -SignMessage.address_n max_count:8 -SignMessage.message max_size:1024 -SignMessage.coin_name max_size:21 +SignMessage.address_n max_count:8 +SignMessage.message max_size:1024 +SignMessage.coin_name max_size:21 -VerifyMessage.address max_size:130 -VerifyMessage.signature max_size:65 -VerifyMessage.message max_size:1024 -VerifyMessage.coin_name max_size:21 +VerifyMessage.address max_size:130 +VerifyMessage.signature max_size:65 +VerifyMessage.message max_size:1024 +VerifyMessage.coin_name max_size:21 -MessageSignature.address max_size:130 -MessageSignature.signature max_size:65 +MessageSignature.address max_size:130 +MessageSignature.signature max_size:65 -EthereumSignMessage.address_n max_count:8 -EthereumSignMessage.message max_size:1024 +EthereumSignMessage.address_n max_count:8 +EthereumSignMessage.message max_size:1024 -EthereumVerifyMessage.address max_size:20 -EthereumVerifyMessage.signature max_size:65 -EthereumVerifyMessage.message max_size:1024 +EthereumVerifyMessage.address max_size:20 +EthereumVerifyMessage.signature max_size:65 +EthereumVerifyMessage.message max_size:1024 -EthereumMessageSignature.address max_size:20 -EthereumMessageSignature.signature max_size:65 +EthereumMessageSignature.address max_size:20 +EthereumMessageSignature.signature max_size:65 # deprecated -EncryptMessage skip_message:true -# EncryptMessage.pubkey max_size:33 -# EncryptMessage.message max_size:1024 -# EncryptMessage.address_n max_count:8 -# EncryptMessage.coin_name max_size:21 +EncryptMessage skip_message:true +# EncryptMessage.pubkey max_size:33 +# EncryptMessage.message max_size:1024 +# EncryptMessage.address_n max_count:8 +# EncryptMessage.coin_name max_size:21 # deprecated -EncryptedMessage skip_message:true -# EncryptedMessage.nonce max_size:33 -# EncryptedMessage.message max_size:1120 -# EncryptedMessage.hmac max_size:8 +EncryptedMessage skip_message:true +# EncryptedMessage.nonce max_size:33 +# EncryptedMessage.message max_size:1120 +# EncryptedMessage.hmac max_size:8 # deprecated -DecryptMessage skip_message:true -# DecryptMessage.address_n max_count:8 -# DecryptMessage.nonce max_size:33 -# DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 -# DecryptMessage.hmac max_size:8 +DecryptMessage skip_message:true +# DecryptMessage.address_n max_count:8 +# DecryptMessage.nonce max_size:33 +# DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 +# DecryptMessage.hmac max_size:8 # deprecated -DecryptedMessage skip_message:true -# DecryptedMessage.address max_size:130 -# DecryptedMessage.message max_size:1024 +DecryptedMessage skip_message:true +# DecryptedMessage.address max_size:130 +# DecryptedMessage.message max_size:1024 -CipherKeyValue.address_n max_count:8 -CipherKeyValue.key max_size:256 -CipherKeyValue.value max_size:1024 -CipherKeyValue.iv max_size:16 +CipherKeyValue.address_n max_count:8 +CipherKeyValue.key max_size:256 +CipherKeyValue.value max_size:1024 +CipherKeyValue.iv max_size:16 -CipheredKeyValue.value max_size:1024 +CipheredKeyValue.value max_size:1024 # deprecated -EstimateTxSize skip_message:true -# EstimateTxSize.coin_name max_size:21 +EstimateTxSize skip_message:true +# EstimateTxSize.coin_name max_size:21 # deprecated -TxSize skip_message:true +TxSize skip_message:true -SignTx.coin_name max_size:21 +SignTx.coin_name max_size:21 -EthereumSignTx.address_n max_count:8 -EthereumSignTx.nonce max_size:32 -EthereumSignTx.gas_price max_size:32 -EthereumSignTx.gas_limit max_size:32 -EthereumSignTx.to max_size:20 -EthereumSignTx.value max_size:32 -EthereumSignTx.data_initial_chunk max_size:1024 +EthereumSignTx.address_n max_count:8 +EthereumSignTx.nonce max_size:32 +EthereumSignTx.gas_price max_size:32 +EthereumSignTx.gas_limit max_size:32 +EthereumSignTx.to max_size:20 +EthereumSignTx.value max_size:32 +EthereumSignTx.data_initial_chunk max_size:1024 -EthereumTxRequest.signature_r max_size:32 -EthereumTxRequest.signature_s max_size:32 +EthereumTxRequest.signature_r max_size:32 +EthereumTxRequest.signature_s max_size:32 -EthereumTxAck.data_chunk max_size:1024 +EthereumTxAck.data_chunk max_size:1024 -SignIdentity.challenge_hidden max_size:256 -SignIdentity.challenge_visual max_size:256 -SignIdentity.ecdsa_curve_name max_size:32 +SignIdentity.challenge_hidden max_size:256 +SignIdentity.challenge_visual max_size:256 +SignIdentity.ecdsa_curve_name max_size:32 -SignedIdentity.address max_size:130 -SignedIdentity.public_key max_size:33 -SignedIdentity.signature max_size:65 +SignedIdentity.address max_size:130 +SignedIdentity.public_key max_size:33 +SignedIdentity.signature max_size:65 -GetECDHSessionKey.peer_public_key max_size:65 -GetECDHSessionKey.ecdsa_curve_name max_size:32 +GetECDHSessionKey.peer_public_key max_size:65 +GetECDHSessionKey.ecdsa_curve_name max_size:32 -ECDHSessionKey.session_key max_size:65 +ECDHSessionKey.session_key max_size:65 -NEMGetAddress.address_n max_count:8 +NEMGetAddress.address_n max_count:8 -NEMAddress.address max_size:41 +NEMAddress.address max_size:41 -NEMSignedTx.data max_size:2048 -NEMSignedTx.signature max_size:64 +NEMSignedTx.data max_size:2048 +NEMSignedTx.signature max_size:64 -NEMDecryptMessage.address_n max_count:8 -NEMDecryptMessage.public_key max_size:32 -NEMDecryptMessage.payload max_size:1072 +NEMDecryptMessage.address_n max_count:8 +NEMDecryptMessage.public_key max_size:32 +NEMDecryptMessage.payload max_size:1072 -NEMDecryptedMessage.payload max_size:1024 +NEMDecryptedMessage.payload max_size:1024 -CosiCommit.address_n max_count:8 -CosiCommit.data max_size:32 +CosiCommit.address_n max_count:8 +CosiCommit.data max_size:32 -CosiCommitment.commitment max_size:32 -CosiCommitment.pubkey max_size:32 +CosiCommitment.commitment max_size:32 +CosiCommitment.pubkey max_size:32 -CosiSign.address_n max_count:8 -CosiSign.data max_size:32 -CosiSign.global_commitment max_size:32 -CosiSign.global_pubkey max_size:32 - -CosiSignature.signature max_size:32 +CosiSign.address_n max_count:8 +CosiSign.data max_size:32 +CosiSign.global_commitment max_size:32 +CosiSign.global_pubkey max_size:32 +CosiSignature.signature max_size:32 # Stellar -StellarGetPublicKey.address_n max_count:10 -StellarPublicKey.public_key max_size:32 +StellarGetPublicKey.address_n max_count:10 -StellarSignMessage.address_n max_count:10 -StellarSignMessage.message max_size:1024 +StellarPublicKey.public_key max_size:32 -StellarMessageSignature.public_key max_size:32 -StellarMessageSignature.signature max_size:64 +StellarSignMessage.address_n max_count:10 +StellarSignMessage.message max_size:1024 -StellarVerifyMessage.public_key max_size:32 -StellarVerifyMessage.message max_size:1024 -StellarVerifyMessage.signature max_size:64 +StellarMessageSignature.public_key max_size:32 +StellarMessageSignature.signature max_size:64 -StellarMessageVerification.public_key max_size: 32 +StellarVerifyMessage.public_key max_size:32 +StellarVerifyMessage.message max_size:1024 +StellarVerifyMessage.signature max_size:64 -StellarSignTx.address_n max_count:10 -StellarSignTx.network_passphrase max_size:1024 -StellarSignTx.source_account max_size:32 -StellarSignTx.memo_text max_size:29 -StellarSignTx.memo_hash max_size:32 +StellarSignTx.address_n max_count:10 +StellarSignTx.network_passphrase max_size:1024 +StellarSignTx.source_account max_size:32 +StellarSignTx.memo_text max_size:29 +StellarSignTx.memo_hash max_size:32 -StellarPaymentOp.source_account max_size:32 -StellarPaymentOp.destination_account max_size:32 +StellarPaymentOp.source_account max_size:32 +StellarPaymentOp.destination_account max_size:32 -StellarCreateAccountOp.source_account max_size:32 -StellarCreateAccountOp.new_account max_size:32 +StellarCreateAccountOp.source_account max_size:32 +StellarCreateAccountOp.new_account max_size:32 -StellarPathPaymentOp.source_account max_size:32 -StellarPathPaymentOp.destination_account max_size:32 -StellarPathPaymentOp.paths max_count:5 +StellarPathPaymentOp.source_account max_size:32 +StellarPathPaymentOp.destination_account max_size:32 +StellarPathPaymentOp.paths max_count:5 -StellarManageOfferOp.source_account max_size:32 +StellarManageOfferOp.source_account max_size:32 -StellarCreatePassiveOfferOp.source_account max_size:32 +StellarCreatePassiveOfferOp.source_account max_size:32 -StellarSetOptionsOp.source_account max_size:32 -StellarSetOptionsOp.inflation_destination_account max_size:32 -StellarSetOptionsOp.home_domain max_size:33 -StellarSetOptionsOp.signer_key max_size:32 +StellarSetOptionsOp.source_account max_size:32 +StellarSetOptionsOp.inflation_destination_account max_size:32 +StellarSetOptionsOp.home_domain max_size:33 +StellarSetOptionsOp.signer_key max_size:32 -StellarChangeTrustOp.source_account max_size:32 +StellarChangeTrustOp.source_account max_size:32 -StellarAllowTrustOp.source_account max_size:32 -StellarAllowTrustOp.trusted_account max_size:32 -StellarAllowTrustOp.asset_code max_size:13 +StellarAllowTrustOp.source_account max_size:32 +StellarAllowTrustOp.trusted_account max_size:32 +StellarAllowTrustOp.asset_code max_size:13 -StellarAccountMergeOp.source_account max_size:32 -StellarAccountMergeOp.destination_account max_size:32 +StellarAccountMergeOp.source_account max_size:32 +StellarAccountMergeOp.destination_account max_size:32 -StellarManageDataOp.source_account max_size:32 -StellarManageDataOp.key max_size:65 -StellarManageDataOp.value max_size:65 +StellarManageDataOp.source_account max_size:32 +StellarManageDataOp.key max_size:65 +StellarManageDataOp.value max_size:65 -StellarBumpSequenceOp.source_account max_size:32 - -StellarSignedTx.public_key max_size:32 -StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint +StellarBumpSequenceOp.source_account max_size:32 +StellarSignedTx.public_key max_size:32 +StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint # deprecated -SimpleSignTx skip_message:true +SimpleSignTx skip_message:true # not used in firmware, just in bootloader -FirmwareErase skip_message:true -FirmwareRequest skip_message:true -FirmwareUpload skip_message:true -SelfTest skip_message:true +FirmwareErase skip_message:true +FirmwareRequest skip_message:true +FirmwareUpload skip_message:true +SelfTest skip_message:true + +# Lisk will be supported later + +LiskGetAddress skip_message:true +LiskSignTx skip_message:true +LiskSignMessage skip_message:true +LiskVerifyMessage skip_message:true +LiskGetPublicKey skip_message:true +LiskAddress skip_message:true +LiskSignedTx skip_message:true +LiskMessageSignature skip_message:true +LiskPublicKey skip_message:true # used only in debug firmware -DebugLinkDecision.input max_size:33 +DebugLinkDecision.input max_size:33 -DebugLinkState.layout max_size:1024 -DebugLinkState.pin max_size:10 -DebugLinkState.matrix max_size:10 -DebugLinkState.mnemonic max_size:241 -DebugLinkState.reset_word max_size:12 -DebugLinkState.reset_entropy max_size:128 -DebugLinkState.recovery_fake_word max_size:12 +DebugLinkState.layout max_size:1024 +DebugLinkState.pin max_size:10 +DebugLinkState.matrix max_size:10 +DebugLinkState.mnemonic max_size:241 +DebugLinkState.reset_word max_size:12 +DebugLinkState.reset_entropy max_size:128 +DebugLinkState.recovery_fake_word max_size:12 -DebugLinkLog.bucket max_size:33 -DebugLinkLog.text max_size:256 +DebugLinkLog.bucket max_size:33 +DebugLinkLog.text max_size:256 -DebugLinkMemory.memory max_size:1024 -DebugLinkMemoryWrite.memory max_size:1024 +DebugLinkMemory.memory max_size:1024 +DebugLinkMemoryWrite.memory max_size:1024 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index ea53f085c7..f8aa00fccd 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -73,5 +73,13 @@ NEMCosignatoryModification.public_key max_size:32 NEMImportanceTransfer.public_key max_size:32 -StellarAssetType.code max_size:13 -StellarAssetType.issuer max_size:32 \ No newline at end of file +StellarAssetType.code max_size:13 +StellarAssetType.issuer max_size:32 + +# Lisk will be supported later + +LiskTransactionCommon skip_message:true +LiskTransactionAsset skip_message:true +LiskSignatureType skip_message:true +LiskDelegateType skip_message:true +LiskMultisignatureType skip_message:true diff --git a/vendor/trezor-common b/vendor/trezor-common index b91db285ba..f54cf5073c 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit b91db285ba8947d6c65a6a807fba87ebc1d43f5d +Subproject commit f54cf5073c550d92338beb7e8c70ec703d63aee8 From ae82735b6b7ecbe46a0baf3243ccd0f3e73ca21d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 May 2018 18:32:04 +0200 Subject: [PATCH 0859/1154] protob: remove Stellar{SignMessage,MessageSignature,VerifyMessage} --- firmware/fsm.h | 2 -- firmware/fsm_msg_stellar.h | 40 -------------------------------- firmware/protob/messages.options | 13 ----------- firmware/stellar.c | 17 -------------- firmware/stellar.h | 3 --- vendor/trezor-common | 2 +- 6 files changed, 1 insertion(+), 76 deletions(-) diff --git a/firmware/fsm.h b/firmware/fsm.h index 6bdb22c490..b8af6d1549 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -93,8 +93,6 @@ void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg); void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg); void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); -void fsm_msgStellarSignMessage(StellarSignMessage *msg); -void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg); void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); // debug message functions diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index de92b76b65..d621323a52 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -19,46 +19,6 @@ void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) layoutHome(); } -void fsm_msgStellarSignMessage(StellarSignMessage *msg) -{ - RESP_INIT(StellarMessageSignature); - - CHECK_INITIALIZED - - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - - CHECK_PIN - - // Populate response message - stellar_signMessage(msg->message.bytes, msg->message.size, msg->address_n, msg->address_n_count, resp->signature.bytes); - resp->has_signature = true; - resp->signature.size = 64; - - stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); - resp->has_public_key = true; - resp->public_key.size = 32; - - msg_write(MessageType_MessageType_StellarMessageSignature, resp); - - layoutHome(); -} - -void fsm_msgStellarVerifyMessage(StellarVerifyMessage *msg) -{ - if (!stellar_verifyMessage(msg)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - return; - } - - fsm_sendSuccess(_("Message verified")); - layoutHome(); -} - void fsm_msgStellarSignTx(StellarSignTx *msg) { CHECK_INITIALIZED diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 8e21a7d8d4..f1d69fb7ef 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -182,16 +182,6 @@ StellarGetPublicKey.address_n max_count:10 StellarPublicKey.public_key max_size:32 -StellarSignMessage.address_n max_count:10 -StellarSignMessage.message max_size:1024 - -StellarMessageSignature.public_key max_size:32 -StellarMessageSignature.signature max_size:64 - -StellarVerifyMessage.public_key max_size:32 -StellarVerifyMessage.message max_size:1024 -StellarVerifyMessage.signature max_size:64 - StellarSignTx.address_n max_count:10 StellarSignTx.network_passphrase max_size:1024 StellarSignTx.source_account max_size:32 @@ -249,12 +239,9 @@ SelfTest skip_message:true LiskGetAddress skip_message:true LiskSignTx skip_message:true -LiskSignMessage skip_message:true -LiskVerifyMessage skip_message:true LiskGetPublicKey skip_message:true LiskAddress skip_message:true LiskSignedTx skip_message:true -LiskMessageSignature skip_message:true LiskPublicKey skip_message:true # used only in debug firmware diff --git a/firmware/stellar.c b/firmware/stellar.c index fbb449c4e5..f0fc3d8b6d 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -1130,23 +1130,6 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature) memcpy(out_signature, signature, sizeof(signature)); } -void stellar_signMessage(const uint8_t *message, uint32_t message_len, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature) -{ - HDNode *node = stellar_deriveNode(address_n, address_n_count); - ed25519_sign(message, message_len, node->private_key, node->public_key + 1, out_signature); -} - -bool stellar_verifyMessage(StellarVerifyMessage *msg) -{ - // returns 0 if signature is valid - return ed25519_sign_open( - msg->message.bytes, - msg->message.size, - msg->public_key.bytes, - msg->signature.bytes - ) == 0; -} - /* * Returns number (representing stroops) formatted as XLM * For example, if number has value 1000000000 then it will be returned as "100.0" diff --git a/firmware/stellar.h b/firmware/stellar.h index d94bfb6ab8..57c1697b22 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -57,9 +57,6 @@ void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); void stellar_confirmManageDataOp(StellarManageDataOp *msg); void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); -void stellar_signMessage(const uint8_t *message, uint32_t message_len, uint32_t *address_n, size_t address_n_count, uint8_t *out_signature); -bool stellar_verifyMessage(StellarVerifyMessage *msg); - // Layout void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count); void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); diff --git a/vendor/trezor-common b/vendor/trezor-common index f54cf5073c..fb662e53b1 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit f54cf5073c550d92338beb7e8c70ec703d63aee8 +Subproject commit fb662e53b129b250149d982259696531ff4c2b95 From a83c64fbdb1fcbf0f9ad74d4b53c7c3e089c0e8f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 22 May 2018 18:40:15 +0200 Subject: [PATCH 0860/1154] protob: don't return coins in Features message --- firmware/coins.c | 2 +- firmware/coins.h | 2 +- firmware/fsm_msg_common.h | 29 ----------------------------- firmware/layout2.c | 2 +- firmware/protob/messages.options | 2 +- firmware/protob/types.options | 6 +++--- 6 files changed, 7 insertions(+), 36 deletions(-) diff --git a/firmware/coins.c b/firmware/coins.c index 1acd8f5221..a53155fbdc 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -44,7 +44,7 @@ const CoinInfo *coinByAddressType(uint32_t address_type) return 0; } -const CoinInfo *coinByCoinType(uint32_t coin_type) +const CoinInfo *coinBySlip44(uint32_t coin_type) { for (int i = 0; i < COINS_COUNT; i++) { if (coin_type == coins[i].coin_type) { diff --git a/firmware/coins.h b/firmware/coins.h index a344c17845..1535824384 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -54,7 +54,7 @@ typedef struct _CoinInfo { const CoinInfo *coinByName(const char *name); const CoinInfo *coinByAddressType(uint32_t address_type); -const CoinInfo *coinByCoinType(uint32_t coin_type); +const CoinInfo *coinBySlip44(uint32_t coin_type); bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 828cd0cedf..6dfc2d0726 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -42,36 +42,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) resp->has_label = true; strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); } - - _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); - resp->coins_count = COINS_COUNT; - for (int i = 0; i < COINS_COUNT; i++) { - if (coins[i].coin_name) { - resp->coins[i].has_coin_name = true; - strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); - } - if (coins[i].coin_shortcut) { - resp->coins[i].has_coin_shortcut = true; - strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut + 1, sizeof(resp->coins[i].coin_shortcut)); - } - resp->coins[i].has_address_type = coins[i].has_address_type; - resp->coins[i].address_type = coins[i].address_type; - resp->coins[i].has_maxfee_kb = true; - resp->coins[i].maxfee_kb = coins[i].maxfee_kb; - resp->coins[i].has_address_type_p2sh = coins[i].has_address_type_p2sh; - resp->coins[i].address_type_p2sh = coins[i].address_type_p2sh; - resp->coins[i].has_xpub_magic = coins[i].xpub_magic != 0; - resp->coins[i].xpub_magic = coins[i].xpub_magic; - resp->coins[i].has_xprv_magic = coins[i].xprv_magic != 0; - resp->coins[i].xprv_magic = coins[i].xprv_magic; - resp->coins[i].has_segwit = true; - resp->coins[i].segwit = coins[i].has_segwit; - resp->coins[i].has_forkid = coins[i].has_forkid; - resp->coins[i].forkid = coins[i].forkid; - resp->coins[i].has_force_bip143 = true; - resp->coins[i].force_bip143 = coins[i].force_bip143; - } resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); diff --git a/firmware/layout2.c b/firmware/layout2.c index 9dd53368d4..b3a39cf098 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -75,7 +75,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou bool native_segwit = (address_n[0] == (0x80000000 + 84)); bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); bool legacy = false; - const CoinInfo *coin = coinByCoinType(address_n[1]); + const CoinInfo *coin = coinBySlip44(address_n[1]); const char *abbr = 0; if (native_segwit) { if (coin && coin->has_segwit && coin->bech32_prefix) { diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index f1d69fb7ef..5a035c92bb 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -4,7 +4,7 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:16 +Features.coins max_count:0 Features.revision max_size:20 Features.bootloader_hash max_size:32 Features.model max_size:17 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index f8aa00fccd..6a1efd11a8 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -4,9 +4,9 @@ HDNodeType.public_key max_size:33 HDNodePathType.address_n max_count:8 -CoinType.coin_name max_size:17 -CoinType.coin_shortcut max_size:9 -CoinType.signed_message_header max_size:32 +CoinType.coin_name max_size:0 +CoinType.coin_shortcut max_size:0 +CoinType.signed_message_header max_size:0 TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 From 1fdcd916c48152e31f1fec3d718c252fe5af7362 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 May 2018 15:46:38 +0200 Subject: [PATCH 0861/1154] fix emulator build --- memory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/memory.h b/memory.h index a10a3b3bd3..eac09efa5f 100644 --- a/memory.h +++ b/memory.h @@ -111,10 +111,10 @@ void memory_protect(void); void memory_write_unlock(void); int memory_bootloader_hash(uint8_t *hash); -inline void flash_write32(uint32_t addr, uint32_t word) { +static inline void flash_write32(uint32_t addr, uint32_t word) { *(volatile uint32_t *) FLASH_PTR(addr) = word; } -inline void flash_write8(uint32_t addr, uint8_t byte) { +static inline void flash_write8(uint32_t addr, uint8_t byte) { *(volatile uint8_t *) FLASH_PTR(addr) = byte; } From bccba48f41f450d01d7edde9178edbb5505dbc59 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 24 May 2018 13:52:57 +0200 Subject: [PATCH 0862/1154] protob: drop CoinType completely --- firmware/protob/messages.options | 1 - firmware/protob/types.options | 4 ---- vendor/trezor-common | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 5a035c92bb..0c66b476d8 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -4,7 +4,6 @@ Features.vendor max_size:33 Features.device_id max_size:25 Features.language max_size:17 Features.label max_size:33 -Features.coins max_count:0 Features.revision max_size:20 Features.bootloader_hash max_size:32 Features.model max_size:17 diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 6a1efd11a8..07d1db77e3 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -4,10 +4,6 @@ HDNodeType.public_key max_size:33 HDNodePathType.address_n max_count:8 -CoinType.coin_name max_size:0 -CoinType.coin_shortcut max_size:0 -CoinType.signed_message_header max_size:0 - TxInputType.address_n max_count:8 TxInputType.prev_hash max_size:32 TxInputType.script_sig max_size:1650 diff --git a/vendor/trezor-common b/vendor/trezor-common index fb662e53b1..0c9d67954c 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit fb662e53b129b250149d982259696531ff4c2b95 +Subproject commit 0c9d67954c871553a7d44575a7a9198cba83df88 From 1f470cf1f18de0235675cf71091bba7bf4fb762f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 May 2018 14:22:54 +0200 Subject: [PATCH 0863/1154] ethereum: use original ethereum message digest --- firmware/ethereum.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index a71e41a88d..17cc9dbf7e 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -628,9 +628,17 @@ static void ethereum_message_hash(const uint8_t *message, size_t message_len, ui struct SHA3_CTX ctx; sha3_256_Init(&ctx); sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); - uint8_t varint[5]; - uint32_t l = ser_length(message_len, varint); - sha3_Update(&ctx, varint, l); + uint8_t c; + if (message_len > 1000000000) { c = '0' + message_len / 1000000000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 100000000) { c = '0' + message_len / 100000000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 10000000) { c = '0' + message_len / 10000000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 1000000) { c = '0' + message_len / 1000000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 100000) { c = '0' + message_len / 100000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 10000) { c = '0' + message_len / 10000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 1000) { c = '0' + message_len / 1000 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 100) { c = '0' + message_len / 100 % 10; sha3_Update(&ctx, &c, 1); } + if (message_len > 10) { c = '0' + message_len / 10 % 10; sha3_Update(&ctx, &c, 1); } + c = '0' + message_len % 10; sha3_Update(&ctx, &c, 1); sha3_Update(&ctx, message, message_len); keccak_Final(&ctx, hash); } From 0ae5e91fcb3f31c0d2e664691998a9b0f665176c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 May 2018 16:34:06 +0200 Subject: [PATCH 0864/1154] nem: check length in layoutNEMTransferPayload --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index b3a39cf098..6d47a8322d 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -759,7 +759,7 @@ void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, u } void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted) { - if (payload[0] == 0xFE) { + if (length >= 1 && payload[0] == 0xFE) { char encoded[(length - 1) * 2 + 1]; data2hex(&payload[1], length - 1, encoded); From e2275a8b83951e2f274c56c3021078f07038bca8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 29 May 2018 17:17:29 +0200 Subject: [PATCH 0865/1154] firmware: use new coin definitions from trezor-common --- firmware/Makefile | 4 ++-- firmware/coin_info.py | 29 ++++++++++++++++++----------- firmware/coins.h | 4 ++-- firmware/coins.json | 1 - firmware/defs | 1 + firmware/nem_mosaics.json | 1 - firmware/nem_mosaics.py | 2 +- firmware/signing.c | 4 ++-- vendor/trezor-common | 2 +- 9 files changed, 27 insertions(+), 21 deletions(-) delete mode 120000 firmware/coins.json create mode 120000 firmware/defs delete mode 120000 firmware/nem_mosaics.json diff --git a/firmware/Makefile b/firmware/Makefile index e760d57f38..a7c36296bd 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -119,6 +119,6 @@ clean:: rm -f $(1).h $(3) endef -$(eval $(call GENERATE_CODE,coin_info,coins.json,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,nem_mosaics.json,nem_mosaics.c)) +$(eval $(call GENERATE_CODE,coin_info,defs,coin_info.c)) +$(eval $(call GENERATE_CODE,nem_mosaics,defs/nem/nem_mosaics.json,nem_mosaics.c)) $(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) diff --git a/firmware/coin_info.py b/firmware/coin_info.py index 6a6b119d6f..4a73d766ac 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -63,7 +63,7 @@ def format_string(value): def format_hex(value): if value is None: value = "0" - return "0x{:08x}".format(int(value, 16)) + return "0x{:08x}".format(value) def prepend_varint(string): @@ -78,22 +78,22 @@ def coin_to_struct(coin): ("coin_name", format_string(coin["coin_name"])), ("coin_shortcut", format_string(" " + coin["coin_shortcut"])), ("maxfee_kb", format_number(coin["maxfee_kb"])), - ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 - ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 - ("has_address_type_p2sh", format_bool(coin["address_type_p2sh"] is not None)), # noqa: E501 + ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 + ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 + ("has_address_type_p2sh", format_bool(coin["address_type_p2sh"] is not None)), # noqa: E501 ("has_segwit", format_bool(coin["segwit"])), - ("has_forkid", format_bool(coin["forkid"] is not None)), + ("has_fork_id", format_bool(coin["fork_id"] is not None)), ("force_bip143", format_bool(coin["force_bip143"])), ("decred", format_bool(coin["decred"])), ("address_type", format_number(coin["address_type"])), ("address_type_p2sh", format_number(coin["address_type_p2sh"])), ("xpub_magic", format_hex(coin["xpub_magic"])), ("xprv_magic", format_hex(coin["xprv_magic"])), - ("forkid", format_number(coin["forkid"])), + ("fork_id", format_number(coin["fork_id"])), ("bech32_prefix", format_string(coin["bech32_prefix"])), ("cashaddr_prefix", format_string(coin["cashaddr_prefix"])), - ("coin_type", "({} | 0x80000000)".format(format_number(coin["bip44"]))), # noqa: E501 - ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 + ("coin_type", "({} | 0x80000000)".format(format_number(coin["slip44"]))), # noqa: E501 + ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 ("curve", "&{}_info".format(coin["curve_name"])), )) @@ -118,9 +118,16 @@ if __name__ == "__main__": coins = collections.defaultdict(list) - for coin in json.load(open("coins.json")): - firmware = coin["firmware"] - coins[firmware].append(coin) + support = json.load(open('defs/support.json', 'r'), object_pairs_hook=collections.OrderedDict) + defs = support['trezor1'].keys() + + for c in defs: + name = c.replace(' ', '_').lower() + firmware = 'debug' if name.endswith('_testnet') else 'stable' + if name == 'testnet': + name = 'bitcoin_testnet' + data = json.load(open('defs/coins/%s.json' % name, 'r')) + coins[firmware].append(data) with open("coin_info.h", "w+") as f: f.write(HEADER_TEMPLATE.format(**{ diff --git a/firmware/coins.h b/firmware/coins.h index 1535824384..5a9596a13f 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -34,7 +34,7 @@ typedef struct _CoinInfo { bool has_address_type; bool has_address_type_p2sh; bool has_segwit; - bool has_forkid; + bool has_fork_id; bool force_bip143; bool decred; // address types > 0xFF represent a two-byte prefix in big-endian order @@ -42,7 +42,7 @@ typedef struct _CoinInfo { uint32_t address_type_p2sh; uint32_t xpub_magic; uint32_t xprv_magic; - uint32_t forkid; + uint32_t fork_id; const char *bech32_prefix; const char *cashaddr_prefix; uint32_t coin_type; diff --git a/firmware/coins.json b/firmware/coins.json deleted file mode 120000 index a13f2d9c08..0000000000 --- a/firmware/coins.json +++ /dev/null @@ -1 +0,0 @@ -../vendor/trezor-common/coins.json \ No newline at end of file diff --git a/firmware/defs b/firmware/defs new file mode 120000 index 0000000000..bbc8f8e0c4 --- /dev/null +++ b/firmware/defs @@ -0,0 +1 @@ +../vendor/trezor-common/defs \ No newline at end of file diff --git a/firmware/nem_mosaics.json b/firmware/nem_mosaics.json deleted file mode 120000 index e0481bfc7a..0000000000 --- a/firmware/nem_mosaics.json +++ /dev/null @@ -1 +0,0 @@ -../vendor/trezor-common/defs/nem/nem_mosaics.json \ No newline at end of file diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index 7b9f259996..49fc026c12 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -109,7 +109,7 @@ if __name__ == "__main__": sys.path.insert(0, "protob") import types_pb2 as types - messages = json.load(open("nem_mosaics.json")) + messages = json.load(open("defs/nem/nem_mosaics.json")) with open("nem_mosaics.h", "w+") as f: f.write(HEADER_TEMPLATE.format( diff --git a/firmware/signing.c b/firmware/signing.c index 9ec43cfd35..90f2c6528f 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -702,8 +702,8 @@ static bool signing_check_fee(void) { static uint32_t signing_hash_type(void) { uint32_t hash_type = SIGHASH_ALL; - if (coin->has_forkid) { - hash_type |= (coin->forkid << 8) | SIGHASH_FORKID; + if (coin->has_fork_id) { + hash_type |= (coin->fork_id << 8) | SIGHASH_FORKID; } return hash_type; diff --git a/vendor/trezor-common b/vendor/trezor-common index 0c9d67954c..a0d37a0371 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0c9d67954c871553a7d44575a7a9198cba83df88 +Subproject commit a0d37a0371aba597d3e0f3f1055adf1a9683a5e4 From 613bde0aebad5edbe53f9f1e082b55a64159d352 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 1 Jun 2018 21:24:59 +0200 Subject: [PATCH 0866/1154] crypto: cashaddr for verify message --- firmware/crypto.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 2830f7b010..e538aeb608 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -32,6 +32,7 @@ #include "coins.h" #include "base58.h" #include "segwit_addr.h" +#include "cash_addr.h" uint32_t ser_length(uint32_t len, uint8_t *out) { @@ -177,7 +178,14 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // p2pkh if (signature[0] >= 27 && signature[0] <= 34) { - size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); + size_t len; + if (coin->cashaddr_prefix) { + if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { + return 2; + } + } else { + len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); + } ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_pubkey, recovered_raw); if (memcmp(recovered_raw, addr_raw, len) != 0 || len != address_prefix_bytes_len(coin->address_type) + 20) { From 64cfcf8053e35bab3338c700d6f1904c69b1468d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 5 Jun 2018 11:16:37 +0200 Subject: [PATCH 0867/1154] vendor: update trezor-common; add version_group_id flag (for zcash overwintered tx) --- firmware/coin_info.py | 3 ++- firmware/coins.h | 1 + vendor/trezor-common | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/coin_info.py b/firmware/coin_info.py index 4a73d766ac..c62fa884b5 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -62,7 +62,7 @@ def format_string(value): def format_hex(value): if value is None: - value = "0" + value = 0 return "0x{:08x}".format(value) @@ -90,6 +90,7 @@ def coin_to_struct(coin): ("xpub_magic", format_hex(coin["xpub_magic"])), ("xprv_magic", format_hex(coin["xprv_magic"])), ("fork_id", format_number(coin["fork_id"])), + ("version_group_id", format_hex(coin["version_group_id"])), ("bech32_prefix", format_string(coin["bech32_prefix"])), ("cashaddr_prefix", format_string(coin["cashaddr_prefix"])), ("coin_type", "({} | 0x80000000)".format(format_number(coin["slip44"]))), # noqa: E501 diff --git a/firmware/coins.h b/firmware/coins.h index 5a9596a13f..3a3b8116b8 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -43,6 +43,7 @@ typedef struct _CoinInfo { uint32_t xpub_magic; uint32_t xprv_magic; uint32_t fork_id; + uint32_t version_group_id; const char *bech32_prefix; const char *cashaddr_prefix; uint32_t coin_type; diff --git a/vendor/trezor-common b/vendor/trezor-common index a0d37a0371..5520e98f4a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit a0d37a0371aba597d3e0f3f1055adf1a9683a5e4 +Subproject commit 5520e98f4ab3ffb3ca347b1bfe417c5a380b9cbf From 4b7e4a95571dc4ab34f651b922fde84c24a77a28 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 5 Jun 2018 11:32:47 +0200 Subject: [PATCH 0868/1154] stellar: comment typo --- firmware/stellar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index f0fc3d8b6d..8f13218273 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -1224,7 +1224,7 @@ const char **stellar_lineBreakAddress(uint8_t *addrbytes) * * Examples: * XLM (Native Asset) - * MOBI (G1234) + * MOBI (G123456789000) * ALPHA12EXAMP (G0987) */ void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len) From 413e3c6a14e6d9d3dbbc146bed443e25b3381af2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 5 Jun 2018 13:31:39 +0200 Subject: [PATCH 0869/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 5520e98f4a..0f7118bb3d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 5520e98f4ab3ffb3ca347b1bfe417c5a380b9cbf +Subproject commit 0f7118bb3d27c3c51a89c776c1b083db91f50541 From 49d9fe4d135348e332b2f38d67ba52462503bf4d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 5 Jun 2018 14:09:38 +0200 Subject: [PATCH 0870/1154] firmware: rename decred_expiry to expiry --- firmware/signing.c | 6 +++--- firmware/transaction.c | 6 +++--- firmware/transaction.h | 2 +- vendor/trezor-common | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 90f2c6528f..7bff44b897 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -511,12 +511,12 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; - to.decred_expiry = msg->decred_expiry; + to.expiry = msg->expiry; tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; - ti.decred_expiry = msg->decred_expiry; + ti.expiry = msg->expiry; } // segwit hashes for hashPrevouts and hashSequence @@ -1014,7 +1014,7 @@ void signing_txack(TransactionType *tx) if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; - tp.decred_expiry = tx->decred_expiry; + tp.expiry = tx->expiry; } progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; diff --git a/firmware/transaction.c b/firmware/transaction.c index 03dcbfdac0..3a0b7217d3 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -599,7 +599,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); if (tx->is_decred) { - memcpy(out + 4, &(tx->decred_expiry), 4); + memcpy(out + 4, &(tx->expiry), 4); return 8; } return 4; @@ -609,7 +609,7 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx) { hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); if (tx->is_decred) { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->decred_expiry), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); return 8; } return 4; @@ -701,7 +701,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->size = 0; tx->is_segwit = false; tx->is_decred = false; - tx->decred_expiry = 0; + tx->expiry = 0; hasher_Init(&(tx->hasher), hasher_sign); } diff --git a/firmware/transaction.h b/firmware/transaction.h index 4363a3b2c4..a875a8ceed 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -34,7 +34,7 @@ typedef struct { uint32_t version; uint32_t lock_time; - uint32_t decred_expiry; + uint32_t expiry; bool is_segwit; bool is_decred; diff --git a/vendor/trezor-common b/vendor/trezor-common index 0f7118bb3d..018eebac7e 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0f7118bb3d27c3c51a89c776c1b083db91f50541 +Subproject commit 018eebac7e64ed082486d746d78d279fe815c65d From df0bad4f09bff651023562e22735ab937a576149 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 5 Jun 2018 22:38:39 +0200 Subject: [PATCH 0871/1154] firmware: introduce protectAbortedByCancel --- firmware/fsm.c | 5 ++++- firmware/protect.c | 17 ++++++++--------- firmware/protect.h | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index c707600e20..5997db6a33 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -114,6 +114,9 @@ void fsm_sendFailureDebug(FailureType code, const char *text, const char *source void fsm_sendFailure(FailureType code, const char *text) #endif { + if (protectAbortedByCancel) { + protectAbortedByCancel = false; + } if (protectAbortedByInitialize) { fsm_msgInitialize((Initialize *)0); protectAbortedByInitialize = false; @@ -230,7 +233,7 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { return true; } - if (protectAbortedByInitialize) { + if (protectAbortedByCancel || protectAbortedByInitialize) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return false; diff --git a/firmware/protect.c b/firmware/protect.c index 713881e397..1f778e7728 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -34,6 +34,7 @@ #define MAX_WRONG_PINS 15 +bool protectAbortedByCancel = false; bool protectAbortedByInitialize = false; bool protectButton(ButtonRequestType type, bool confirm_only) @@ -77,9 +78,8 @@ bool protectButton(ButtonRequestType type, bool confirm_only) // check for Cancel / Initialize if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByInitialize = true; - } + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); msg_tiny_id = 0xFFFF; result = false; break; @@ -130,9 +130,8 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { pinmatrix_done(0); - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByInitialize = true; - } + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); msg_tiny_id = 0xFFFF; usbTiny(0); return 0; @@ -182,6 +181,7 @@ bool protectPin(bool use_cached) // wait one second usbSleep(1000); if (msg_tiny_id == MessageType_MessageType_Initialize) { + protectAbortedByCancel = false; protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; usbTiny(0); @@ -263,9 +263,8 @@ bool protectPassphrase(void) break; } if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByInitialize = true; - } + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); msg_tiny_id = 0xFFFF; result = false; break; diff --git a/firmware/protect.h b/firmware/protect.h index efa6163cfb..0836f565f3 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -28,6 +28,7 @@ bool protectPin(bool use_cached); bool protectChangePin(void); bool protectPassphrase(void); +extern bool protectAbortedByCancel; extern bool protectAbortedByInitialize; #endif From a685462ee5dc83cbf12f42354a9c71aa7bd4f99a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 6 Jun 2018 14:45:50 +0200 Subject: [PATCH 0872/1154] firmware: refactor last change in protect.c --- firmware/protect.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 1f778e7728..b66e3520e5 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -77,9 +77,9 @@ bool protectButton(ButtonRequestType type, bool confirm_only) } // check for Cancel / Initialize - if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { msg_tiny_id = 0xFFFF; result = false; break; @@ -128,10 +128,11 @@ const char *requestPin(PinMatrixRequestType type, const char *text) usbTiny(0); return pma->pin; } - if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { + // check for Cancel / Initialize + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { pinmatrix_done(0); - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); msg_tiny_id = 0xFFFF; usbTiny(0); return 0; @@ -262,9 +263,10 @@ bool protectPassphrase(void) result = true; break; } - if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + // check for Cancel / Initialize + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { msg_tiny_id = 0xFFFF; result = false; break; From 747f2aa7729998bbb2df6622a5921f30d9b872f0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 7 Jun 2018 13:17:51 +0200 Subject: [PATCH 0873/1154] firmware: refactor expiry into tx_init --- firmware/signing.c | 17 ++++++++--------- firmware/transaction.c | 4 ++-- firmware/transaction.h | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 7bff44b897..af81ce99b8 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -63,6 +63,7 @@ static uint8_t hash_check[32]; static uint64_t to_spend, authorized_amount, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; +static uint32_t expiry = 0; static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; @@ -477,6 +478,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) root = _root; version = msg->version; lock_time = msg->lock_time; + expiry = msg->expiry; uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); if (coin->decred) { @@ -506,17 +508,15 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; - to.expiry = msg->expiry; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; - ti.expiry = msg->expiry; } // segwit hashes for hashPrevouts and hashSequence @@ -1010,11 +1010,10 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, coin->curve->hasher_sign); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; - tp.expiry = tx->expiry; } progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); idx2 = 0; @@ -1094,7 +1093,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); hasher_Reset(&hashers[0]); } // check prevouts and script type @@ -1289,12 +1288,12 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx1 == 0) { // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); to.is_decred = true; } // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 3a0b7217d3..106dba5a06 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -688,12 +688,13 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_sign) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; tx->version = version; tx->lock_time = lock_time; + tx->expiry = expiry; tx->have_inputs = 0; tx->have_outputs = 0; tx->extra_data_len = extra_data_len; @@ -701,7 +702,6 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->size = 0; tx->is_segwit = false; tx->is_decred = false; - tx->expiry = 0; hasher_Init(&(tx->hasher), hasher_sign); } diff --git a/firmware/transaction.h b/firmware/transaction.h index a875a8ceed..c269c4518d 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -68,7 +68,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, HasherType hasher_sign); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); From 3185eb0fd444701e2bc976555545fe08d572c957 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Thu, 7 Jun 2018 14:48:15 +0200 Subject: [PATCH 0874/1154] build: ciscript includes firmware sign so that emulator build uses pipenv to ensure stable environment for python-trezor but fetching python-trezor and friends doesn't needlessly slow down non-emulator builds that don't need it --- .travis.yml | 11 ++++++++++- Makefile.include | 4 ++-- script/cibuild | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5038918d9..f4f587a0ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,13 +33,22 @@ matrix: - $PYTHON -m pip install --user pipenv - pipenv install script: - - script/cibuild && pipenv run script/test + # use outer environment (with protobuf & ecdsa) to build, + # then use pipenv to run tests + - ./script/cibuild && pipenv run script/test + +# using two "separate" python environments is somewhat unwieldy, and it would be nicer +# to consolidate everything into one. +# Unfortunately, installing pipenv and fetching python-trezor from git takes about one minute. +# For now, we keep the envs separate. If the number of "outer" modules grows significantly, +# they should probably be moved into pipenv. install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc - export PATH="$(pwd)/protoc/bin:$PATH" - $PYTHON -m pip install --user "protobuf==${PROTOBUF_VERSION}" + - $PYTHON -m pip install --user ecdsa # for firmware_sign script: - script/cibuild diff --git a/Makefile.include b/Makefile.include index d257bd329a..9eca4fa482 100644 --- a/Makefile.include +++ b/Makefile.include @@ -143,10 +143,10 @@ upload: sign trezorctl firmware_update -f $(NAME).bin sign: $(NAME).bin - ../bootloader/firmware_sign.py -f $(NAME).bin + $(PYTHON) ../bootloader/firmware_sign.py -f $(NAME).bin release: $(NAME).bin - ../bootloader/firmware_sign.py -f $(NAME).bin + $(PYTHON) ../bootloader/firmware_sign.py -f $(NAME).bin cp $(NAME).bin $(NAME)-$(APPVER).bin chmod -x $(NAME)-$(APPVER).bin xxd -p $(NAME)-$(APPVER).bin | tr -d '\n' > $(NAME)-$(APPVER).bin.hex diff --git a/script/cibuild b/script/cibuild index 098deb8c0f..3b13af97fb 100755 --- a/script/cibuild +++ b/script/cibuild @@ -20,4 +20,4 @@ fi make -C vendor/nanopb/generator/proto make -C firmware/protob -make -C firmware +make -C firmware sign From 217d5dd01d4b85003ac163fdeae969e07431a237 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 11 Jun 2018 19:13:34 +0200 Subject: [PATCH 0875/1154] firmware: refactor Stellar code; update trezor-common --- firmware/fsm.h | 1 + firmware/fsm_msg_stellar.h | 65 ++++++++++++++++++++++-- firmware/layout2.c | 2 +- firmware/layout2.h | 2 + firmware/protob/messages.options | 7 +++ firmware/stellar.c | 84 +++++--------------------------- firmware/stellar.h | 2 - vendor/trezor-common | 2 +- 8 files changed, 87 insertions(+), 78 deletions(-) diff --git a/firmware/fsm.h b/firmware/fsm.h index b8af6d1549..dc80280a61 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -81,6 +81,7 @@ void fsm_msgCosiCommit(CosiCommit *msg); void fsm_msgCosiSign(CosiSign *msg); // Stellar +void fsm_msgStellarGetAddress(StellarGetAddress *msg); void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg); void fsm_msgStellarSignTx(StellarSignTx *msg); void fsm_msgStellarPaymentOp(StellarPaymentOp *msg); diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index d621323a52..38b176586c 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -1,3 +1,41 @@ +void fsm_msgStellarGetAddress(StellarGetAddress *msg) +{ + RESP_INIT(StellarAddress); + + CHECK_INITIALIZED + + CHECK_PIN + + HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + return; + } + + if (msg->has_show_display && msg->show_display) { + const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2], + NULL, + NULL, NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + resp->has_address = true; + stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); + + msg_write(MessageType_MessageType_StellarAddress, resp); + + layoutHome(); +} + void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) { RESP_INIT(StellarPublicKey); @@ -6,13 +44,34 @@ void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) CHECK_PIN - // Will exit if the user does not confirm - stellar_layoutGetPublicKey(msg->address_n, msg->address_n_count); + HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + return; + } + + if (msg->has_show_display && msg->show_display) { + char hex[32 * 2 + 1]; + data2hex(node->public_key + 1, 32, hex); + const char **str_pubkey_rows = split_message((const uint8_t *)hex, 32 * 2, 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), + str_pubkey_rows[0], + str_pubkey_rows[1], + str_pubkey_rows[2], + str_pubkey_rows[3], + NULL, NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } // Read public key and write it to the response resp->has_public_key = true; resp->public_key.size = 32; - stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, resp->public_key.bytes, sizeof(resp->public_key.bytes)); + memcpy(resp->public_key.bytes, node->public_key + 1, 32); msg_write(MessageType_MessageType_StellarPublicKey, resp); diff --git a/firmware/layout2.c b/firmware/layout2.c index 6d47a8322d..9e3d42ee14 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -153,7 +153,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou } // split longer string into 4 rows, rowlen chars each -static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) +const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) { static char str[4][32 + 1]; if (rowlen > 32) { diff --git a/firmware/layout2.h b/firmware/layout2.h index 2c523a242e..43f1d76a8a 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -68,4 +68,6 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); +const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); + #endif diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 0c66b476d8..84f440c16c 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -177,6 +177,10 @@ CosiSignature.signature max_size:32 # Stellar +StellarGetAddress.address_n max_count:10 + +StellarAddress.address max_size:57 + StellarGetPublicKey.address_n max_count:10 StellarPublicKey.public_key max_size:32 @@ -242,6 +246,9 @@ LiskGetPublicKey skip_message:true LiskAddress skip_message:true LiskSignedTx skip_message:true LiskPublicKey skip_message:true +LiskSignMessage skip_message:true +LiskMessageSignature skip_message:true +LiskVerifyMessage skip_message:true # used only in debug firmware diff --git a/firmware/stellar.c b/firmware/stellar.c index 8f13218273..195c82eb16 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -45,32 +45,6 @@ static bool stellar_signing = false; static StellarTransaction stellar_activeTx; -static const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) -{ - static char str[4][32 + 1]; - if (rowlen > 32) { - rowlen = 32; - } - memset(str, 0, sizeof(str)); - strlcpy(str[0], (char *)msg, rowlen + 1); - if (len > rowlen) { - strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); - } - if (len > rowlen * 2) { - strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); - } - if (len > rowlen * 3) { - strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); - } - if (len > rowlen * 4) { - str[3][rowlen - 1] = '.'; - str[3][rowlen - 2] = '.'; - str[3][rowlen - 3] = '.'; - } - static const char *ret[4] = { str[0], str[1], str[2], str[3] }; - return ret; -} - /* * Starts the signing process and parses the transaction header */ @@ -100,16 +74,19 @@ void stellar_signingInit(StellarSignTx *msg) stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); // Public key comes from deriving the specified account path - uint8_t bytes_pubkey[32]; - stellar_getPubkeyAtAddress(msg->address_n, msg->address_n_count, bytes_pubkey, sizeof(bytes_pubkey)); - memcpy(&(stellar_activeTx.signing_pubkey), bytes_pubkey, sizeof(stellar_activeTx.signing_pubkey)); + HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + // TODO: bail on error + return; + } + memcpy(&(stellar_activeTx.signing_pubkey), node->public_key + 1, sizeof(stellar_activeTx.signing_pubkey)); stellar_activeTx.address_n_count = msg->address_n_count; // todo: fix sizeof check memcpy(&(stellar_activeTx.address_n), &(msg->address_n), sizeof(stellar_activeTx.address_n)); // Hash: public key - stellar_hashupdate_address(bytes_pubkey); + stellar_hashupdate_address(node->public_key + 1); // Hash: fee stellar_hashupdate_uint32(msg->fee); @@ -1319,23 +1296,6 @@ uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) return crc & 0xffff; } -/* - * Writes 32-byte public key to out - */ -void stellar_getPubkeyAtAddress(uint32_t *address_n, size_t address_n_count, uint8_t *out, size_t outlen) -{ - if (outlen < 32) return; - - HDNode *node = stellar_deriveNode(address_n, address_n_count); - - if (node == 0) { - stellar_signingAbort(); - return; - } - - memcpy(out, node->public_key + 1, outlen); -} - /* * Derives the HDNode at the given index * Standard Stellar prefix is m/44'/148'/ and the default account is m/44'/148'/0' @@ -1637,8 +1597,11 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha int offset_y = 1; int line_height = 9; - uint8_t public_key[32]; - stellar_getPubkeyAtAddress(address_n, address_n_count, public_key, sizeof(public_key)); + HDNode *node = stellar_deriveNode(address_n, address_n_count); + if (!node) { + // TODO: bail on error + return; + } char str_pubaddr_truncated[12]; // G???? + null memset(str_pubaddr_truncated, 0, sizeof(str_pubaddr_truncated)); @@ -1650,7 +1613,7 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha // Load up public address char str_pubaddr[56+1]; memset(str_pubaddr, 0, sizeof(str_pubaddr)); - stellar_publicAddressAsStr(public_key, str_pubaddr, sizeof(str_pubaddr)); + stellar_publicAddressAsStr(node->public_key + 1, str_pubaddr, sizeof(str_pubaddr)); memcpy(str_pubaddr_truncated, str_pubaddr, sizeof(str_pubaddr_truncated) - 1); // Header @@ -1742,25 +1705,4 @@ void stellar_layoutTransactionDialog(const char *line1, const char *line2, const str_warning, false ); -} - -void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count) -{ - // Derive node and calculate address - uint8_t pubkey_bytes[32]; - stellar_getPubkeyAtAddress(address_n, address_n_count, pubkey_bytes, sizeof(pubkey_bytes)); - const char **str_addr_rows = stellar_lineBreakAddress(pubkey_bytes); - - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2], - NULL, - NULL, NULL - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } } \ No newline at end of file diff --git a/firmware/stellar.h b/firmware/stellar.h index 57c1697b22..81b287a35f 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -58,7 +58,6 @@ void stellar_confirmManageDataOp(StellarManageDataOp *msg); void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); // Layout -void stellar_layoutGetPublicKey(uint32_t *address_n, size_t address_n_count); void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); void stellar_layoutTransactionSummary(StellarSignTx *msg); void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); @@ -68,7 +67,6 @@ HDNode *stellar_deriveNode(uint32_t *address_n, size_t address_n_count); size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen); const char **stellar_lineBreakAddress(uint8_t *addrbytes); -void stellar_getPubkeyAtAddress(uint32_t *address_n, size_t address_n_count, uint8_t *out, size_t outlen); void stellar_hashupdate_uint32(uint32_t value); void stellar_hashupdate_uint64(uint64_t value); diff --git a/vendor/trezor-common b/vendor/trezor-common index 018eebac7e..0bf60dbda9 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 018eebac7e64ed082486d746d78d279fe815c65d +Subproject commit 0bf60dbda9bd85db01ed36e5d9045a223744a35c From 32a7db423c14274a4d8058d0338842b3dcb4263a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 12 Jun 2018 15:42:18 +0200 Subject: [PATCH 0876/1154] signing: rename hashers to separate their use and reduce confusion --- firmware/signing.c | 79 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index af81ce99b8..9618a647cd 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -54,7 +54,7 @@ static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; -static Hasher hashers[3]; +static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check, hasher_preimage; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; @@ -363,11 +363,11 @@ void phase1_request_next_input(void) send_req_1_input(); } else { // compute segwit hashPrevouts & hashSequence - hasher_Final(&hashers[0], hash_prevouts); - hasher_Final(&hashers[1], hash_sequence); - hasher_Final(&hashers[2], hash_check); + hasher_Final(&hasher_prevouts, hash_prevouts); + hasher_Final(&hasher_sequence, hash_sequence); + hasher_Final(&hasher_check, hash_check); // init hashOutputs - hasher_Reset(&hashers[0]); + hasher_Reset(&hasher_outputs); idx1 = 0; send_req_3_output(); } @@ -519,10 +519,11 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) ti.is_decred = true; } - // segwit hashes for hashPrevouts and hashSequence - hasher_Init(&hashers[0], coin->curve->hasher_sign); - hasher_Init(&hashers[1], coin->curve->hasher_sign); - hasher_Init(&hashers[2], coin->curve->hasher_sign); + hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); + hasher_Init(&hasher_sequence, coin->curve->hasher_sign); + hasher_Init(&hasher_outputs, coin->curve->hasher_sign); + hasher_Init(&hasher_check, coin->curve->hasher_sign); + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); layoutProgressSwipe(_("Signing transaction"), 0); @@ -556,8 +557,8 @@ static bool signing_check_input(TxInputType *txinput) { // change addresses must use the same bip32 path as all inputs extract_input_bip32_path(txinput); // compute segwit hashPrevouts & hashSequence - tx_prevout_hash(&hashers[0], txinput); - tx_sequence_hash(&hashers[1], txinput); + tx_prevout_hash(&hasher_prevouts, txinput); + tx_sequence_hash(&hasher_sequence, txinput); if (coin->decred) { if (txinput->decred_script_version > 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); @@ -574,8 +575,8 @@ static bool signing_check_input(TxInputType *txinput) { tx_serialize_input_hash(&ti, txinput); } // hash prevout and script type to check it later (relevant for fee computation) - tx_prevout_hash(&hashers[2], txinput); - hasher_Update(&hashers[2], (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); + tx_prevout_hash(&hasher_check, txinput); + hasher_Update(&hasher_check, (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -669,7 +670,7 @@ static bool signing_check_output(TxOutputType *txoutput) { tx_serialize_output_hash(&ti, &bin_output); } // compute segwit hashOuts - tx_output_hash(&hashers[0], &bin_output, coin->decred); + tx_output_hash(&hasher_outputs, &bin_output, coin->decred); return true; } @@ -718,7 +719,7 @@ static void phase1_request_next_output(void) { // compute Decred hashPrefix tx_hash_final(&ti, hash_prefix, false); } - hasher_Final(&hashers[0], hash_outputs); + hasher_Final(&hasher_outputs, hash_outputs); if (!signing_check_fee()) { return; } @@ -737,27 +738,27 @@ static void phase1_request_next_output(void) { static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - hasher_Reset(&hashers[0]); - hasher_Update(&hashers[0], (const uint8_t *)&version, 4); - hasher_Update(&hashers[0], hash_prevouts, 32); - hasher_Update(&hashers[0], hash_sequence, 32); - tx_prevout_hash(&hashers[0], txinput); - tx_script_hash(&hashers[0], txinput->script_sig.size, txinput->script_sig.bytes); - hasher_Update(&hashers[0], (const uint8_t*) &txinput->amount, 8); - tx_sequence_hash(&hashers[0], txinput); - hasher_Update(&hashers[0], hash_outputs, 32); - hasher_Update(&hashers[0], (const uint8_t*) &lock_time, 4); - hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); - hasher_Final(&hashers[0], hash); + hasher_Reset(&hasher_preimage); + hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); + hasher_Update(&hasher_preimage, hash_prevouts, 32); + hasher_Update(&hasher_preimage, hash_sequence, 32); + tx_prevout_hash(&hasher_preimage, txinput); + tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); + hasher_Update(&hasher_preimage, (const uint8_t*) &txinput->amount, 8); + tx_sequence_hash(&hasher_preimage, txinput); + hasher_Update(&hasher_preimage, hash_outputs, 32); + hasher_Update(&hasher_preimage, (const uint8_t*) &lock_time, 4); + hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); + hasher_Final(&hasher_preimage, hash); } static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - hasher_Reset(&hashers[0]); - hasher_Update(&hashers[0], (const uint8_t*) &hash_type, 4); - hasher_Update(&hashers[0], hash_prefix, 32); - hasher_Update(&hashers[0], hash_witness, 32); - hasher_Final(&hashers[0], hash); + hasher_Reset(&hasher_preimage); + hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); + hasher_Update(&hasher_preimage, hash_prefix, 32); + hasher_Update(&hasher_preimage, hash_witness, 32); + hasher_Final(&hasher_preimage, hash); } static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { @@ -797,7 +798,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, static bool signing_sign_input(void) { uint8_t hash[32]; - hasher_Final(&hashers[0], hash); + hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_outputs, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); @@ -1094,11 +1095,11 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); - hasher_Reset(&hashers[0]); + hasher_Reset(&hasher_check); } // check prevouts and script type - tx_prevout_hash(&hashers[0], tx->inputs); - hasher_Update(&hashers[0], (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + tx_prevout_hash(&hasher_check, tx->inputs); + hasher_Update(&hasher_check, (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); @@ -1126,13 +1127,13 @@ void signing_txack(TransactionType *tx) send_req_4_input(); } else { uint8_t hash[32]; - hasher_Final(&hashers[0], hash); + hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_check, 32) != 0) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } - hasher_Reset(&hashers[0]); + hasher_Reset(&hasher_check); idx2 = 0; send_req_4_output(); } @@ -1145,7 +1146,7 @@ void signing_txack(TransactionType *tx) return; } // check hashOutputs - tx_output_hash(&hashers[0], &bin_output, coin->decred); + tx_output_hash(&hasher_check, &bin_output, coin->decred); if (!tx_serialize_output_hash(&ti, &bin_output)) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); From b73e18e5732e3493edbd0860577f39053c86826a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 12 Jun 2018 15:03:17 +0200 Subject: [PATCH 0877/1154] firmware: implement zip143 overwinter --- firmware/Makefile | 3 ++ firmware/signing.c | 88 ++++++++++++++++++++++++++++++------------ firmware/transaction.c | 45 ++++++++++++++++----- firmware/transaction.h | 5 ++- vendor/trezor-crypto | 2 +- 5 files changed, 107 insertions(+), 36 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index a7c36296bd..ba3f7516db 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -65,6 +65,8 @@ OBJS += ../vendor/trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha3.o OBJS += ../vendor/trezor-crypto/blake256.o +OBJS += ../vendor/trezor-crypto/blake2b.o +OBJS += ../vendor/trezor-crypto/groestl.o OBJS += ../vendor/trezor-crypto/hasher.o OBJS += ../vendor/trezor-crypto/aes/aescrypt.o @@ -103,6 +105,7 @@ CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_NEM=1 +CFLAGS += -DUSE_MONERO=0 define GENERATE_CODE # $(1) - Basename for script and output header file diff --git a/firmware/signing.c b/firmware/signing.c index 9618a647cd..83503a9186 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -64,6 +64,7 @@ static uint64_t to_spend, authorized_amount, spending, change_spend; static uint32_t version = 1; static uint32_t lock_time = 0; static uint32_t expiry = 0; +static bool overwintered = false; static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; @@ -479,6 +480,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) version = msg->version; lock_time = msg->lock_time; expiry = msg->expiry; + overwintered = msg->has_overwintered && msg->overwintered; uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); if (coin->decred) { @@ -508,22 +510,31 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; } - hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); - hasher_Init(&hasher_sequence, coin->curve->hasher_sign); - hasher_Init(&hasher_outputs, coin->curve->hasher_sign); - hasher_Init(&hasher_check, coin->curve->hasher_sign); - hasher_Init(&hasher_preimage, coin->curve->hasher_sign); + // segwit hashes for hashPrevouts and hashSequence + if (overwintered) { + hasher_Init(&hasher_prevouts, HASHER_OVERWINTER_PREVOUTS); + hasher_Init(&hasher_sequence, HASHER_OVERWINTER_SEQUENCE); + hasher_Init(&hasher_outputs, HASHER_OVERWINTER_OUTPUTS); + hasher_Init(&hasher_preimage, HASHER_OVERWINTER_PREIMAGE); + hasher_Init(&hasher_check, coin->curve->hasher_sign); + } else { + hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); + hasher_Init(&hasher_sequence, coin->curve->hasher_sign); + hasher_Init(&hasher_outputs, coin->curve->hasher_sign); + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); + hasher_Init(&hasher_check, coin->curve->hasher_sign); + } layoutProgressSwipe(_("Signing transaction"), 0); @@ -739,16 +750,39 @@ static void phase1_request_next_output(void) { static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); hasher_Reset(&hasher_preimage); - hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); - hasher_Update(&hasher_preimage, hash_prevouts, 32); - hasher_Update(&hasher_preimage, hash_sequence, 32); - tx_prevout_hash(&hasher_preimage, txinput); - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); - hasher_Update(&hasher_preimage, (const uint8_t*) &txinput->amount, 8); - tx_sequence_hash(&hasher_preimage, txinput); - hasher_Update(&hasher_preimage, hash_outputs, 32); - hasher_Update(&hasher_preimage, (const uint8_t*) &lock_time, 4); - hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion + hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence + tx_prevout_hash(&hasher_preimage, txinput); // outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // scriptCode + hasher_Update(&hasher_preimage, (const uint8_t*) &txinput->amount, 8); // amount + tx_sequence_hash(&hasher_preimage, txinput); // nSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs + hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // nLockTime + hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // nHashType + hasher_Final(&hasher_preimage, hash); +} + +static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { + uint32_t hash_type = signing_hash_type(); + hasher_Reset(&hasher_preimage); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&coin->version_group_id, 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 7. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 8. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 9. nHashType + + tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 10b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 10c. value + tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence + hasher_Final(&hasher_preimage, hash); } @@ -933,9 +967,9 @@ void signing_txack(TransactionType *tx) } #endif - if (coin->force_bip143) { + if (coin->force_bip143 || overwintered) { if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("BIP 143 input without amount")); + fsm_sendFailure(FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); signing_abort(); return; } @@ -1011,7 +1045,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; @@ -1094,7 +1128,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); hasher_Reset(&hasher_check); } // check prevouts and script type @@ -1181,7 +1215,7 @@ void signing_txack(TransactionType *tx) resp.serialized.has_serialized_tx = true; if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - if (!coin->force_bip143) { + if (!(coin->force_bip143 || overwintered)) { fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; @@ -1199,7 +1233,11 @@ void signing_txack(TransactionType *tx) authorized_amount -= tx->inputs[0].amount; uint8_t hash[32]; - signing_hash_bip143(&tx->inputs[0], hash); + if (overwintered) { + signing_hash_zip143(&tx->inputs[0], hash); + } else { + signing_hash_bip143(&tx->inputs[0], hash); + } if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash)) return; // since this took a longer time, update progress @@ -1289,12 +1327,12 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx1 == 0) { // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); to.is_decred = true; } // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { diff --git a/firmware/transaction.c b/firmware/transaction.c index 106dba5a06..7d12749b34 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -465,10 +465,18 @@ uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { int r = 4; - memcpy(out, &(tx->version), 4); - if (tx->is_segwit) { - memcpy(out + r, segwit_header, 2); - r += 2; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + memcpy(out, &ver, 4); + uint32_t version_group_id = 0x03c48270; + memcpy(out + 4, &version_group_id, 4); + r += 4; + } else { + memcpy(out, &(tx->version), 4); + if (tx->is_segwit) { + memcpy(out + r, segwit_header, 2); + r += 2; + } } return r + ser_length(tx->inputs_len, out + r); } @@ -476,10 +484,18 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_header_hash(TxStruct *tx) { int r = 4; - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); - if (tx->is_segwit) { - hasher_Update(&(tx->hasher), segwit_header, 2); - r += 2; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); + uint32_t version_group_id = 0x03c48270; + hasher_Update(&(tx->hasher), (const uint8_t *)&version_group_id, 4); + r += 4; + } else { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); + if (tx->is_segwit) { + hasher_Update(&(tx->hasher), segwit_header, 2); + r += 2; + } } return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } @@ -598,6 +614,11 @@ uint32_t tx_serialize_middle_hash(TxStruct *tx) uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); + if (tx->overwintered) { + memcpy(out + 4, &(tx->expiry), 4); + out[8] = 0x00; // nJoinSplit + return 9; + } if (tx->is_decred) { memcpy(out + 4, &(tx->expiry), 4); return 8; @@ -608,6 +629,11 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_footer_hash(TxStruct *tx) { hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); + if (tx->overwintered) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit + return 9; + } if (tx->is_decred) { hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); return 8; @@ -688,7 +714,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; @@ -702,6 +728,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->size = 0; tx->is_segwit = false; tx->is_decred = false; + tx->overwintered = overwintered; hasher_Init(&(tx->hasher), hasher_sign); } diff --git a/firmware/transaction.h b/firmware/transaction.h index c269c4518d..22c2522994 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -28,6 +28,8 @@ #include "hasher.h" #include "types.pb.h" +#define TX_OVERWINTERED 0x80000000 + typedef struct { uint32_t inputs_len; uint32_t outputs_len; @@ -41,6 +43,7 @@ typedef struct { uint32_t have_inputs; uint32_t have_outputs; + bool overwintered; uint32_t extra_data_len; uint32_t extra_data_received; @@ -68,7 +71,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index e81fb38ab4..dba2361728 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit e81fb38ab452f2170769e9c454b10caaf8869974 +Subproject commit dba23617280ea75b434bbca4699abfd1524fdbe2 From f2ad9b921ecc961ebd6805526f092bdf4e165653 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Jun 2018 10:38:49 +0200 Subject: [PATCH 0878/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index dba2361728..669acd7331 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit dba23617280ea75b434bbca4699abfd1524fdbe2 +Subproject commit 669acd7331fc02b6ef41c4a91112e6e6d6e831be From a46de7b5916b74cc31a0aed1396ca47e4e4fed50 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jun 2018 16:00:31 +0200 Subject: [PATCH 0879/1154] build: optimize for speed just the essential critical crypto stuff --- firmware/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index ba3f7516db..9cd23f6ef0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -87,10 +87,11 @@ OBJS += protob/types.pb.o OPTFLAGS ?= -Os -../vendor/trezor-crypto/%.o: OPTFLAGS = -O3 -../vendor/trezor-crypto/aes/%.o: OPTFLAGS = -O3 -../vendor/trezor-crypto/ed25519-donna/%.o: OPTFLAGS = -O3 -../vendor/nanopb/%.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/bip32.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/bip39.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/ecdsa.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/sha2.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/secp256k1.o: OPTFLAGS = -O3 include ../Makefile.include From a49e0a9d167a88e9242b2941e6b9ec85545dc223 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Jun 2018 16:49:49 +0200 Subject: [PATCH 0880/1154] firmware: next version will be 1.6.2 --- firmware/trezor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index 20fcfc481e..f1ae52d06f 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,8 +23,8 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 7 -#define VERSION_PATCH 0 +#define VERSION_MINOR 6 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) From 16ad5ce85401de53864b61afca88e1efebb7219a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Jun 2018 00:02:41 +0200 Subject: [PATCH 0881/1154] firmware: disable Stellar for now --- firmware/Makefile | 2 +- firmware/fsm.c | 2 +- firmware/protob/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 9cd23f6ef0..cb61ea05c3 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,7 @@ OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o -OBJS += stellar.o +# OBJS += stellar.o OBJS += debug.o diff --git a/firmware/fsm.c b/firmware/fsm.c index 5997db6a33..aca5fe0a40 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -247,5 +247,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore #include "fsm_msg_ethereum.h" #include "fsm_msg_crypto.h" #include "fsm_msg_nem.h" -#include "fsm_msg_stellar.h" +// #include "fsm_msg_stellar.h" #include "fsm_msg_debug.h" diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 09643feb54..a741bc4c57 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -12,7 +12,7 @@ PYTHON ?= python protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py types_pb2.py - $(PYTHON) $< | grep -v MessageType_Lisk > $@ + $(PYTHON) $< | grep -v -e MessageType_Lisk -e MessageType_Stellar > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From 2ec6129da5eb1eaa2adae9cc1e283140d1ee19f5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Jun 2018 16:31:47 +0200 Subject: [PATCH 0882/1154] vendor: update trezor-common Prepare for Stellar rewrite (accounts are addresses, not pubkeys) This commit breaks the existing Stellar code, but it is disabled and we need to refactor that anyway :-/ --- firmware/protob/messages.options | 36 ++++++++++++++++---------------- vendor/trezor-common | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index 84f440c16c..c93f182496 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -187,43 +187,43 @@ StellarPublicKey.public_key max_size:32 StellarSignTx.address_n max_count:10 StellarSignTx.network_passphrase max_size:1024 -StellarSignTx.source_account max_size:32 +StellarSignTx.source_account max_size:57 StellarSignTx.memo_text max_size:29 StellarSignTx.memo_hash max_size:32 -StellarPaymentOp.source_account max_size:32 -StellarPaymentOp.destination_account max_size:32 +StellarPaymentOp.source_account max_size:57 +StellarPaymentOp.destination_account max_size:57 -StellarCreateAccountOp.source_account max_size:32 -StellarCreateAccountOp.new_account max_size:32 +StellarCreateAccountOp.source_account max_size:57 +StellarCreateAccountOp.new_account max_size:57 -StellarPathPaymentOp.source_account max_size:32 -StellarPathPaymentOp.destination_account max_size:32 +StellarPathPaymentOp.source_account max_size:57 +StellarPathPaymentOp.destination_account max_size:57 StellarPathPaymentOp.paths max_count:5 -StellarManageOfferOp.source_account max_size:32 +StellarManageOfferOp.source_account max_size:57 -StellarCreatePassiveOfferOp.source_account max_size:32 +StellarCreatePassiveOfferOp.source_account max_size:57 -StellarSetOptionsOp.source_account max_size:32 -StellarSetOptionsOp.inflation_destination_account max_size:32 +StellarSetOptionsOp.source_account max_size:57 +StellarSetOptionsOp.inflation_destination_account max_size:57 StellarSetOptionsOp.home_domain max_size:33 StellarSetOptionsOp.signer_key max_size:32 -StellarChangeTrustOp.source_account max_size:32 +StellarChangeTrustOp.source_account max_size:57 -StellarAllowTrustOp.source_account max_size:32 -StellarAllowTrustOp.trusted_account max_size:32 +StellarAllowTrustOp.source_account max_size:57 +StellarAllowTrustOp.trusted_account max_size:57 StellarAllowTrustOp.asset_code max_size:13 -StellarAccountMergeOp.source_account max_size:32 -StellarAccountMergeOp.destination_account max_size:32 +StellarAccountMergeOp.source_account max_size:57 +StellarAccountMergeOp.destination_account max_size:57 -StellarManageDataOp.source_account max_size:32 +StellarManageDataOp.source_account max_size:57 StellarManageDataOp.key max_size:65 StellarManageDataOp.value max_size:65 -StellarBumpSequenceOp.source_account max_size:32 +StellarBumpSequenceOp.source_account max_size:57 StellarSignedTx.public_key max_size:32 StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint diff --git a/vendor/trezor-common b/vendor/trezor-common index 0bf60dbda9..e5df1abfbe 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0bf60dbda9bd85db01ed36e5d9045a223744a35c +Subproject commit e5df1abfbe752da9232893715c496b3a1a9bde7a From c67c2d41bb64fa90c5d9a71de8750161aa04deb0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 13:18:10 +0200 Subject: [PATCH 0883/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index e5df1abfbe..d71239faff 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit e5df1abfbe752da9232893715c496b3a1a9bde7a +Subproject commit d71239faff0c70c9f904fe3832acbb7c8d270105 From 027e64d21a2db89106c86fa114d882a1101d286e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 13:18:10 +0200 Subject: [PATCH 0884/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index d71239faff..e74d966cf6 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit d71239faff0c70c9f904fe3832acbb7c8d270105 +Subproject commit e74d966cf6794553fb91f4f6980ce4f8466de504 From 0ddf443346f022702a033ad42c0d488ab2aca5d1 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 21 Jun 2018 14:28:39 +0200 Subject: [PATCH 0885/1154] Check if firmware has privileges. (#369) Only drop privileges if firmware is running with privileges. Don't change the bootloader if running without privileges. --- firmware/bl_check.c | 6 ++++++ firmware/trezor.c | 9 ++++++--- util.h | 7 +++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 598bac276c..c93624a4a4 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -53,6 +53,10 @@ void check_bootloader(void) shutdown(); } + if (is_mode_unprivileged()) { + return; + } + if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { // all OK -> done return; @@ -62,6 +66,8 @@ void check_bootloader(void) // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK // YOUR DEVICE. + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Overwriting bootloader", NULL, NULL, "DON'T UNPLUG", "YOUR TREZOR", NULL); + // unlock sectors memory_write_unlock(); diff --git a/firmware/trezor.c b/firmware/trezor.c index 9737733fed..4d256eaece 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -96,12 +96,15 @@ int main(void) __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif - timer_init(); + if (!is_mode_unprivileged()) { + + timer_init(); #ifdef APPVER - // enable MPU (Memory Protection Unit) - mpu_config(); + // enable MPU (Memory Protection Unit) + mpu_config(); #endif + } #if DEBUG_LINK oledSetDebugLink(1); diff --git a/util.h b/util.h index 4e807d1fab..c131dbead2 100644 --- a/util.h +++ b/util.h @@ -79,6 +79,13 @@ static inline void set_mode_unprivileged(void) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html __asm__ volatile("msr control, %0" :: "r" (0x1)); } + +static inline bool is_mode_unprivileged(void) +{ + uint32_t r0; + __asm__ volatile("mrs %0, control" : "=r" (r0)); + return r0 & 1; +} #endif #endif From da9f8bec6f21a79964cf9173ff0743e2443c9221 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Thu, 21 Jun 2018 14:52:17 +0200 Subject: [PATCH 0886/1154] Fixed compilation of emulator (#370) --- util.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/util.h b/util.h index c131dbead2..03faf2dc8d 100644 --- a/util.h +++ b/util.h @@ -21,6 +21,7 @@ #define __UTIL_H_ #include +#include #include #if !EMULATOR @@ -86,6 +87,13 @@ static inline bool is_mode_unprivileged(void) __asm__ volatile("mrs %0, control" : "=r" (r0)); return r0 & 1; } + +#else /* EMULATOR */ + +static inline bool is_mode_unprivileged(void) +{ + return true; +} #endif #endif From 01933e68fb0e897a735e9000702d4769154f59f2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 14:39:23 +0200 Subject: [PATCH 0887/1154] firmware: try updating bootloader 10 times before bailing --- firmware/bl_check.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index c93624a4a4..35b1fd1ad7 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -49,7 +49,7 @@ void check_bootloader(void) int r = memory_bootloader_hash(hash); if (!known_bootloader(r, hash)) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unknown bootloader", "detected.", NULL, "Unplug your TREZOR", "contact our support.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Unknown bootloader"), _("detected."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); shutdown(); } @@ -66,24 +66,33 @@ void check_bootloader(void) // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK // YOUR DEVICE. - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Overwriting bootloader", NULL, NULL, "DON'T UNPLUG", "YOUR TREZOR", NULL); + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, _("Updating bootloader"), NULL, NULL, _("DO NOT UNPLUG"), _("YOUR TREZOR!"), NULL); // unlock sectors memory_write_unlock(); - // replace bootloader - flash_unlock(); - for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + for (int tries = 0; tries < 10; tries++) { + // replace bootloader + flash_unlock(); + for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + for (int i = 0; i < FLASH_BOOT_LEN / 4; i++) { + const uint32_t *w = (const uint32_t *)(bl_data + i * 4); + flash_program_word(FLASH_BOOT_START + i * 4, *w); + } + flash_lock(); + // check whether the write was OK + r = memory_bootloader_hash(hash); + if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { + // OK -> show info and halt + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); + shutdown(); + return; + } } - for (int i = 0; i < FLASH_BOOT_LEN / 4; i++) { - const uint32_t *w = (const uint32_t *)(bl_data + i * 4); - flash_program_word(FLASH_BOOT_START + i * 4, *w); - } - flash_lock(); - // show info and halt - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Bootloader update"), _("broken."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); shutdown(); #endif } From 156fab867b7ff48255ac6fbc39aa0dc7b3d755f8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 15:22:56 +0200 Subject: [PATCH 0888/1154] firmware: support also testnet coins in stable firmware --- firmware/coin_info.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/firmware/coin_info.py b/firmware/coin_info.py index c62fa884b5..d5c7d1b1c5 100755 --- a/firmware/coin_info.py +++ b/firmware/coin_info.py @@ -12,11 +12,7 @@ HEADER_TEMPLATE = """ #include "coins.h" -#if DEBUG_LINK -#define COINS_COUNT ({stable} + {debug}) -#else -#define COINS_COUNT ({stable}) -#endif +#define COINS_COUNT ({count}) extern const CoinInfo coins[COINS_COUNT]; @@ -32,10 +28,7 @@ CODE_TEMPLATE = """ #include "secp256k1.h" const CoinInfo coins[COINS_COUNT] = {{ -{stable} -#if DEBUG_LINK -{debug} -#endif +{coins} }}; """.lstrip() @@ -117,25 +110,20 @@ def format_coins(coins): if __name__ == "__main__": os.chdir(os.path.abspath(os.path.dirname(__file__))) - coins = collections.defaultdict(list) + coins = [] support = json.load(open('defs/support.json', 'r'), object_pairs_hook=collections.OrderedDict) defs = support['trezor1'].keys() for c in defs: name = c.replace(' ', '_').lower() - firmware = 'debug' if name.endswith('_testnet') else 'stable' if name == 'testnet': name = 'bitcoin_testnet' data = json.load(open('defs/coins/%s.json' % name, 'r')) - coins[firmware].append(data) + coins.append(data) with open("coin_info.h", "w+") as f: - f.write(HEADER_TEMPLATE.format(**{ - k: format_number(len(v)) for k, v in coins.items() - })) + f.write(HEADER_TEMPLATE.format(count=len(coins))) with open("coin_info.c", "w+") as f: - f.write(CODE_TEMPLATE.format(**{ - k: format_coins(v) for k, v in coins.items() - })) + f.write(CODE_TEMPLATE.format(coins=format_coins(coins))) From a1379371a0a31884bae5b69e56c90773e18a98dd Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 15:52:23 +0200 Subject: [PATCH 0889/1154] ethereum: add new networks --- firmware/ethereum.c | 56 +++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 17cc9dbf7e..f06215c03f 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -241,23 +241,29 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, suffix = " Wei"; decimals = 0; } else { - if (tx_type == 1 || tx_type == 6) { - suffix = " WAN"; - } else { - switch (chain_id) { - case 1: suffix = " ETH"; break; // Ethereum Mainnet - case 61: suffix = " ETC"; break; // Ethereum Classic Mainnet - case 62: suffix = " tETC"; break; // Ethereum Classic Testnet - case 30: suffix = " RSK"; break; // Rootstock Mainnet - case 31: suffix = " tRSK"; break; // Rootstock Testnet - case 3: suffix = " tETH"; break; // Ethereum Testnet: Ropsten - case 4: suffix = " tETH"; break; // Ethereum Testnet: Rinkeby - case 42: suffix = " tETH"; break; // Ethereum Testnet: Kovan - case 2: suffix = " EXP"; break; // Expanse - case 8: suffix = " UBQ"; break; // UBIQ - default: suffix = " UNKN"; break; // unknown chain - } - } + if (tx_type == 1 || tx_type == 6) { + suffix = " WAN"; + } else { + // constants from trezor-common/defs/ethereum/networks.json + switch (chain_id) { + case 1: suffix = " ETH"; break; // Ethereum + case 2: suffix = " EXP"; break; // Expanse + case 3: suffix = " tETH"; break; // Ethereum Testnet Ropsten + case 4: suffix = " tETH"; break; // Ethereum Testnet Rinkeby + case 8: suffix = " UBQ"; break; // UBIQ + case 20: suffix = " EOSC"; break; // EOS Classic + case 28: suffix = " ETSC"; break; // Ethereum Social + case 30: suffix = " RSK"; break; // RSK + case 31: suffix = " tRSK"; break; // RSK Testnet + case 42: suffix = " tETH"; break; // Ethereum Testnet Kovan + case 61: suffix = " ETC"; break; // Ethereum Classic + case 62: suffix = " tETC"; break; // Ethereum Classic Testnet + case 64: suffix = " ELLA"; break; // Ellaism + case 820: suffix = " CLO"; break; // Callisto + case 1987: suffix = " EGEM"; break; // EtherGem + default : suffix = " UNKN"; break; // unknown chain + } + } } bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); } @@ -455,10 +461,10 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) chain_id = 0; } - /* Wanchain txtype */ + /* Wanchain txtype */ if (msg->has_tx_type) { if (msg->tx_type == 1 || msg->tx_type == 6) { - tx_type = msg->tx_type; + tx_type = msg->tx_type; } else { fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); ethereum_signing_abort(); @@ -548,9 +554,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); - if (tx_type) { - rlp_length += rlp_calculate_length(1, tx_type); - } + if (tx_type) { + rlp_length += rlp_calculate_length(1, tx_type); + } if (chain_id) { rlp_length += rlp_calculate_length(1, chain_id); rlp_length += rlp_calculate_length(0, 0); @@ -562,9 +568,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutProgress(_("Signing"), 100); - if (tx_type) { - hash_rlp_number(tx_type); - } + if (tx_type) { + hash_rlp_number(tx_type); + } hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); From 9abb30f7cd535ce421b46376a11f952990792219 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 16:28:25 +0200 Subject: [PATCH 0890/1154] ethereum: update token list --- firmware/ethereum_tokens.c | 841 +++++++++++++++++++++++++++++++------ firmware/ethereum_tokens.h | 2 +- 2 files changed, 717 insertions(+), 126 deletions(-) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index d1e605264b..b7d89ec207 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -2,131 +2,722 @@ #include "ethereum_tokens.h" const TokenType tokens[TOKENS_COUNT] = { - { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, - { 1, "\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", " 300", 18}, - { 1, "\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", " ADST", 0}, - { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, - { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, - { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, - { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, - { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, - { 1, "\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10", " ATH", 18}, - { 1, "\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f", " AVA", 4}, - { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, - { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, - { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BEER", 0}, - { 1, "\x72\x58\x03\x31\x55\x19\xde\x78\xd2\x32\x26\x5a\x8f\x10\x40\xf0\x54\xe7\x0b\x98", " BET", 18}, - { 1, "\x6d\xc7\x0d\x22\xee\x85\x40\x79\x6a\xb5\xb0\x2f\x98\xf9\xf2\x4d\xc8\x79\xe1\x0a", " BLX", 18}, - { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, - { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, - { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, - { 1, "\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", " CAT", 18}, - { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, - { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, - { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, - { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CCRB", 6}, - { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, - { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, - { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, - { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, - { 1, "\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", " DENT", 8}, - { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, - { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, - { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, - { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, - { 1, "\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37", " DROP", 0}, - { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, - { 1, "\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", " ECN", 2}, - { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, - { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, - { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, - { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, - { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, - { 1, "\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", " FYN", 18}, - { 1, "\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", " GELD", 18}, - { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, - { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, - { 1, "\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", " GTKT", 0}, - { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, - { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, - { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, - { 1, "\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", " ICE", 18}, - { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, - { 1, "\xed\x19\x69\x8c\x0a\xbd\xe8\x63\x54\x13\xae\x7a\xd7\x22\x4d\xf6\xee\x30\xbf\x22", " IMT", 0}, - { 1, "\xc1\xe6\xc6\xc6\x81\xb2\x86\xfb\x50\x3b\x36\xa9\xdd\x6c\x1d\xbf\xf8\x5e\x73\xcf", " JET", 18}, - { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JTC", 18}, - { 1, "\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", " LOK", 18}, - { 1, "\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53", " LUCK", 0}, - { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, - { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, - { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, - { 1, "\xd0\xb1\x71\xeb\x0b\x0f\x2c\xbd\x35\xcc\xd9\x7c\xdc\x5e\xdc\x3f\xfe\x48\x71\xaa", " MDA", 18}, - { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, - { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, - { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " MKR", 18}, - { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, - { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, - { 1, "\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", " MRV", 18}, - { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, - { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, - { 1, "\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", " MYD", 16}, - { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, - { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, - { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, - { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, - { 1, "\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", " NXX", 8}, - { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, - { 1, "\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", " OHNI", 0}, - { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, - { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, - { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, - { 1, "\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", " PLR", 18}, - { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, - { 1, "\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", " PPT", 8}, - { 1, "\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", " PRO", 8}, - { 1, "\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b", " PRS", 18}, - { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, - { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, - { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, - { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, - { 1, "\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", " REX", 18}, - { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, - { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, - { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, - { 1, "\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", " SAN", 18}, - { 1, "\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8", " SCL", 8}, - { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, - { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, - { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, - { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, - { 1, "\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97", " SKO1", 18}, - { 1, "\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04", " SNC", 18}, - { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, - { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, - { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, - { 1, "\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", " SPARC", 18}, - { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, - { 1, "\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96", " STRC", 8}, - { 1, "\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45", " STX", 18}, - { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, - { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, - { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, - { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, - { 1, "\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", " TIX", 18}, - { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, - { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, - { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " UNCRN", 0}, - { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, - { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, - { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, - { 1, "\x82\x66\x57\x64\xea\x0b\x58\x15\x7e\x1e\x5e\x9b\xab\x32\xf6\x8c\x76\xec\x0c\xdf", " VSM", 0}, - { 1, "\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63", " WCT", 18}, - { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, - { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, - { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, - { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, - { 1, "\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", " ZRX", 18}, - {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, + {64, "\x99\x1e\x7f\xe4\xb0\x5f\x2b\x3d\xb1\xd7\x88\xe7\x05\x96\x3f\x5d\x64\x7b\x00\x44", " MINING", 18}, // ella / Ella Mining Tokens + {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, // etc / BEC + {61, "\x5a\xce\x17\xf8\x7c\x73\x91\xe5\x79\x2a\x76\x83\x06\x9a\x80\x25\xb8\x3b\xbd\x85", " PLAY", 0}, // etc / Smart Billions + { 1, "\x4e\x84\xe9\xe5\xfb\x0a\x97\x26\x28\xcf\x45\x68\xc4\x03\x16\x7e\xf1\xd4\x04\x31", " $FFC", 18}, // eth / $Fluzcoin + { 1, "\xa0\x24\xe8\x05\x7e\xec\x47\x4a\x9b\x23\x56\x83\x37\x07\xdd\x05\x79\xe2\x6e\xf3", " $FXY", 18}, // eth / $FIXY NETWORK + { 1, "\x7d\xd7\xf5\x6d\x69\x7c\xc0\xf2\xb5\x2b\xd5\x5c\x05\x7f\x37\x8f\x1f\xe6\xab\x4b", " $TEAK", 18}, // eth / $TEAK + { 1, "\xb6\xed\x76\x44\xc6\x94\x16\xd6\x7b\x52\x2e\x20\xbc\x29\x4a\x9a\x9b\x40\x5b\x31", " 0xBTC", 8}, // eth / 0xBitcoin + { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, // eth / FirstBlood + { 1, "\xfd\xbc\x1a\xdc\x26\xf0\xf8\xf8\x60\x6a\x5d\x63\xb7\xd3\xa3\xcd\x21\xc2\x2b\x23", " 1WO", 8}, // eth / 1WO + { 1, "\x9f\xc0\x58\x32\x20\xeb\x44\xfa\xee\x9e\x2d\xc1\xe6\x3f\x39\x20\x4d\xdd\x90\x90", " 2DC", 18}, // eth / DualChain + { 1, "\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", " 300", 18}, // eth / 300 Token Sparta + { 1, "\xbd\xe8\xf7\x82\x0b\x55\x44\xa4\x9d\x34\xf9\xdd\xea\xca\xbe\xdc\x7c\x0b\x5a\xdc", " A18", 0}, // eth / Apollo18 + { 1, "\xb9\x8d\x4c\x97\x42\x5d\x99\x08\xe6\x6e\x53\xa6\xfd\xf6\x73\xac\xca\x0b\xe9\x86", " ABT", 18}, // eth / ArcBlock Token + { 1, "\x0e\x8d\x6b\x47\x1e\x33\x2f\x14\x0e\x7d\x9d\xbb\x99\xe5\xe3\x82\x2f\x72\x8d\xa6", " ABYSS", 18}, // eth / ABYSS + { 1, "\x13\xf1\xb7\xfd\xfb\xe1\xfc\x66\x67\x6d\x56\x48\x3e\x21\xb1\xec\xb4\x0b\x58\xe2", " ACC", 18}, // eth / Accelerator Network + { 1, "\xe6\x9a\x35\x3b\x31\x52\xdd\x7b\x70\x6f\xf7\xdd\x40\xfe\x1d\x18\xb7\x80\x2d\x31", " ADH", 18}, // eth / AdHive Token + { 1, "\x88\x10\xc6\x34\x70\xd3\x86\x39\x95\x4c\x6b\x41\xaa\xc5\x45\x84\x8c\x46\x48\x4a", " ADI", 18}, // eth / Aditus + { 1, "\x66\x0e\x71\x48\x37\x85\xf6\x61\x33\x54\x8b\x10\xf6\x92\x6d\xc3\x32\xb0\x6e\x61", " ADL", 18}, // eth / Adelphoi + { 1, "\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", " ADST", 0}, // eth / AdShares + { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, // eth / AdToken + { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, // eth / AdEx Network + { 1, "\x5c\xa9\xa7\x1b\x1d\x01\x84\x9c\x0a\x95\x49\x0c\xc0\x05\x59\x71\x7f\xcf\x0d\x1d", " AE", 18}, // eth / aeternity + { 1, "\x8e\xb2\x43\x19\x39\x37\x16\x66\x8d\x76\x8d\xce\xc2\x93\x56\xae\x9c\xff\xe2\x85", " AGI", 8}, // eth / SingularityNET + { 1, "\x4c\xed\xa7\x90\x6a\x5e\xd2\x17\x97\x85\xcd\x3a\x40\xa6\x9e\xe8\xbc\x99\xc4\x66", " AION", 8}, // eth / Aion + { 1, "\x27\xdc\xe1\xec\x4d\x3f\x72\xc3\xe4\x57\xcc\x50\x35\x4f\x1f\x97\x5d\xde\xf4\x88", " AIR", 8}, // eth / AirToken + { 1, "\x10\x63\xce\x52\x42\x65\xd5\xa3\xa6\x24\xf4\x91\x4a\xcd\x57\x3d\xd8\x9c\xe9\x88", " AIX", 18}, // eth / Aigang + { 1, "\x18\x1a\x63\x74\x6d\x3a\xdc\xf3\x56\xcb\xc7\x3a\xce\x22\x83\x2f\xfb\xb1\xee\x5a", " ALCO", 8}, // eth / ALCO + { 1, "\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab", " ALIS", 18}, // eth / ALIS Token + { 1, "\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa", " ALTS", 18}, // eth / ALTS Token + { 1, "\x4d\xc3\x64\x3d\xbc\x64\x2b\x72\xc1\x58\xe7\xf3\xd2\xff\x23\x2d\xf6\x1c\xb6\xce", " AMB", 18}, // eth / Amber Token + { 1, "\x94\x9b\xed\x88\x6c\x73\x9f\x1a\x32\x73\x62\x9b\x33\x20\xdb\x0c\x50\x24\xc7\x19", " AMIS", 9}, // eth / AMIS + { 1, "\x73\x7f\x98\xac\x8c\xa5\x9f\x2c\x68\xad\x65\x8e\x3c\x3d\x8c\x89\x63\xe4\x0a\x4c", " AMN", 18}, // eth / Amon + { 1, "\x38\xc8\x7a\xa8\x9b\x2b\x8c\xd9\xb9\x5b\x73\x6e\x1f\xa7\xb6\x12\xea\x97\x21\x69", " AMO", 18}, // eth / AMO Coin + { 1, "\x84\x93\x6c\xf7\x63\x0a\xa3\xe2\x7d\xd9\xaf\xf9\x68\xb1\x40\xd5\xae\xe4\x9f\x5a", " AMTC", 8}, // eth / AmberTime Coin + { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, // eth / ANT + { 1, "\x4c\x0f\xbe\x1b\xb4\x66\x12\x91\x5e\x79\x67\xd2\xc3\x21\x3c\xd4\xd8\x72\x57\xad", " APIS", 18}, // eth / APIS + { 1, "\x1a\x7a\x8b\xd9\x10\x6f\x2b\x8d\x97\x7e\x08\x58\x2d\xc7\xd2\x4c\x72\x3a\xb0\xdb", " APPC", 18}, // eth / AppCoins + { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, // eth / AIGang + { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, // eth / ARC + { 1, "\x12\x45\xef\x80\xf4\xd9\xe0\x2e\xd9\x42\x53\x75\xe8\xf6\x49\xb9\x22\x1b\x31\xd8", " ARCT", 8}, // eth / ArbitrageCT + { 1, "\x75\xaa\x7b\x0d\x02\x53\x2f\x38\x33\xb6\x6c\x7f\x0a\xd3\x53\x76\xd3\x73\xdd\xf8", " ARD", 18}, // eth / Accord + { 1, "\xba\x5f\x11\xb1\x6b\x15\x57\x92\xcf\x3b\x2e\x68\x80\xe8\x70\x68\x59\xa8\xae\xb6", " ARN", 8}, // eth / Aeron Token + { 1, "\xfe\xc0\xcf\x7f\xe0\x78\xa5\x00\xab\xf1\x5f\x12\x84\x95\x8f\x22\x04\x9c\x2c\x7e", " ART", 18}, // eth / ART + { 1, "\x77\x05\xfa\xa3\x4b\x16\xeb\x6d\x77\xdf\xc7\x81\x2b\xe2\x36\x7b\xa6\xb0\x24\x8e", " ARX", 8}, // eth / ARX + { 1, "\xb0\xd9\x26\xc1\xbc\x3d\x78\x06\x4f\x3e\x10\x75\xd5\xbd\x9a\x24\xf3\x5a\xe6\xc5", " ARXT", 18}, // eth / Assistive Reality ARX + { 1, "\x27\x05\x4b\x13\xb1\xb7\x98\xb3\x45\xb5\x91\xa4\xd2\x2e\x65\x62\xd4\x7e\xa7\x5a", " AST", 4}, // eth / Airswap + { 1, "\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10", " ATH", 18}, // eth / Athenian Warrior Token + { 1, "\x15\x43\xd0\xf8\x34\x89\xe8\x2a\x13\x44\xdf\x68\x27\xb2\x3d\x54\x1f\x23\x5a\x50", " ATH (AIgatha Token)", 18}, // eth / AIgatha Token + { 1, "\x78\xb7\xfa\xda\x55\xa6\x4d\xd8\x95\xd8\xc8\xc3\x57\x79\xdd\x8b\x67\xfa\x8a\x05", " ATL", 18}, // eth / ATL + { 1, "\x97\xae\xb5\x06\x6e\x1a\x59\x0e\x86\x8b\x51\x14\x57\xbe\xb6\xfe\x99\xd3\x29\xf5", " ATMI", 18}, // eth / Atonomi + { 1, "\x88\x78\x34\xd3\xb8\xd4\x50\xb6\xba\xb1\x09\xc2\x52\xdf\x3d\xa2\x86\xd7\x3c\xe4", " ATT", 18}, // eth / Atmatrix Token + { 1, "\x63\x39\x78\x4d\x94\x78\xda\x43\x10\x6a\x42\x91\x96\x77\x2a\x02\x9c\x2f\x17\x7d", " ATTN", 18}, // eth / Attention Token + { 1, "\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f", " AVA", 4}, // eth / AVA + { 1, "\x0d\x88\xed\x6e\x74\xbb\xfd\x96\xb8\x31\x23\x16\x38\xb6\x6c\x05\x57\x1e\x82\x4f", " AVT", 18}, // eth / AVT + { 1, "\xcd\x4b\x4b\x0f\x32\x84\xa3\x3a\xc4\x9c\x67\x96\x1e\xc6\xe1\x11\x70\x83\x18\xcf", " AX1", 5}, // eth / AX1 Mining Token + { 1, "\x9a\xf2\xc6\xb1\xa2\x8d\x3d\x6b\xc0\x84\xbd\x26\x7f\x70\xe9\x0d\x49\x74\x1d\x5b", " AXP", 8}, // eth / AXP + { 1, "\xf8\x7f\x0d\x91\x53\xfe\xa5\x49\xc7\x28\xad\x61\xcb\x80\x15\x95\xa6\x8b\x73\xde", " BANX", 18}, // eth / BANX + { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, // eth / BAT + { 1, "\x4a\x60\x58\x66\x6c\xf1\x05\x7e\xac\x3c\xd3\xa5\xa6\x14\x62\x05\x47\x55\x9f\xc9", " BBK", 18}, // eth / BRICKBLOCK TOKEN + { 1, "\x73\x67\xa6\x80\x39\xd4\x70\x4f\x30\xbf\xbf\x6d\x94\x80\x20\xc3\xb0\x7d\xfc\x59", " BCBC", 18}, // eth / Beercoin + { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, // eth / BCDN + { 1, "\xac\xfa\x20\x9f\xb7\x3b\xf3\xdd\x5b\xbf\xb1\x10\x1b\x9b\xc9\x99\xc4\x90\x62\xa5", " BCDT", 18}, // eth / Blockchain Certified Data Token + { 1, "\xbc\x12\x34\x55\x2e\xbe\xa3\x2b\x51\x21\x19\x03\x56\xbb\xa6\xd3\xbb\x22\x5b\xb5", " BCL", 18}, // eth / BCL + { 1, "\x1c\x44\x81\x75\x0d\xaa\x5f\xf5\x21\xa2\xa7\x49\x0d\x99\x81\xed\x46\x46\x5d\xbd", " BCPT", 18}, // eth / BCPT + { 1, "\x10\x14\x61\x3e\x2b\x3c\xbc\x4d\x57\x50\x54\xd4\x98\x2e\x58\x0d\x9b\x99\xd7\xb1", " BCV", 8}, // eth / BitCapitalVendor Token + { 1, "\x19\x61\xb3\x33\x19\x69\xed\x52\x77\x07\x51\xfc\x71\x8e\xf5\x30\x83\x8b\x6d\xee", " BDG", 18}, // eth / BitDegree Token + { 1, "\x4d\x8f\xc1\x45\x3a\x0f\x35\x9e\x99\xc9\x67\x59\x54\xe6\x56\xd8\x0d\x99\x6f\xbf", " BEE", 18}, // eth / Bee Token + { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BeerCoin", 0}, // eth / BeerCoin + { 1, "\x6a\xeb\x95\xf0\x6c\xda\x84\xca\x34\x5c\x2d\xe0\xf3\xb7\xf9\x69\x23\xa4\x4f\x4c", " BERRY", 14}, // eth / Berry + { 1, "\x8a\xa3\x3a\x78\x99\xfc\xc8\xea\x5f\xbe\x6a\x60\x8a\x10\x9c\x38\x93\xa1\xb8\xb2", " BET", 18}, // eth / BET + { 1, "\x76\x31\x86\xeb\x8d\x48\x56\xd5\x36\xed\x44\x78\x30\x29\x71\x21\x4f\xeb\xc6\xa9", " BETR", 18}, // eth / BETR + { 1, "\xb2\xbf\xeb\x70\xb9\x03\xf1\xba\xac\x7f\x2b\xa2\xc6\x29\x34\xc7\xe5\xb9\x74\xc4", " BKB", 8}, // eth / BetKing Bankroll Token + { 1, "\x3c\xf9\xe0\xc3\x85\xa5\xab\xec\x9f\xd2\xa7\x17\x90\xaa\x34\x4c\x4e\x8e\x35\x70", " BKRx", 18}, // eth / BlockRx + { 1, "\x45\x24\x5b\xc5\x92\x19\xee\xaa\xf6\xcd\x3f\x38\x2e\x07\x8a\x46\x1f\xf9\xde\x7b", " BKX", 18}, // eth / BANKEX + { 1, "\x10\x7c\x45\x04\xcd\x79\xc5\xd2\x69\x6e\xa0\x03\x0a\x8d\xd4\xe9\x26\x01\xb8\x2e", " BLT", 18}, // eth / Bloom + { 1, "\x53\x9e\xfe\x69\xbc\xdd\x21\xa8\x3e\xfd\x91\x22\x57\x1a\x64\xcc\x25\xe0\x28\x2b", " BLUE", 8}, // eth / Ethereum Blue + { 1, "\xce\x59\xd2\x9b\x09\xaa\xe5\x65\xfe\xee\xf8\xe5\x2f\x47\xc3\xcd\x53\x68\xc6\x63", " BLX (Bullion)", 18}, // eth / Bullion Crypto + { 1, "\xe5\xa7\xc1\x29\x72\xf3\xbb\xfe\x70\xed\x29\x52\x1c\x89\x49\xb8\xaf\x6a\x09\x70", " BLX (Iconomi)", 18}, // eth / Iconomi + { 1, "\x57\x32\x04\x6a\x88\x37\x04\x40\x4f\x28\x4c\xe4\x1f\xfa\xdd\x5b\x00\x7f\xd6\x68", " BLZ", 18}, // eth / Bluezelle + { 1, "\xdf\x6e\xf3\x43\x35\x07\x80\xbf\x8c\x34\x10\xbf\x06\x2e\x0c\x01\x5b\x1d\xd6\x71", " BMC", 8}, // eth / Blackmoon Crypto BMC Token + { 1, "\xf0\x28\xad\xee\x51\x53\x3b\x1b\x47\xbe\xaa\x89\x0f\xeb\x54\xa4\x57\xf5\x1e\x89", " BMT", 18}, // eth / BMT + { 1, "\x98\x6e\xe2\xb9\x44\xc4\x2d\x01\x7f\x52\xaf\x21\xc4\xc6\x9b\x84\xdb\xea\x35\xd8", " BMX", 18}, // eth / BitMartToken + { 1, "\xb8\xc7\x74\x82\xe4\x5f\x1f\x44\xde\x17\x45\xf5\x2c\x74\x42\x6c\x63\x1b\xdd\x52", " BNB", 18}, // eth / BNB + { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, // eth / BNC + { 1, "\xda\x2c\x42\x4f\xc9\x8c\x74\x1c\x2d\x4e\xf2\xf4\x28\x97\xce\xfe\xd8\x97\xca\x75", " BNFT", 9}, // eth / Benefits Coin + { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, // eth / Bancor + { 1, "\xd2\xd6\x15\x86\x83\xae\xe4\xcc\x83\x80\x67\x72\x72\x09\xa0\xaa\xf4\x35\x9d\xe3", " BNTY", 18}, // eth / Bounty0x Token + { 1, "\xdf\x34\x79\x11\x91\x0b\x6c\x9a\x42\x86\xba\x8e\x2e\xe5\xea\x4a\x39\xeb\x21\x34", " BOB", 18}, // eth / Bob's repair + { 1, "\xcc\x34\x36\x6e\x38\x42\xca\x1b\xd3\x6c\x1f\x32\x4d\x15\x25\x79\x60\xfc\xc8\x01", " BON", 18}, // eth / Bonpay + { 1, "\x7f\x1e\x2c\x7d\x6a\x69\xbf\x34\x82\x4d\x72\xc5\x3b\x45\x50\xe8\x95\xc0\xd8\xc2", " BOP", 8}, // eth / BlockOptiopns Token + { 1, "\xc2\xc6\x3f\x23\xec\x5e\x97\xef\xbd\x75\x65\xdf\x9e\xc7\x64\xfd\xc7\xd4\xe9\x1d", " BOU", 18}, // eth / Boule Coin + { 1, "\x32\x76\x82\x77\x9b\xab\x2b\xf4\xd1\x33\x7e\x89\x74\xab\x9d\xe8\x27\x5a\x7c\xa8", " BPT", 18}, // eth / Blockport Token + { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, // eth / Bitquence + { 1, "\x9e\x77\xd5\xa1\x25\x1b\x6f\x7d\x45\x67\x22\xa6\xea\xc6\xd2\xd5\x98\x0b\xd8\x91", " BRAT", 8}, // eth / BRAT + { 1, "\x55\x8e\xc3\x15\x2e\x2e\xb2\x17\x49\x05\xcd\x19\xae\xa4\xe3\x4a\x23\xde\x9a\xd6", " BRD", 18}, // eth / Bread + { 1, "\xf2\x6e\xf5\xe0\x54\x53\x84\xb7\xdc\xc0\xf2\x97\xf2\x67\x41\x89\x58\x68\x30\xdf", " BSDC", 18}, // eth / BSDC + { 1, "\x50\x9a\x38\xb7\xa1\xcc\x0d\xcd\x83\xaa\x9d\x06\x21\x46\x63\xd9\xec\x7c\x7f\x4a", " BST", 18}, // eth / BlocksquareToken + { 1, "\x08\x86\x94\x9c\x1b\x8c\x41\x28\x60\xc4\x26\x4c\xeb\x80\x83\xd1\x36\x5e\x86\xcf", " BTCE", 8}, // eth / EthereumBitcoin + { 1, "\x5a\xcd\x19\xb9\xc9\x1e\x59\x6b\x1f\x06\x2f\x18\xe3\xd0\x2d\xa7\xed\x8d\x1e\x50", " BTCL", 8}, // eth / BTC Lite + { 1, "\x73\xdd\x06\x9c\x29\x9a\x5d\x69\x1e\x98\x36\x24\x3b\xca\xec\x9c\x8c\x1d\x87\x34", " BTE", 8}, // eth / BTE + { 1, "\xfa\xd5\x72\xdb\x56\x6e\x52\x34\xac\x9f\xc3\xd5\x70\xc4\xed\xc0\x05\x0e\xaa\x92", " BTH", 18}, // eth / Bytether + { 1, "\xa0\x2e\x3b\xb9\xce\xbc\x03\x95\x26\x01\xb3\x72\x4b\x49\x40\xe0\x84\x5b\xeb\xcf", " BTHR", 18}, // eth / Bethereum + { 1, "\xdb\x86\x46\xf5\xb4\x87\xb5\xdd\x97\x9f\xac\x61\x83\x50\xe8\x50\x18\xf5\x57\xd4", " BTK", 18}, // eth / Bitcoin Token + { 1, "\x2a\xcc\xab\x9c\xb7\xa4\x8c\x3e\x82\x28\x6f\x0b\x2f\x87\x98\xd2\x01\xf4\xec\x3f", " BTL (Battle)", 18}, // eth / BTL (Battle) + { 1, "\x92\x68\x5e\x93\x95\x65\x37\xc2\x5b\xb7\x5d\x5d\x47\xfc\xa4\x26\x6d\xd6\x28\xb8", " BTL (Bitlle)", 4}, // eth / Bitlle Token + { 1, "\xcb\x97\xe6\x5f\x07\xda\x24\xd4\x6b\xcd\xd0\x78\xeb\xeb\xd7\xc6\xe6\xe3\xd7\x50", " BTM", 8}, // eth / Bytom + { 1, "\x16\xb0\xe6\x2a\xc1\x3a\x2f\xae\xd3\x6d\x18\xbc\xe2\x35\x6d\x25\xab\x3c\xfa\xd3", " BTQ", 18}, // eth / Bitcoin Boutique + { 1, "\x08\x0a\xa0\x7e\x2c\x71\x85\x15\x0d\x7e\x4d\xa9\x88\x38\xa8\xd2\xfe\xac\x3d\xfc", " BTT", 0}, // eth / Bitether + { 1, "\xfa\x45\x6c\xf5\x52\x50\xa8\x39\x08\x8b\x27\xee\x32\xa4\x24\xd7\xda\xcb\x54\xff", " BTTX", 18}, // eth / Blocktrade.com + { 1, "\xca\x3c\x18\xa6\x5b\x80\x2e\xc2\x67\xf8\xf4\x80\x25\x45\xe7\xf5\x3d\x24\xc7\x5e", " BUC", 18}, // eth / BeeUnity Chain + { 1, "\x26\xe7\x53\x07\xfc\x0c\x02\x14\x72\xfe\xb8\xf7\x27\x83\x95\x31\xf1\x12\xf3\x17", " C20", 18}, // eth / Crypto20's Token + { 1, "\xd4\x2d\xeb\xe4\xed\xc9\x2b\xd5\xa3\xfb\xb4\x24\x3e\x1e\xcc\xf6\xd6\x3a\x4a\x5d", " C8", 18}, // eth / Carboneum + { 1, "\x7d\x4b\x8c\xce\x05\x91\xc9\x04\x4a\x22\xee\x54\x35\x33\xb7\x2e\x97\x6e\x36\xc3", " CAG", 18}, // eth / Change Bank + { 1, "\x1d\x46\x24\x14\xfe\x14\xcf\x48\x9c\x7a\x21\xca\xc7\x85\x09\xf4\xbf\x8c\xd7\xc0", " CAN", 6}, // eth / CAN + { 1, "\x42\x3e\x43\x22\xcd\xda\x29\x15\x6b\x49\xa1\x7d\xfb\xd2\xac\xc4\xb2\x80\x60\x0d", " CAR", 9}, // eth / Car Sharing Community + { 1, "\xa5\x17\xa4\x6b\xaa\xd6\xb0\x54\xa7\x6b\xd1\x9c\x46\x84\x4f\x71\x7f\xe6\x9f\xea", " CARB", 8}, // eth / CarbCoin + { 1, "\x21\x08\xe6\x2d\x33\x5b\xbd\xc8\x9e\xc3\xe9\xd8\x58\x2f\x18\xdc\xfb\x0c\xdf\xf4", " CARCO", 8}, // eth / CARCO + { 1, "\x1e\xd2\xb1\xea\xed\x8e\x96\x8b\xc3\x6e\xb9\x0a\x91\x46\x60\xa7\x18\x27\xa5\xe9", " CARD", 0}, // eth / Cardstack Token + { 1, "\xbf\x18\xf2\x46\xb9\x30\x1f\x23\x1e\x95\x61\xb3\x5a\x38\x79\x76\x9b\xb4\x63\x75", " CARE", 18}, // eth / Token CARE + { 1, "\xe8\x78\x0b\x48\xbd\xb0\x5f\x92\x86\x97\xa5\xe8\x15\x5f\x67\x2e\xd9\x14\x62\xf7", " CAS", 18}, // eth / Cashaa + { 1, "\x12\x34\x56\x74\x61\xd3\xf8\xdb\x74\x96\x58\x17\x74\xbd\x86\x9c\x83\xd5\x1c\x93", " CAT (BitClave)", 18}, // eth / CAT (BitClave) + { 1, "\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", " CAT (Blockcat)", 18}, // eth / CAT (Blockcat) + { 1, "\x68\xe1\x4b\xb5\xa4\x5b\x96\x81\x32\x7e\x16\xe5\x28\x08\x4b\x9d\x96\x2c\x1a\x39", " CATs (BitClave)_Old", 18}, // eth / CATs (BitClave)_Old + { 1, "\xc1\x66\x03\x87\x05\xff\xba\xb3\x79\x41\x85\xb3\xa9\xd9\x25\x63\x2a\x1d\xf3\x7d", " CC3", 18}, // eth / Coal Coin + { 1, "\x28\x57\x7a\x6d\x31\x55\x9b\xd2\x65\xce\x3a\xdb\x62\xd0\x45\x85\x50\xf7\xb8\xa7", " CCC (CryptoCrashCourse)", 18}, // eth / CryptoCrashCourse + { 1, "\xbe\x11\xee\xb1\x86\xe6\x24\xb8\xf2\x6a\x50\x45\x57\x5a\x13\x40\xe4\x05\x45\x52", " CCC (ICONOMI)", 18}, // eth / CCC (ICONOMI) + { 1, "\xd3\x48\xe0\x7a\x28\x06\x50\x5b\x85\x61\x23\x04\x5d\x27\xae\xed\x90\x92\x4b\x50", " CCLC", 8}, // eth / Christ Coin + { 1, "\x31\x5c\xe5\x9f\xaf\xd3\xa8\xd5\x62\xb7\xec\x1c\x85\x42\x38\x2d\x27\x10\xb0\x6c", " CCS", 18}, // eth / CacaoShares + { 1, "\x8a\x95\xca\x44\x8a\x52\xc0\xad\xf0\x05\x4b\xb3\x40\x2d\xc5\xe0\x9c\xd6\xb2\x32", " CDL", 18}, // eth / Confideal + { 1, "\x17\x7d\x39\xac\x67\x6e\xd1\xc6\x7a\x2b\x26\x8a\xd7\xf1\xe5\x88\x26\xe5\xb0\xaf", " CDT", 18}, // eth / CoinDash + { 1, "\x6f\xff\x38\x06\xbb\xac\x52\xa2\x0e\x0d\x79\xbc\x53\x8d\x52\x7f\x6a\x22\xc9\x6b", " CDX", 18}, // eth / CDX + { 1, "\x2c\xb1\x01\xd7\xda\x0e\xba\xa5\x7d\x3f\x2f\xef\x46\xd7\xff\xb7\xbb\x64\x59\x2b", " CDX", 0}, // eth / Carbon Dollar X + { 1, "\xb0\x56\xc3\x8f\x6b\x7d\xc4\x06\x43\x67\x40\x3e\x26\x42\x4c\xd2\xc6\x06\x55\xe1", " CEEK", 18}, // eth / CEEK VR Token + { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, // eth / Cofound.it + { 1, "\x69\x56\x98\x3f\x8b\x3c\xe1\x73\xb4\xab\x84\x36\x1a\xa0\xad\x52\xf3\x8d\x93\x6f", " CFTY", 8}, // eth / Crafty Token + { 1, "\xba\x9d\x41\x99\xfa\xb4\xf2\x6e\xfe\x35\x51\xd4\x90\xe3\x82\x14\x86\xf1\x35\xba", " CHSB", 8}, // eth / CHSB + { 1, "\x06\x01\x2c\x8c\xf9\x7b\xea\xd5\xde\xae\x23\x70\x70\xf9\x58\x7f\x8e\x7a\x26\x6d", " CK", 0}, // eth / CK + { 1, "\xb1\xc1\xcb\x8c\x7c\x19\x92\xdb\xa2\x4e\x62\x8b\xf7\xd3\x8e\x71\xda\xd4\x6a\xeb", " CLB", 18}, // eth / Cloudbric + { 1, "\x3d\xc9\xa4\x2f\xa7\xaf\xe5\x7b\xe0\x3c\x58\xfd\x7f\x44\x11\xb1\xe4\x66\xc5\x08", " CLL", 18}, // eth / CryptoLiveLeak + { 1, "\x41\x62\x17\x8b\x78\xd6\x98\x54\x80\xa3\x08\xb2\x19\x0e\xe5\x51\x74\x60\x40\x6d", " CLN", 18}, // eth / ColuLocalNetwork + { 1, "\x7f\xce\x28\x56\x89\x9a\x68\x06\xee\xef\x70\x80\x79\x85\xfc\x75\x54\xc6\x63\x40", " CLP", 9}, // eth / CryptoLending + { 1, "\x3e\xdd\x23\x5c\x3e\x84\x0c\x1f\x29\x28\x6b\x2e\x39\x37\x0a\x25\x5c\x7b\x6f\xdb", " CMBT", 8}, // eth / CMBToken + { 1, "\x7e\x66\x75\x25\x52\x1c\xf6\x13\x52\xe2\xe0\x1b\x50\xfa\xaa\xe7\xdf\x39\x74\x9a", " CMC", 18}, // eth / CryptoMart + { 1, "\xf8\x5f\xee\xa2\xfd\xd8\x1d\x51\x17\x7f\x6b\x8f\x35\xf0\xe6\x73\x4c\xe4\x5f\x5f", " CMT", 18}, // eth / CyberMiles Token + { 1, "\xeb\xf2\xf9\xe8\xde\x96\x0f\x64\xec\x0f\xdc\xda\x6c\xb2\x82\x42\x31\x33\x34\x7b", " CNB", 8}, // eth / Canabio + { 1, "\xd4\xc4\x35\xf5\xb0\x9f\x85\x5c\x33\x17\xc8\x52\x4c\xb1\xf5\x86\xe4\x27\x95\xfa", " CND", 18}, // eth / Cindicator + { 1, "\xb4\xb1\xd2\xc2\x17\xec\x07\x76\x58\x4c\xe0\x8d\x3d\xd9\x8f\x90\xed\xed\xa4\x4b", " CO2", 18}, // eth / Climatecoin + { 1, "\x57\x4b\x36\xbc\xed\x44\x33\x38\x87\x5d\x17\x1c\xc3\x77\xe6\x91\xf7\xd4\xf8\x87", " CO2Bit", 18}, // eth / CO2Bit + { 1, "\xb2\xf7\xeb\x1f\x2c\x37\x64\x5b\xe6\x1d\x73\x95\x30\x35\x36\x0e\x76\x8d\x81\xe6", " COB", 18}, // eth / Cobinhood Token + { 1, "\x31\x36\xef\x85\x15\x92\xac\xf4\x9c\xa4\xc8\x25\x13\x1e\x36\x41\x70\xfa\x32\xb3", " COFI", 18}, // eth / CoinFi Token + { 1, "\x0c\x91\xb0\x15\xab\xa6\xf7\xb4\x73\x8d\xcd\x36\xe7\x41\x01\x38\xb2\x9a\xdc\x29", " COIL", 8}, // eth / CoinOil + { 1, "\x5e\x8f\x85\x59\x66\xd6\x38\x13\x5a\x96\x88\x61\xe8\x0d\xda\x72\x22\x91\xb0\x6d", " COIN", 18}, // eth / Coinvest V2 Token + { 1, "\x65\x29\x2e\xea\xdf\x14\x26\xcd\x2d\xf1\xc4\x79\x3a\x3d\x75\x19\xf2\x53\x91\x3b", " COSS", 18}, // eth / Coss Token + { 1, "\x9e\x96\x60\x44\x45\xec\x19\xff\xed\x9a\x5e\x8d\xd7\xb5\x0a\x29\xc8\x99\xa1\x0c", " COSS", 18}, // eth / Coss Token + { 1, "\xe2\xfb\x65\x29\xef\x56\x6a\x08\x0e\x6d\x23\xde\x0b\xd3\x51\x31\x10\x87\xd5\x67", " COV", 18}, // eth / Covesting + { 1, "\xb7\x87\xd4\xea\xc8\x89\x97\x30\xbb\x8c\x57\xfc\x3c\x99\x8c\x49\xc5\x24\x4e\xc0", " CPEX", 8}, // eth / CoinPulseToken + { 1, "\xf4\x47\x45\xfb\xd4\x1f\x6a\x1b\xa1\x51\xdf\x19\x0d\xb0\x56\x4c\x5f\xcc\x44\x10", " CPY", 18}, // eth / COPYTRACK + { 1, "\x7f\x58\x5b\x91\x30\xc6\x4e\x9e\x9f\x47\x0b\x61\x8a\x7b\xad\xd0\x3d\x79\xca\x7e", " CR7", 18}, // eth / CR7Coin + { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, // eth / CRB + { 1, "\x67\x2a\x1a\xd4\xf6\x67\xfb\x18\xa3\x33\xaf\x13\x66\x7a\xa0\xaf\x1f\x5b\x5b\xdd", " CRED", 18}, // eth / CRED + { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, // eth / Credo / Bitbounce + { 1, "\x80\xa7\xe0\x48\xf3\x7a\x50\x50\x03\x51\xc2\x04\xcb\x40\x77\x66\xfa\x3b\xae\x7f", " CRPT", 18}, // eth / CrypteriumToken + { 1, "\xf0\xda\x11\x86\xa4\x97\x72\x26\xb9\x13\x5d\x06\x13\xee\x72\xe2\x29\xec\x3f\x4d", " CRT", 18}, // eth / CreamtoeCoin + { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CryptoCarbon", 6}, // eth / CryptoCarbon + { 1, "\x45\x45\x75\x0f\x39\xaf\x6b\xe4\xf2\x37\xb6\x86\x9d\x4e\xcc\xa9\x28\xfd\x5a\x85", " CTF", 18}, // eth / CryptoTask + { 1, "\xc8\x7c\x5d\xd8\x6a\x3d\x56\x7f\xf2\x87\x01\x88\x6f\xb0\x74\x5a\xaa\x89\x8d\xa4", " CTG", 18}, // eth / CT Global Token + { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, // eth / CTL + { 1, "\xe3\xfa\x17\x7a\xce\xcf\xb8\x67\x21\xcf\x6f\x9f\x42\x06\xbd\x3b\xd6\x72\xd7\xd5", " CTT", 18}, // eth / ChainTrade Token + { 1, "\x66\x2a\xbc\xad\x0b\x7f\x34\x5a\xb7\xff\xb1\xb1\xfb\xb9\xdf\x78\x94\xf1\x8e\x66", " CTX", 18}, // eth / CarTaxi + { 1, "\xda\x6c\xb5\x8a\x0d\x0c\x01\x61\x0a\x29\xc5\xa6\x5c\x30\x3e\x13\xe8\x85\x88\x7c", " cV", 18}, // eth / carVertical + { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, // eth / CVC + { 1, "\x21\x34\x05\x7c\x0b\x46\x1f\x89\x8d\x37\x5c\xea\xd6\x52\xac\xae\x62\xb5\x95\x41", " CXC", 18}, // eth / CoxxxCoin + { 1, "\xb6\xee\x96\x68\x77\x1a\x79\xbe\x79\x67\xee\x29\xa6\x3d\x41\x84\xf8\x09\x71\x43", " CXO", 18}, // eth / CargoX + { 1, "\xda\xb0\xc3\x1b\xf3\x4c\x89\x7f\xb0\xfe\x90\xd1\x2e\xc9\x40\x1c\xaf\x5c\x36\xec", " DAB", 0}, // eth / DAB + { 1, "\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba", " DADI", 18}, // eth / DADI + { 1, "\x89\xd2\x4a\x6b\x4c\xcb\x1b\x6f\xaa\x26\x25\xfe\x56\x2b\xdd\x9a\x23\x26\x03\x59", " DAI", 18}, // eth / Dai Stablecoin v1.0 + { 1, "\x07\xd9\xe4\x9e\xa4\x02\x19\x4b\xf4\x8a\x82\x76\xda\xfb\x16\xe4\xed\x63\x33\x17", " DALC", 8}, // eth / DaleCoin + { 1, "\x9b\x70\x74\x0e\x70\x8a\x08\x3c\x6f\xf3\x8d\xf5\x22\x97\x02\x0f\x5d\xfa\xa5\xee", " DAN", 10}, // eth / DaneelToken + { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, // eth / DAO + { 1, "\x81\xc9\x15\x1d\xe0\xc8\xba\xfc\xd3\x25\xa5\x7e\x3d\xb5\xa5\xdf\x1c\xeb\xf7\x9c", " DAT", 18}, // eth / Datum Token + { 1, "\x1b\x5f\x21\xee\x98\xee\xd4\x8d\x29\x2e\x8e\x2d\x3e\xd8\x2b\x40\xa9\x72\x8a\x22", " DATABroker", 18}, // eth / DataBrokerDAO Token + { 1, "\x0c\xf0\xee\x63\x78\x8a\x08\x49\xfe\x52\x97\xf3\x40\x7f\x70\x1e\x12\x2c\xc0\x23", " DATACoin", 18}, // eth / DATACoin + { 1, "\xd8\x2d\xf0\xab\xd3\xf5\x14\x25\xeb\x15\xef\x75\x80\xfd\xa5\x57\x27\x87\x5f\x14", " DAV", 18}, // eth / DAV Token + { 1, "\x61\x72\x5f\x3d\xb4\x00\x4a\xfe\x01\x47\x45\xb2\x1d\xab\x1e\x16\x77\xcc\x32\x8b", " DAXT", 18}, // eth / Digital Asset Exchange Token + { 1, "\xe8\x14\xae\xe9\x60\xa8\x52\x08\xc3\xdb\x54\x2c\x53\xe7\xd4\xa6\xc8\xd5\xf6\x0f", " DAY", 18}, // eth / ChronoLogic DAY + { 1, "\x38\x6f\xaa\x47\x03\xa3\x4a\x7f\xdb\x19\xbe\xc2\xe1\x4f\xd4\x27\xc9\x63\x84\x16", " DCA", 18}, // eth / DoBetAcceptBet + { 1, "\x39\x9a\x0e\x6f\xbe\xb3\xd7\x4c\x85\x35\x74\x39\xf4\xc8\xae\xd9\x67\x8a\x5c\xbf", " DCL", 3}, // eth / DCL + { 1, "\x08\xd3\x2b\x0d\xa6\x3e\x2c\x3b\xcf\x80\x19\xc9\xc5\xd8\x49\xd7\xa9\xd7\x91\xe6", " DCN", 0}, // eth / Dentacoin + { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, // eth / DDF + { 1, "\x15\x12\x02\xc9\xc1\x8e\x49\x56\x56\xf3\x72\x28\x1f\x49\x3e\xb7\x69\x89\x61\xd5", " DEB", 18}, // eth / DEBITUM + { 1, "\x07\x5c\x60\xee\x2c\xd3\x08\xff\x47\x87\x3b\x38\xbd\x9a\x0f\xa5\x85\x33\x82\xc4", " DEEZ", 18}, // eth / DeezNuts + { 1, "\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", " DENT", 8}, // eth / DENT + { 1, "\x7c\xf2\x71\x96\x6f\x36\x34\x3b\xf0\x15\x0f\x25\xe5\x36\x4f\x79\x61\xc5\x82\x01", " DEPO", 0}, // eth / CRYPTODEPOZIT + { 1, "\xdd\x94\xde\x9c\xfe\x06\x35\x77\x05\x1a\x5e\xb7\x46\x5d\x08\x31\x7d\x88\x08\xb6", " Devcon2 Token", 0}, // eth / Devcon2 Token + { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, // eth / Digix DAO + { 1, "\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1", " DGPT", 18}, // eth / DigiPulse + { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX", 9}, // eth / DGX + { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, // eth / Etheroll + { 1, "\x13\xf1\x1c\x99\x05\xa0\x8c\xa7\x6e\x3e\x85\x3b\xe6\x3d\x4f\x09\x44\x32\x6c\x72", " DIVX", 18}, // eth / DIVX + { 1, "\xba\x18\x7b\x09\xff\xa8\xdd\xdc\x80\xd2\x57\x1e\xd3\xcb\xc4\xbe\x0a\xf6\x9e\x0c", " DKP", 18}, // eth / Draggin Karma Points + { 1, "\x07\xe3\xc7\x06\x53\x54\x8b\x04\xf0\xa7\x59\x70\xc1\xf8\x1b\x4c\xbb\xfb\x60\x6f", " DLT", 18}, // eth / Agrello + { 1, "\x2c\xcb\xff\x3a\x04\x2c\x68\x71\x6e\xd2\xa2\xcb\x0c\x54\x4a\x9f\x1d\x19\x35\xe1", " DMT", 8}, // eth / DMarket Token + { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, // eth / DistrictOx + { 1, "\xe4\x3e\x20\x41\xdc\x37\x86\xe1\x66\x96\x1e\xd9\x48\x4a\x55\x39\x03\x3d\x10\xfb", " DNX", 18}, // eth / DenCity + { 1, "\x76\x97\x4c\x7b\x79\xdc\x8a\x6a\x10\x9f\xd7\x1f\xd7\xce\xb9\xe4\x0e\xff\x53\x82", " DOW", 18}, // eth / DOW + { 1, "\xee\xf6\xe9\x00\x34\xee\xa8\x9e\x31\xeb\x4b\x8e\xac\xd3\x23\xf2\x8a\x92\xea\xe4", " DOW", 18}, // eth / DOW + { 1, "\x01\xb3\xec\x4a\xae\x1b\x87\x29\x52\x9b\xeb\x49\x65\xf2\x7d\x00\x87\x88\xb0\xeb", " DPP", 18}, // eth / Digital Assets Power Play + { 1, "\x41\x9c\x4d\xb4\xb9\xe2\x5d\x6d\xb2\xad\x96\x91\xcc\xb8\x32\xc8\xd9\xfd\xa0\x5e", " DRGN", 18}, // eth / Dragon + { 1, "\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37", " DROP", 0}, // eth / Droplex + { 1, "\x46\x72\xba\xd5\x27\x10\x74\x71\xcb\x50\x67\xa8\x87\xf4\x65\x6d\x58\x5a\x8a\x31", " DROP (dropil)", 18}, // eth / Dropil + { 1, "\x27\x99\xd9\x0c\x6d\x44\xcb\x9a\xa5\xfb\xc3\x77\x17\x7f\x16\xc3\x3e\x05\x6b\x82", " DRP", 0}, // eth / Dripcoin + { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, // eth / DCorp + { 1, "\x1e\x09\xbd\x8c\xad\xb4\x41\x63\x2e\x44\x1d\xb3\xe1\xd7\x99\x09\xee\x0a\x22\x56", " DSC", 1}, // eth / Digital Safe Coin + { 1, "\x5a\xdc\x96\x1d\x6a\xc3\xf7\x06\x2d\x2e\xa4\x5f\xef\xb8\xd8\x16\x7d\x44\xb1\x90", " DTH", 18}, // eth / dether + { 1, "\xd2\x34\xbf\x24\x10\xa0\x00\x9d\xf9\xc3\xc6\x3b\x61\x0c\x09\x73\x8f\x18\xcc\xd7", " DTR", 8}, // eth / DTR + { 1, "\xf9\xf7\xc2\x9c\xfd\xf1\x9f\xcf\x1f\x2a\xa6\xb8\x4a\xa3\x67\xbc\xf1\xbd\x16\x76", " DTT", 18}, // eth / Delphi Tech Token + { 1, "\x76\x5f\x0c\x16\xd1\xdd\xc2\x79\x29\x5c\x1a\x7c\x24\xb0\x88\x3f\x62\xd3\x3f\x75", " DTX", 18}, // eth / DaTa eXchange Token + { 1, "\x82\xfd\xed\xfb\x76\x35\x44\x1a\xa5\xa9\x27\x91\xd0\x01\xfa\x73\x88\xda\x80\x25", " DTx", 18}, // eth / DigitalTicks + { 1, "\x9c\x6f\xa4\x22\x09\x16\x9b\xce\xa0\x32\xe4\x01\x18\x8a\x6f\xc3\xe9\xc9\xf5\x9c", " DUBI", 18}, // eth / Decentralized Universal Basic Income + { 1, "\xd4\xcf\xfe\xef\x10\xf6\x0e\xca\x58\x1b\x5e\x11\x46\xb5\xac\xa4\x19\x4a\x4c\x3b", " DUBI", 18}, // eth / Decentralized Universal Basic Income + { 1, "\x99\x4f\x0d\xff\xdb\xae\x0b\xbf\x09\xb6\x52\xd6\xf1\x1a\x49\x3f\xd3\x3f\x42\xb9", " EAGLE", 18}, // eth / EagleCoin + { 1, "\xaf\xc3\x97\x88\xc5\x1f\x0c\x1f\xf7\xb5\x53\x17\xf3\xe7\x02\x99\xe5\x21\xff\xf6", " eBCH", 8}, // eth / eBCH + { 1, "\xeb\x7c\x20\x02\x71\x72\xe5\xd1\x43\xfb\x03\x0d\x50\xf9\x1c\xec\xe2\xd1\x48\x5d", " eBTC", 8}, // eth / eBTC + { 1, "\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", " ECN", 2}, // eth / ECN + { 1, "\x17\xf9\x34\x75\xd2\xa9\x78\xf5\x27\xc3\xf7\xc4\x4a\xbf\x44\xad\xfb\xa6\x0d\x5c", " ECO2", 2}, // eth / EtherCO2 + { 1, "\xfa\x1d\xe2\xee\x97\xe4\xc1\x0c\x94\xc9\x1c\xb2\xb5\x06\x2b\x89\xfb\x14\x0b\x82", " EDC", 6}, // eth / Education Credits + { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, // eth / Edgeless + { 1, "\xce\xd4\xe9\x31\x98\x73\x4d\xda\xff\x84\x92\xd5\x25\xbd\x25\x8d\x49\xeb\x38\x8e", " EDO", 18}, // eth / Eidoo + { 1, "\x5b\x26\xc5\xd0\x77\x2e\x5b\xba\xc8\xb3\x18\x2a\xe9\xa1\x3f\x9b\xb2\xd0\x37\x65", " EDU", 8}, // eth / EDU + { 1, "\x2a\x22\xe5\xcc\xa0\x0a\x3d\x63\x30\x8f\xa3\x9f\x29\x20\x2e\xb1\xb3\x9e\xef\x52", " EDU", 6}, // eth / EDU Token + { 1, "\xb5\x3a\x96\xbc\xbd\xd9\xcf\x78\xdf\xf2\x0b\xab\x6c\x2b\xe7\xba\xec\x8f\x00\xf8", " eGAS", 8}, // eth / ETH GAS + { 1, "\x8e\x1b\x44\x8e\xc7\xad\xfc\x7f\xa3\x5f\xc2\xe8\x85\x67\x8b\xd3\x23\x17\x6e\x34", " EGT", 18}, // eth / Egretia Token + { 1, "\xf9\xf0\xfc\x71\x67\xc3\x11\xdd\x2f\x1e\x21\xe9\x20\x4f\x87\xeb\xa9\x01\x2f\xb2", " EHT", 8}, // eth / EasyHomes + { 1, "\xbf\x21\x79\x85\x9f\xc6\xd5\xbe\xe9\xbf\x91\x58\x63\x2d\xc5\x16\x78\xa4\x10\x0e", " ELF", 18}, // eth / ELF Token + { 1, "\xc8\xc6\xa3\x1a\x4a\x80\x6d\x37\x10\xa7\xb3\x8b\x7b\x29\x6d\x2f\xab\xcc\xdb\xa8", " ELIX", 18}, // eth / Elixir Token + { 1, "\x44\x19\x7a\x4c\x44\xd6\xa0\x59\x29\x7c\xaf\x6b\xe4\xf7\xe1\x72\xbd\x56\xca\xaf", " ELTCOIN", 8}, // eth / ELTCOIN + { 1, "\xb6\x7b\x88\xa2\x57\x08\xa3\x5a\xe7\xc2\xd7\x36\xd3\x98\xd2\x68\xce\x4f\x7f\x83", " EMON", 8}, // eth / Etheremon + { 1, "\x95\xda\xaa\xb9\x80\x46\x84\x6b\xf4\xb2\x85\x3e\x23\xcb\xa2\x36\xfa\x39\x4a\x31", " EMONT", 8}, // eth / Etheremon Token + { 1, "\x95\x01\xbf\xc4\x88\x97\xdc\xee\xad\xf7\x31\x13\xef\x63\x5d\x2f\xf7\xee\x4b\x97", " EMT", 18}, // eth / easyMINE Token + { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, // eth / EMovieVenture + { 1, "\x03\x9f\x50\x50\xde\x49\x08\xf9\xb5\xdd\xf4\x0a\x4f\x3a\xa3\xf3\x29\x08\x63\x87", " ENC", 18}, // eth / Ethernet.Cash + { 1, "\xf0\xee\x6b\x27\xb7\x59\xc9\x89\x3c\xe4\xf0\x94\xb4\x9a\xd2\x8f\xd1\x5a\x23\xe4", " ENG", 8}, // eth / Enigma + { 1, "\xf6\x29\xcb\xd9\x4d\x37\x91\xc9\x25\x01\x52\xbd\x8d\xfb\xdf\x38\x0e\x2a\x3b\x9c", " ENJ", 18}, // eth / ENJIN + { 1, "\x5b\xc7\xe5\xf0\xab\x8b\x2e\x10\xd2\xd0\xa3\xf2\x17\x39\xfc\xe6\x24\x59\xae\xf3", " ENTRP", 18}, // eth / Hut34 Entropy Token + { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, // eth / EOS + { 1, "\x7e\x9e\x43\x1a\x0b\x8c\x4d\x53\x2c\x74\x5b\x10\x43\xc7\xfa\x29\xa4\x8d\x4f\xba", " eosDAC", 18}, // eth / eosDAC + { 1, "\x35\xba\xa7\x20\x38\xf1\x27\xf9\xf8\xc8\xf9\xb4\x91\x04\x9f\x64\xf3\x77\x91\x4d", " EPX", 4}, // eth / ethPoker.io EPX + { 1, "\xe8\xa1\xdf\x95\x8b\xe3\x79\x04\x5e\x2b\x46\xa3\x1a\x98\xb9\x3a\x2e\xcd\xfd\xed", " ESZ", 18}, // eth / ESZCoin + { 1, "\x1b\x97\x43\xf5\x56\xd6\x5e\x75\x7c\x4c\x65\x0b\x45\x55\xba\xf3\x54\xcb\x8b\xd3", " ETBS", 12}, // eth / Ethbits + { 1, "\xdd\x74\xa7\xa3\x76\x9f\xa7\x25\x61\xb3\xa6\x9e\x65\x96\x8f\x49\x74\x8c\x69\x0c", " ETCH", 18}, // eth / ETCH + { 1, "\x3a\x26\x74\x6d\xdb\x79\xb1\xb8\xe4\x45\x0e\x3f\x4f\xfe\x32\x85\xa3\x07\x38\x7e", " ETHB", 8}, // eth / EtherBTC + { 1, "\x69\x27\xc6\x9f\xb4\xda\xf2\x04\x3f\xbb\x1c\xb7\xb8\x6c\x56\x61\x41\x6b\xea\x29", " ETR", 18}, // eth / Etheruem Risen + { 1, "\xab\xdf\x14\x78\x70\x23\x5f\xcf\xc3\x41\x53\x82\x8c\x76\x9a\x70\xb3\xfa\xe0\x1f", " EURT", 6}, // eth / EUR Tether (erc20) + { 1, "\x52\x36\x30\x97\x6e\xb6\x14\x76\x21\xb5\xc3\x1c\x78\x1e\xbe\x2e\xc2\xa8\x06\xe0", " eUSD", 18}, // eth / Ether-Backed USD Nomins (erc20) + { 1, "\x92\x31\x08\xa4\x39\xc4\xe8\xc2\x31\x5c\x4f\x65\x21\xe5\xce\x95\xb4\x4e\x9b\x4c", " EVE", 18}, // eth / EVE + { 1, "\xd7\x80\xae\x2b\xf0\x4c\xd9\x6e\x57\x7d\x3d\x01\x47\x62\xf8\x31\xd9\x71\x29\xd0", " EVN", 18}, // eth / Envion AG + { 1, "\xf3\xdb\x5f\xa2\xc6\x6b\x7a\xf3\xeb\x0c\x0b\x78\x25\x10\x81\x6c\xbe\x48\x13\xb8", " EVX", 4}, // eth / EVX Token + { 1, "\xc9\x8e\x06\x39\xc6\xd2\xec\x03\x7a\x61\x53\x41\xc3\x69\x66\x6b\x11\x0e\x80\xe5", " EXMR", 8}, // eth / eXMRcoin + { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, // eth / FAM + { 1, "\x7f\x67\x15\xc3\xfc\x47\x40\xa0\x2f\x70\xde\x85\xb9\xfd\x50\xac\x60\x01\xfe\xd9", " FANX", 18}, // eth / FANX Token + { 1, "\x00\x9e\x86\x49\x23\xb4\x92\x63\xc7\xf1\x0d\x19\xb7\xf8\xab\x7a\x9a\x5a\xad\x33", " FKX", 18}, // eth / Knoxstertoken + { 1, "\xf0\x4a\x8a\xc5\x53\xfc\xed\xb5\xba\x99\xa6\x47\x99\x15\x58\x26\xc1\x36\xb0\xbe", " FLIXX", 18}, // eth / FLIXX + { 1, "\x04\xcc\x78\x3b\x45\x0b\x8d\x11\xf3\xc7\xd0\x0d\xd0\x3f\xdf\x7f\xb5\x1f\xe9\xf2", " FLMC", 18}, // eth / Filmscoin + { 1, "\x59\x76\xf7\xda\xc1\x52\x5e\xf3\x27\x78\x36\x04\x3b\xa4\x74\xa3\x5e\x6b\x42\x72", " FLMC", 0}, // eth / Filmscoin + { 1, "\x3a\x1b\xda\x28\xad\xb5\xb0\xa8\x12\xa7\xcf\x10\xa1\x95\x0c\x92\x0f\x79\xbc\xd3", " FLP", 18}, // eth / FLIP Token + { 1, "\x9a\xef\xbe\x0b\x3c\x3b\xa9\xea\xb2\x62\xcb\x98\x56\xe8\x15\x7a\xb7\x64\x8e\x09", " FLR", 18}, // eth / Flair Coin + { 1, "\x95\x4b\x5d\xe0\x9a\x55\xe5\x97\x55\xac\xbd\xa2\x9e\x1e\xb7\x4a\x45\xd3\x01\x75", " FLUZ", 18}, // eth / Fluz Fluz Global + { 1, "\x70\xb1\x47\xe0\x1e\x92\x85\xe7\xce\x68\xb9\xba\x43\x7f\xe3\xa9\x19\x0e\x75\x6a", " FLX", 18}, // eth / BitFlux + { 1, "\x4d\xf4\x7b\x49\x69\xb2\x91\x1c\x96\x65\x06\xe3\x59\x2c\x41\x38\x94\x93\x95\x3b", " FND", 18}, // eth / FundRequest + { 1, "\x0a\xbe\xfb\x76\x11\xcb\x3a\x01\xea\x3f\xad\x85\xf3\x3c\x3c\x93\x4f\x8e\x2c\xf4", " FRD", 18}, // eth / FARAD Cryptoken + { 1, "\xe6\xf7\x4d\xcf\xa0\xe2\x08\x83\x00\x8d\x8c\x16\xb6\xd9\xa3\x29\x18\x9d\x0c\x30", " FTC", 2}, // eth / FTC + { 1, "\x20\x23\xdc\xf7\xc4\x38\xc8\xc8\xc0\xb0\xf2\x8d\xba\xe1\x55\x20\xb4\xf3\xee\x20", " FTR", 18}, // eth / Futourist Token + { 1, "\x2a\xec\x18\xc5\x50\x0f\x21\x35\x9c\xe1\xbe\xa5\xdc\x17\x77\x34\x4d\xf4\xc0\xdc", " FTT", 18}, // eth / FarmaTrust Token + { 1, "\x65\xbe\x44\xc7\x47\x98\x8f\xbf\x60\x62\x07\x69\x8c\x94\x4d\xf4\x44\x2e\xfe\x19", " FUCK", 4}, // eth / Finally Usable Crypto Karma + { 1, "\xab\x16\xe0\xd2\x5c\x06\xcb\x37\x62\x59\xcc\x18\xc1\xde\x4a\xca\x57\x60\x55\x89", " FUCK", 4}, // eth / FinallyUsableCryptoKarma + { 1, "\xea\x38\xea\xa3\xc8\x6c\x8f\x9b\x75\x15\x33\xba\x2e\x56\x2d\xeb\x9a\xcd\xed\x40", " FUEL", 18}, // eth / Etherparty FUEL + { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, // eth / Funfair + { 1, "\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", " FYN", 18}, // eth / Fund Yourself Now + { 1, "\xf6\x74\x51\xdc\x84\x21\xf0\xe0\xaf\xeb\x52\xfa\xa8\x10\x10\x34\xed\x08\x1e\xd9", " GAM", 8}, // eth / Gambit + { 1, "\x67\x54\xe2\x1b\x9e\xaa\x05\x3c\x62\xd7\x85\x4d\xd6\x56\x1a\xe4\x51\xb0\xcb\xcf", " GANA", 18}, // eth / GANA + { 1, "\xc0\xea\x63\x06\xf6\x36\x0f\xe7\xdc\xab\x65\xd1\x6b\xf1\xa3\xaf\x92\xc7\x9a\xa2", " GANA", 18}, // eth / GANA + { 1, "\x70\x88\x76\xf4\x86\xe4\x48\xee\x89\xeb\x33\x2b\xfb\xc8\xe5\x93\x55\x30\x58\xb9", " GAVEL", 18}, // eth / GAVEL + { 1, "\x75\x85\xf8\x35\xae\x2d\x52\x27\x22\xd2\x68\x43\x23\xa0\xba\x83\x40\x1f\x32\xf5", " GBT", 18}, // eth / GBT + { 1, "\x12\xfc\xd6\x46\x3e\x66\x97\x4c\xf7\xbb\xc2\x4f\xfc\x4d\x40\xd6\xbe\x45\x82\x83", " GBX", 18}, // eth / Globitex + { 1, "\xdb\x0f\x69\x30\x6f\xf8\xf9\x49\xf2\x58\xe8\x3f\x6b\x87\xee\x5d\x05\x2d\x0b\x23", " GCP", 18}, // eth / Globcoin Crypto Platform + { 1, "\x4f\x4f\x0d\xb4\xde\x90\x3b\x88\xf2\xb1\xa2\x84\x79\x71\xe2\x31\xd5\x4f\x8f\xd3", " GEE", 8}, // eth / Geens NPO + { 1, "\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", " GELD", 18}, // eth / GELD + { 1, "\x54\x3f\xf2\x27\xf6\x4a\xa1\x7e\xa1\x32\xbf\x98\x86\xca\xb5\xdb\x55\xdc\xad\xdf", " GEN", 18}, // eth / DAOstack + { 1, "\x8a\x85\x42\x88\xa5\x97\x60\x36\xa7\x25\x87\x91\x64\xca\x3e\x91\xd3\x0c\x6a\x1b", " GET", 18}, // eth / GET + { 1, "\xfc\xd8\x62\x98\x56\x28\xb2\x54\x06\x1f\x7a\x91\x80\x35\xb8\x03\x40\xd0\x45\xd3", " GIF", 18}, // eth / GIFcoin Token + { 1, "\xae\x4f\x56\xf0\x72\xc3\x4c\x0a\x65\xb3\xae\x3e\x4d\xb7\x97\xd8\x31\x43\x9d\x93", " GIM", 8}, // eth / Gimli + { 1, "\xb3\xbd\x49\xe2\x8f\x8f\x83\x2b\x8d\x1e\x24\x61\x06\x99\x1e\x54\x6c\x32\x35\x02", " GMT", 18}, // eth / GMT + { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, // eth / Gnosis + { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, // eth / Golem + { 1, "\xea\xb4\x31\x93\xcf\x06\x23\x07\x3c\xa8\x9d\xb9\xb7\x12\x79\x63\x56\xfa\x74\x14", " GOLDX", 18}, // eth / GOLDX + { 1, "\x12\xb1\x9d\x3e\x2c\xcc\x14\xda\x04\xfa\xe3\x3e\x63\x65\x2c\xe4\x69\xb3\xf2\xfd", " GRID", 12}, // eth / GRID + { 1, "\x0a\x9a\x9c\xe6\x00\xd0\x8b\xf9\xb7\x6f\x49\xfa\x4e\x7b\x38\xa6\x7e\xbe\xb1\xe6", " GROW", 8}, // eth / Growchain + { 1, "\xb7\x08\x35\xd7\x82\x2e\xbb\x94\x26\xb5\x65\x43\xe3\x91\x84\x6c\x10\x7b\xd3\x2c", " GTC", 18}, // eth / GTC Token + { 1, "\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", " GTKT", 0}, // eth / GTKT + { 1, "\xc5\xbb\xae\x50\x78\x1b\xe1\x66\x93\x06\xb9\xe0\x01\xef\xf5\x7a\x29\x57\xb0\x9d", " GTO", 5}, // eth / Gifto + { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, // eth / GUP + { 1, "\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0", " GVT", 18}, // eth / Genesis Vision + { 1, "\x58\xca\x30\x65\xc0\xf2\x4c\x7c\x96\xae\xe8\xd6\x05\x6b\x5b\x5d\xec\xf9\xc2\xf8", " GXC", 10}, // eth / GXC + { 1, "\x22\xf0\xaf\x8d\x78\x85\x1b\x72\xee\x79\x9e\x05\xf5\x4a\x77\x00\x15\x86\xb1\x8a", " GXVC", 10}, // eth / Genevieve VC + { 1, "\x8c\x65\xe9\x92\x29\x7d\x5f\x09\x2a\x75\x6d\xef\x24\xf4\x78\x1a\x28\x01\x98\xff", " GZE", 18}, // eth / GazeCoin + { 1, "\xe6\x38\xdc\x39\xb6\xad\xbe\xe8\x52\x6b\x5c\x22\x38\x0b\x4b\x45\xda\xf4\x6d\x8e", " GZR", 6}, // eth / Gizer + { 1, "\x90\x02\xd4\x48\x5b\x75\x94\xe3\xe8\x50\xf0\xa2\x06\x71\x3b\x30\x51\x13\xf6\x9e", " HAT", 18}, // eth / Hawala Today + { 1, "\xc0\x11\xa7\x24\x00\xe5\x8e\xcd\x99\xee\x49\x7c\xf8\x9e\x37\x75\xd4\xbd\x73\x2f", " HAV", 18}, // eth / Havven + { 1, "\xff\xe8\x19\x6b\xc2\x59\xe8\xde\xdc\x54\x4d\x93\x57\x86\xaa\x47\x09\xec\x3e\x64", " HDG", 18}, // eth / Hedge Crypto + { 1, "\xe9\xff\x07\x80\x9c\xcf\xf0\x5d\xae\x74\x99\x0e\x25\x83\x1d\x0b\xc5\xcb\xe5\x75", " Hdp", 18}, // eth / HEdpAY + { 1, "\xba\x21\x84\x52\x0a\x1c\xc4\x9a\x61\x59\xc5\x7e\x61\xe1\x84\x4e\x08\x56\x15\xb6", " HGT", 8}, // eth / HGT + { 1, "\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44", " HIG", 18}, // eth / ethereumhigh + { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, // eth / HKG + { 1, "\x88\xac\x94\xd5\xd1\x75\x13\x03\x47\xfc\x95\xe1\x09\xd7\x7a\xc0\x9d\xbf\x5a\xb7", " HKY", 18}, // eth / Hicky + { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, // eth / HMQ + { 1, "\xb4\x5d\x7b\xc4\xce\xbc\xab\x98\xad\x09\xba\xbd\xf8\xc8\x18\xb2\x29\x2b\x67\x2c", " HODL", 18}, // eth / HODLCoin + { 1, "\x5b\x07\x51\x71\x3b\x25\x27\xd7\xf0\x02\xc0\xc4\xe2\xa3\x7e\x12\x19\x61\x0a\x6b", " HORSE", 18}, // eth / HORSE + { 1, "\x6c\x6e\xe5\xe3\x1d\x82\x8d\xe2\x41\x28\x2b\x96\x06\xc8\xe9\x8e\xa4\x85\x26\xe2", " HOT", 18}, // eth / HoloToken + { 1, "\x9a\xf8\x39\x68\x7f\x6c\x94\x54\x2a\xc5\xec\xe2\xe3\x17\xda\xae\x35\x54\x93\xa1", " HOT", 18}, // eth / Hydro Protocol + { 1, "\x55\x4c\x20\xb7\xc4\x86\xbe\xee\x43\x92\x77\xb4\x54\x0a\x43\x45\x66\xdc\x4c\x02", " HST", 18}, // eth / HST + { 1, "\xc0\xeb\x85\x28\x5d\x83\x21\x7c\xd7\xc8\x91\x70\x2b\xcb\xc0\xfc\x40\x1e\x2d\x9d", " HVN", 8}, // eth / Hive Project + { 1, "\xeb\xbd\xf3\x02\xc9\x40\xc6\xbf\xd4\x9c\x6b\x16\x5f\x45\x7f\xdb\x32\x46\x49\xbc", " HYDRO", 18}, // eth / Hydro + { 1, "\xc1\xe2\x09\x7d\x78\x8d\x33\x70\x1b\xa3\xcc\x27\x73\xbf\x67\x15\x5e\xc9\x3f\xc4", " IAD", 18}, // eth / IADOWR Coin + { 1, "\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", " ICE", 18}, // eth / ICE + { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, // eth / ICN + { 1, "\xa3\x3e\x72\x9b\xf4\xfd\xeb\x86\x8b\x53\x4e\x1f\x20\x52\x34\x63\xd9\xc4\x6b\xee", " ICO", 10}, // eth / ICO + { 1, "\x01\x4b\x50\x46\x65\x90\x34\x0d\x41\x30\x7c\xc5\x4d\xce\xe9\x90\xc8\xd5\x8a\xa8", " ICOS", 6}, // eth / ICOS + { 1, "\xb5\xa5\xf2\x26\x94\x35\x2c\x15\xb0\x03\x23\x84\x4a\xd5\x45\xab\xb2\xb1\x10\x28", " ICX", 18}, // eth / ICON + { 1, "\x81\x4c\xaf\xd4\x78\x2d\x2e\x72\x81\x70\xfd\xa6\x82\x57\x98\x3f\x03\x32\x1c\x58", " IDEA", 0}, // eth / IDEA Token + { 1, "\x76\x54\x91\x5a\x1b\x82\xd6\xd2\xd0\xaf\xc3\x7c\x52\xaf\x55\x6e\xa8\x98\x3c\x7e", " IFT", 18}, // eth / InvestFeed + { 1, "\x16\x66\x2f\x73\xdf\x3e\x79\xe5\x4c\x6c\x59\x38\xb4\x31\x3f\x92\xc5\x24\xc1\x20", " IIC", 18}, // eth / IIC + { 1, "\x88\xae\x96\x84\x5e\x15\x75\x58\xef\x59\xe9\xff\x90\xe7\x66\xe2\x2e\x48\x03\x90", " IKB", 0}, // eth / IKB + { 1, "\xe3\x83\x1c\x5a\x98\x2b\x27\x9a\x19\x84\x56\xd5\x77\xcf\xb9\x04\x24\xcb\x63\x40", " IMC", 6}, // eth / Immune Coin + { 1, "\x22\xe5\xf6\x2d\x0f\xa1\x99\x74\x74\x9f\xaa\x19\x4e\x3d\x3e\xf6\xd8\x9c\x08\xd7", " IMT", 0}, // eth / IMT + { 1, "\xf8\xe3\x86\xed\xa8\x57\x48\x4f\x5a\x12\xe4\xb5\xda\xa9\x98\x4e\x06\xe7\x37\x05", " IND", 18}, // eth / Indorse + { 1, "\x48\xe5\x41\x3b\x73\xad\xd2\x43\x4e\x47\x50\x4e\x2a\x22\xd1\x49\x40\xdb\xfe\x78", " INRM", 3}, // eth / Integrated Money + { 1, "\x5b\x2e\x4a\x70\x0d\xfb\xc5\x60\x06\x1e\x95\x7e\xde\xc8\xf6\xee\xeb\x74\xa3\x20", " INS", 10}, // eth / INS + { 1, "\xc7\x2f\xe8\xe3\xdd\x5b\xef\x0f\x9f\x31\xf2\x59\x39\x9f\x30\x12\x72\xef\x2a\x2d", " INSTAR", 18}, // eth / Insights Network + { 1, "\xa8\x00\x6c\x4c\xa5\x6f\x24\xd6\x83\x67\x27\xd1\x06\x34\x93\x20\xdb\x7f\xef\x82", " INXT", 8}, // eth / Internxt + { 1, "\xfa\x1a\x85\x6c\xfa\x34\x09\xcf\xa1\x45\xfa\x4e\x20\xeb\x27\x0d\xf3\xeb\x21\xab", " IOST", 18}, // eth / IOSToken + { 1, "\xc3\x4b\x21\xf6\xf8\xe5\x1c\xc9\x65\xc2\x39\x3b\x3c\xcf\xa3\xb8\x2b\xeb\x24\x03", " IoT", 6}, // eth / IoTコイン + { 1, "\x6f\xb3\xe0\xa2\x17\x40\x7e\xff\xf7\xca\x06\x2d\x46\xc2\x6e\x5d\x60\xa1\x4d\x69", " IOTX", 18}, // eth / IoTeX Network + { 1, "\x64\xcd\xf8\x19\xd3\xe7\x5a\xc8\xec\x21\x7b\x34\x96\xd7\xce\x16\x7b\xe4\x2e\x80", " IPL", 18}, // eth / InsurePal token + { 1, "\x00\x1f\x0a\xa5\xda\x15\x58\x5e\x5b\x23\x05\xdb\xab\x2b\xac\x42\x5e\xa7\x10\x07", " IPSX", 18}, // eth / IPSX + { 1, "\x5e\x6b\x6d\x9a\xba\xd9\x09\x3f\xdc\x86\x1e\xa1\x60\x0e\xba\x1b\x35\x5c\xd9\x40", " ITC", 18}, // eth / IoT Chain + { 1, "\x0a\xef\x06\xdc\xcc\xc5\x31\xe5\x81\xf0\x44\x00\x59\xe6\xff\xcc\x20\x60\x39\xee", " ITT", 8}, // eth / ITT Token + { 1, "\xfc\xa4\x79\x62\xd4\x5a\xdf\xdf\xd1\xab\x2d\x97\x23\x15\xdb\x4c\xe7\xcc\xf0\x94", " IXT", 8}, // eth / InsureX + { 1, "\x0d\x26\x2e\x5d\xc4\xa0\x6a\x0f\x1c\x90\xce\x79\xc7\xa6\x0c\x09\xdf\xc8\x84\xe4", " J8T", 8}, // eth / J8T Token + { 1, "\x0a\xaf\x56\x1e\xff\x5b\xd9\xc8\xf9\x11\x61\x69\x33\xf8\x41\x66\xa1\x7c\xfe\x0c", " JBX", 0}, // eth / JBX + { 1, "\x88\x4e\x39\x02\xc4\xd5\xcf\xa8\x6d\xe4\xac\xe7\xa9\x6a\xa9\x1e\xbc\x25\xc0\xff", " JBX", 18}, // eth / JBOX + { 1, "\x87\x27\xc1\x12\xc7\x12\xc4\xa0\x33\x71\xac\x87\xa7\x4d\xd6\xab\x10\x4a\xf7\x68", " JET", 18}, // eth / JET + { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JetCoins", 18}, // eth / JetCoins + { 1, "\xa5\xfd\x1a\x79\x1c\x4d\xfc\xaa\xcc\x96\x3d\x4f\x73\xc6\xae\x58\x24\x14\x9e\xa7", " JNT", 18}, // eth / JNT + { 1, "\xdd\xe1\x2a\x12\xa6\xf6\x71\x56\xe0\xda\x67\x2b\xe0\x5c\x37\x4e\x1b\x0a\x3e\x57", " JOY", 6}, // eth / JOYSO + { 1, "\x0d\x6d\xd9\xf6\x8d\x24\xec\x1d\x5f\xe2\x17\x4f\x3e\xc8\xda\xb5\x2b\x52\xba\xf5", " KC", 18}, // eth / KMCC + { 1, "\x72\xd3\x2a\xc1\xc5\xe6\x6b\xfc\x5b\x08\x80\x62\x71\xf8\xee\xf9\x15\x54\x51\x64", " KEE", 0}, // eth / CryptoKEE + { 1, "\x4c\xc1\x93\x56\xf2\xd3\x73\x38\xb9\x80\x2a\xa8\xe8\xfc\x58\xb0\x37\x32\x96\xe7", " KEY", 18}, // eth / SelfKey + { 1, "\x4c\xd9\x88\xaf\xba\xd3\x72\x89\xba\xaf\x53\xc1\x3e\x98\xe2\xbd\x46\xaa\xea\x8c", " KEY", 18}, // eth / BihuKey + { 1, "\x27\x69\x5e\x09\x14\x9a\xdc\x73\x8a\x97\x8e\x9a\x67\x8f\x99\xe4\xc3\x9e\x9e\xb9", " KICK", 8}, // eth / KICK + { 1, "\x81\x8f\xc6\xc2\xec\x59\x86\xbc\x6e\x2c\xbf\x00\x93\x9d\x90\x55\x6a\xb1\x2c\xe5", " KIN", 18}, // eth / Kin Foundation + { 1, "\xdd\x97\x4d\x5c\x2e\x29\x28\xde\xa5\xf7\x1b\x98\x25\xb8\xb6\x46\x68\x6b\xd2\x00", " KNC", 18}, // eth / Kyber Network + { 1, "\xb5\xc3\x3f\x96\x5c\x88\x99\xd2\x55\xc3\x4c\xdd\x2a\x3e\xfa\x8a\xbc\xbb\x3d\xea", " KPR", 18}, // eth / KPRCoin + { 1, "\x46\x4e\xbe\x77\xc2\x93\xe4\x73\xb4\x8c\xfe\x96\xdd\xcf\x88\xfc\xf7\xbf\xda\xc0", " KRL", 18}, // eth / Kryll + { 1, "\x95\x41\xfd\x8b\x9b\x5f\xa9\x73\x81\x78\x37\x83\xce\xbf\x2f\x5f\xa7\x93\xc2\x62", " KZN", 8}, // eth / KaizenCoin + { 1, "\xe5\x03\x65\xf5\xd6\x79\xcb\x98\xa1\xdd\x62\xd6\xf6\xe5\x8e\x59\x32\x1b\xcd\xdf", " LA", 18}, // eth / LATOKEN + { 1, "\xfd\x10\x7b\x47\x3a\xb9\x0e\x8f\xbd\x89\x87\x21\x44\xa3\xdc\x92\xc4\x0f\xa8\xc9", " LALA", 18}, // eth / LALA World Token + { 1, "\x51\x02\x79\x1c\xa0\x2f\xc3\x59\x53\x98\x40\x0b\xfe\x0e\x33\xd7\xb6\xc8\x22\x67", " LDC", 18}, // eth / LEADCOIN + { 1, "\xd6\xe3\x54\xf0\x73\x19\xe2\x47\x44\x91\xd8\xc7\xc7\x12\x13\x7b\xee\x68\x62\xa2", " LEMO", 0}, // eth / Lemo + { 1, "\xb5\xae\x84\x8e\xdb\x29\x6c\x21\x25\x9b\x74\x67\x33\x14\x67\xd2\x64\x7e\xec\xdf", " LEMO", 18}, // eth / Lemo + { 1, "\x80\xfb\x78\x4b\x7e\xd6\x67\x30\xe8\xb1\xdb\xd9\x82\x0a\xfd\x29\x93\x1a\xab\x03", " LEND", 18}, // eth / EHTLend + { 1, "\xc7\x98\xcd\x1c\x49\xdb\x0e\x29\x73\x12\xe4\xc6\x82\x75\x26\x68\xce\x1d\xb2\xad", " LFR", 5}, // eth / LifeRun Coin + { 1, "\x12\x3a\xb1\x95\xdd\x38\xb1\xb4\x05\x10\xd4\x67\xa6\xa3\x59\xb2\x01\xaf\x05\x6f", " LGO", 8}, // eth / LGO + { 1, "\x2e\xb8\x6e\x8f\xc5\x20\xe0\xf6\xbb\x5d\x9a\xf0\x8f\x92\x4f\xe7\x05\x58\xab\x89", " LGR", 8}, // eth / Logarithm + { 1, "\xeb\x99\x51\x02\x16\x98\xb4\x2e\x43\x99\xf9\xcb\xb6\x26\x7a\xa3\x5f\x82\xd5\x9d", " LIF", 18}, // eth / LIF + { 1, "\xff\x18\xdb\xc4\x87\xb4\xc2\xe3\x22\x2d\x11\x59\x52\xba\xbf\xda\x8b\xa5\x2f\x5f", " LIFE", 18}, // eth / LIFE + { 1, "\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", " LINK (Chainlink)", 18}, // eth / LINK Chainlink + { 1, "\xe2\xe6\xd4\xbe\x08\x6c\x69\x38\xb5\x3b\x22\x14\x48\x55\xee\xf6\x74\x28\x16\x39", " LINK Platform", 18}, // eth / Link Platform + { 1, "\x24\xa7\x7c\x1f\x17\xc5\x47\x10\x5e\x14\x81\x3e\x51\x7b\xe0\x6b\x00\x40\xaa\x76", " LIVE", 18}, // eth / LIVE Token + { 1, "\x63\xe6\x34\x33\x0a\x20\x15\x0d\xbb\x61\xb1\x56\x48\xbc\x73\x85\x5d\x6c\xcf\x07", " LNC", 18}, // eth / Lancer Token + { 1, "\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66", " LNC-Linker Coin", 18}, // eth / Linker Coin + { 1, "\x09\x47\xb0\xe6\xd8\x21\x37\x88\x05\xc9\x59\x82\x91\x38\x5c\xe7\xc7\x91\xa6\xb2", " LND", 18}, // eth / Lendingblock + { 1, "\x5e\x33\x46\x44\x40\x10\x13\x53\x22\x26\x8a\x46\x30\xd2\xed\x5f\x8d\x09\x44\x6c", " LOC", 18}, // eth / LockChain + { 1, "\x9c\x23\xd6\x7a\xea\x7b\x95\xd8\x09\x42\xe3\x83\x6b\xcd\xf7\xe7\x08\xa7\x47\xc2", " LOCI", 18}, // eth / LOCIcoin + { 1, "\xc6\x45\x00\xdd\x7b\x0f\x17\x94\x80\x7e\x67\x80\x2f\x8a\xbb\xf5\xf8\xff\xb0\x54", " LOCUS", 18}, // eth / Locus Chain + { 1, "\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", " LOK", 18}, // eth / LOK + { 1, "\xa4\xe8\xc3\xec\x45\x61\x07\xea\x67\xd3\x07\x5b\xf9\xe3\xdf\x3a\x75\x82\x3d\xb0", " LOOM", 18}, // eth / LOOM + { 1, "\x58\xb6\xa8\xa3\x30\x23\x69\xda\xec\x38\x33\x34\x67\x24\x04\xee\x73\x3a\xb2\x39", " LPT", 18}, // eth / Livepeer Token + { 1, "\xef\x68\xe7\xc6\x94\xf4\x0c\x82\x02\x82\x1e\xdf\x52\x5d\xe3\x78\x24\x58\x63\x9f", " LRC", 18}, // eth / LRC + { 1, "\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19", " LUC", 18}, // eth / LUCToken + { 1, "\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53", " LUCK", 0}, // eth / LUCK + { 1, "\xa8\x9b\x59\x34\x86\x34\x47\xf6\xe4\xfc\x53\xb3\x15\xa9\x3e\x87\x3b\xda\x69\xa3", " LUM", 18}, // eth / Lumino Coin + { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, // eth / LUN + { 1, "\xdd\x41\xfb\xd1\xae\x95\xc5\xd9\xb1\x98\x17\x4a\x28\xe0\x4b\xe6\xb3\xd1\xaa\x27", " LYS", 8}, // eth / Lightyears + { 1, "\x3f\x4b\x72\x66\x68\xda\x46\xf5\xe0\xe7\x5a\xa5\xd4\x78\xac\xec\x9f\x38\x21\x0f", " M-ETH", 18}, // eth / M-ETH + { 1, "\x5b\x09\xa0\x37\x1c\x1d\xa4\x4a\x8e\x24\xd3\x6b\xf5\xde\xb1\x14\x1a\x84\xd8\x75", " MAD", 18}, // eth / MAD + { 1, "\xe2\x5b\xce\xc5\xd3\x80\x1c\xe3\xa7\x94\x07\x9b\xf9\x4a\xdf\x1b\x8c\xcd\x80\x2d", " MAN", 18}, // eth / MAN + { 1, "\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", " MANA", 18}, // eth / Decentraland MANA + { 1, "\xfd\xcc\x07\xab\x60\x66\x0d\xe5\x33\xb5\xad\x26\xe1\x45\x7b\x56\x5a\x9d\x59\xbd", " MART", 18}, // eth / Martcoin + { 1, "\x38\x64\x67\xf1\xf3\xdd\xbe\x83\x24\x48\x65\x04\x18\x31\x1a\x47\x9e\xec\xfc\x57", " MBRS", 0}, // eth / Embers + { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, // eth / MCAP + { 1, "\x13\x8a\x87\x52\x09\x3f\x4f\x9a\x79\xaa\xed\xf4\x8d\x4b\x92\x48\xfa\xb9\x3c\x9c", " MCI", 18}, // eth / Musiconomi + { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, // eth / MCO + { 1, "\x51\xdb\x5a\xd3\x5c\x67\x1a\x87\x20\x7d\x88\xfc\x11\xd5\x93\xac\x0c\x84\x15\xbd", " MDA", 18}, // eth / MDA + { 1, "\x01\xf2\xac\xf2\x91\x48\x60\x33\x1c\x1c\xb1\xa9\xac\xec\xda\x74\x75\xe0\x6a\xf8", " MESH", 18}, // eth / Meshbox + { 1, "\x5b\x8d\x43\xff\xde\x4a\x29\x82\xb9\xa5\x38\x7c\xdf\x21\xd5\x4e\xad\x64\xac\x8d", " MEST", 18}, // eth / Monaco Estate + { 1, "\x67\x10\xc6\x34\x32\xa2\xde\x02\x95\x4f\xc0\xf8\x51\xdb\x07\x14\x6a\x6c\x03\x12", " MFG", 18}, // eth / SyncFab Smart Manufacturing Blockchain + { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, // eth / MGO + { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, // eth / MIT + { 1, "\xad\x8d\xd4\xc7\x25\xde\x1d\x31\xb9\xe8\xf8\xd1\x46\x08\x9e\x9d\xc6\x88\x20\x93", " MIT (Mychatcoin)", 6}, // eth / Mychatcoin + { 1, "\x9f\x8f\x72\xaa\x93\x04\xc8\xb5\x93\xd5\x55\xf1\x2e\xf6\x58\x9c\xc3\xa5\x79\xa2", " MKR", 18}, // eth / MakerDAO + { 1, "\x79\x39\x88\x2b\x54\xfc\xf0\xbc\xae\x6b\x53\xde\xc3\x9a\xd6\xe8\x06\x17\x64\x42", " MKT", 8}, // eth / Mikado + { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, // eth / Melonport + { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, // eth / MNE + { 1, "\xa9\x87\x7b\x1e\x05\xd0\x35\x89\x91\x31\xdb\xd1\xe4\x03\x82\x51\x66\xd0\x9f\x92", " MNT", 18}, // eth / Media Network Token + { 1, "\x83\xce\xe9\xe0\x86\xa7\x7e\x49\x2e\xe0\xbb\x93\xc2\xb0\x43\x7a\xd6\xfd\xec\xcc", " MNTP", 18}, // eth / Goldmint MNT Prelaunch Token + { 1, "\x95\x7c\x30\xab\x04\x26\xe0\xc9\x3c\xd8\x24\x1e\x2c\x60\x39\x2d\x08\xc6\xac\x8e", " MOD", 0}, // eth / Modum + { 1, "\x82\x12\x5a\xfe\x01\x81\x9d\xff\x15\x35\xd0\xd6\x27\x6d\x57\x04\x52\x91\xb6\xc0", " MRL", 18}, // eth / Marcelo + { 1, "\x21\xf0\xf0\xfd\x31\x41\xee\x9e\x11\xb3\xd7\xf1\x3a\x10\x28\xcd\x51\x5f\x45\x9c", " MRP", 18}, // eth / MoneyRebel Token + { 1, "\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", " MRV", 18}, // eth / MRV + { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, // eth / Mothership + { 1, "\x90\x5e\x33\x7c\x6c\x86\x45\x26\x3d\x35\x21\x20\x5a\xa3\x7b\xf4\xd0\x34\xe7\x45", " MTC", 18}, // eth / Medical Token Currency + { 1, "\xaf\x4d\xce\x16\xda\x28\x77\xf8\xc9\xe0\x05\x44\xc9\x3b\x62\xac\x40\x63\x1f\x16", " MTH", 5}, // eth / Monetha + { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, // eth / MetalPay + { 1, "\x41\xdb\xec\xc1\xcd\xc5\x51\x7c\x6f\x76\xf6\xa6\xe8\x36\xad\xbe\xe2\x75\x4d\xe3", " MTN", 18}, // eth / MedToken + { 1, "\x7f\xc4\x08\x01\x11\x65\x76\x0e\xe3\x1b\xe2\xbf\x20\xda\xf4\x50\x35\x66\x92\xaf", " MTR", 8}, // eth / Mitrav + { 1, "\x1e\x49\xff\x77\xc3\x55\xa3\xe3\x8d\x66\x51\xce\x84\x04\xaf\x0e\x48\xc5\x39\x5f", " MTRc", 18}, // eth / MTRCToken + { 1, "\x0a\xf4\x4e\x27\x84\x63\x72\x18\xdd\x1d\x32\xa3\x22\xd4\x4e\x60\x3a\x8f\x0c\x6a", " MTX", 18}, // eth / MTX + { 1, "\x51\x56\x69\xd3\x08\xf8\x87\xfd\x83\xa4\x71\xc7\x76\x4f\x5d\x08\x48\x86\xd3\x4d", " MUXE", 18}, // eth / MUXE + { 1, "\x8a\x77\xe4\x09\x36\xbb\xc2\x7e\x80\xe9\xa3\xf5\x26\x36\x8c\x96\x78\x69\xc8\x6d", " MVP", 18}, // eth / Merculet + { 1, "\x64\x25\xc6\xbe\x90\x2d\x69\x2a\xe2\xdb\x75\x2b\x3c\x26\x8a\xfa\xdb\x09\x9d\x3b", " MWAT", 18}, // eth / RED MWAT + { 1, "\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", " MYD", 16}, // eth / MYD + { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, // eth / Mysterium + { 1, "\x8d\x80\xde\x8a\x78\x19\x83\x96\x32\x9d\xfa\x76\x9a\xd5\x4d\x24\xbf\x90\xe7\xaa", " NAC", 18}, // eth / Nami ICO + { 1, "\xff\xe0\x2e\xe4\xc6\x9e\xdf\x1b\x34\x0f\xca\xd6\x4f\xbd\x6b\x37\xa7\xb9\xe2\x65", " NANJ", 8}, // eth / NANJCOIN + { 1, "\x58\x80\x47\x36\x5d\xf5\xba\x58\x9f\x92\x36\x04\xaa\xc2\x3d\x67\x35\x55\xc6\x23", " NAVI", 18}, // eth / NaviToken + { 1, "\x17\xf8\xaf\xb6\x3d\xfc\xdc\xc9\x0e\xbe\x6e\x84\xf0\x60\xcc\x30\x6a\x98\x25\x7d", " NBAI", 18}, // eth / NebulaAiToken + { 1, "\x80\x98\x26\xcc\xea\xb6\x8c\x38\x77\x26\xaf\x96\x27\x13\xb6\x4c\xb5\xcb\x3c\xca", " nCash", 18}, // eth / NucleusVision + { 1, "\x9e\x46\xa3\x8f\x5d\xaa\xbe\x86\x83\xe1\x07\x93\xb0\x67\x49\xee\xf7\xd7\x33\xd1", " NCT", 18}, // eth / Nectar + { 1, "\xa5\x4d\xdc\x7b\x3c\xce\x7f\xc8\xb1\xe3\xfa\x02\x56\xd0\xdb\x80\xd2\xc1\x09\x70", " NDC", 18}, // eth / Neverdie + { 1, "\xcc\x80\xc0\x51\x05\x7b\x77\x4c\xd7\x50\x67\xdc\x48\xf8\x98\x7c\x4e\xb9\x7a\x5e", " NEC", 18}, // eth / Ethfinex Nectar Token + { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, // eth / NIMIQ + { 1, "\xa8\x23\xe6\x72\x20\x06\xaf\xe9\x9e\x91\xc3\x0f\xf5\x29\x50\x52\xfe\x6b\x8e\x32", " NEU", 18}, // eth / NEU Fund + { 1, "\x72\xdd\x4b\x6b\xd8\x52\xa3\xaa\x17\x2b\xe4\xd6\xc5\xa6\xdb\xec\x58\x8c\xf1\x31", " NGC", 18}, // eth / NAGA Coin + { 1, "\xe2\x65\x17\xa9\x96\x72\x99\x45\x3d\x3f\x1b\x48\xaa\x00\x5e\x61\x27\xe6\x72\x10", " NIMFA", 18}, // eth / Ninfa Money + { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, // eth / NMR + { 1, "\x64\x3b\x68\x70\xbe\xab\xee\x94\x1b\x92\x60\xa0\xa8\x78\xbc\xf4\xa6\x1f\xb0\xf1", " NONE", 0}, // eth / None + { 1, "\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c", " NOX", 18}, // eth / NOX + { 1, "\x4c\xe6\xb3\x62\xbc\x77\xa2\x49\x66\xdd\xa9\x07\x8f\x9c\xef\x81\xb3\xb8\x86\xa7", " NPER", 18}, // eth / NPER + { 1, "\xa1\x5c\x7e\xbe\x1f\x07\xca\xf6\xbf\xf0\x97\xd8\xa5\x89\xfb\x8a\xc4\x9a\xe5\xb3", " NPXS", 18}, // eth / Pundi X Token + { 1, "\xb9\x13\x18\xf3\x5b\xdb\x26\x2e\x94\x23\xbc\x7c\x7c\x2a\x3a\x93\xdd\x93\xc9\x2c", " NULS", 18}, // eth / NULS + { 1, "\x57\xab\x1e\x02\xfe\xe2\x37\x74\x58\x0c\x11\x97\x40\x12\x9e\xac\x70\x81\xe9\xd3", " nUSD", 18}, // eth / Havven-Backed USD Nomins (nUSD) + { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, // eth / Nexium + { 1, "\x76\x27\xde\x4b\x93\x26\x3a\x6a\x75\x70\xb8\xda\xfa\x64\xba\xe8\x12\xe5\xc3\x94", " NXX", 8}, // eth / NXX + { 1, "\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", " NXX OLD", 8}, // eth / NXX OLD + { 1, "\x5e\x88\x8b\x83\xb7\x28\x7e\xed\x4f\xb7\xda\x7b\x7d\x0a\x0d\x4c\x73\x5d\x94\xb3", " OAK", 18}, // eth / OAK + { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, // eth / OAX + { 1, "\x02\x35\xfe\x62\x4e\x04\x4a\x05\xee\xd7\xa4\x3e\x16\xe3\x08\x3b\xc8\xa4\x28\x7a", " OCC", 18}, // eth / Original Crypto Coin + { 1, "\x6f\x53\x9a\x94\x56\xa5\xbc\xb6\x33\x4a\x1a\x41\x20\x7c\x37\x88\xf5\x82\x52\x07", " OHNI", 18}, // eth / Ohni + { 1, "\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", " OHNI", 0}, // eth / OHNI + { 1, "\xbe\xef\x54\x6a\xc8\xa4\xe0\xa8\x0d\xc1\xe2\xd6\x96\x96\x8e\xf5\x41\x38\xf1\xd4", " OJX", 18}, // eth / Ojooo Coin + { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " OLD_MKR", 18}, // eth / MakerDAO + { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, // eth / OMG + { 1, "\xb2\x3b\xe7\x35\x73\xbc\x7e\x03\xdb\x6e\x5d\xfc\x62\x40\x53\x68\x71\x6d\x28\xa8", " ONEK", 18}, // eth / One K Token + { 1, "\xd3\x41\xd1\x68\x0e\xee\xe3\x25\x5b\x8c\x4c\x75\xbc\xce\x7e\xb5\x7f\x14\x4d\xae", " onG", 18}, // eth / onG + { 1, "\x69\xc4\xbb\x24\x0c\xf0\x5d\x51\xee\xab\x69\x85\xba\xb3\x55\x27\xd0\x4a\x8c\x64", " OPEN", 8}, // eth / OPEN + { 1, "\xe9\xde\x1c\x63\x07\x53\xa1\x5d\x70\x21\xcc\x56\x34\x29\xc2\x1d\x48\x87\x50\x6f", " OPEN", 8}, // eth / OPEN + { 1, "\x43\x55\xfc\x16\x0f\x74\x32\x8f\x9b\x38\x3d\xf2\xec\x58\x9b\xb3\xdf\xd8\x2b\xa0", " OPT", 18}, // eth / Opus Foundation + { 1, "\xff\x56\xcc\x6b\x1e\x6d\xed\x34\x7a\xa0\xb7\x67\x6c\x85\xab\x0b\x3d\x08\xb0\xfa", " ORBS", 18}, // eth / Orbs + { 1, "\x2c\x4e\x8f\x2d\x74\x61\x13\xd0\x69\x6c\xe8\x9b\x35\xf0\xd8\xbf\x88\xe0\xae\xca", " OST", 18}, // eth / Simple Token 'OST' + { 1, "\x65\xa1\x50\x14\x96\x4f\x21\x02\xff\x58\x64\x7e\x16\xa1\x6a\x6b\x9e\x14\xbc\xf6", " Ox Fina", 3}, // eth / Ox Fina + { 1, "\xfe\xda\xe5\x64\x26\x68\xf8\x63\x6a\x11\x98\x7f\xf3\x86\xbf\xd2\x15\xf9\x42\xee", " PAL", 18}, // eth / PolicyPal Network + { 1, "\xea\x5f\x88\xe5\x4d\x98\x2c\xbb\x0c\x44\x1c\xde\x4e\x79\xbc\x30\x5e\x5b\x43\xbc", " PARETO", 18}, // eth / PARETO + { 1, "\xbb\x1f\xa4\xfd\xeb\x34\x59\x73\x3b\xf6\x7e\xbc\x6f\x89\x30\x03\xfa\x97\x6a\x82", " PAT", 18}, // eth / Pangea Arbitration Token + { 1, "\x69\x44\x04\x59\x5e\x30\x75\xa9\x42\x39\x7f\x46\x6a\xac\xd4\x62\xff\x1a\x7b\xd0", " PATENTS", 18}, // eth / PATENTS + { 1, "\xf8\x13\xf3\x90\x2b\xbc\x00\xa6\xdc\xe3\x78\x63\x4d\x3b\x79\xd8\x4f\x98\x03\xd7", " PATH", 18}, // eth / PATH + { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, // eth / TenX + { 1, "\x55\x64\x8d\xe1\x98\x36\x33\x85\x49\x13\x0b\x1a\xf5\x87\xf1\x6b\xea\x46\xf6\x6b", " PBL", 18}, // eth / PBL + { 1, "\xf4\xc0\x7b\x18\x65\xbc\x32\x6a\x3c\x01\x33\x94\x92\xca\x75\x38\xfd\x03\x8c\xc0", " PBT", 4}, // eth / Primalbase Token (PBT) + { 1, "\xfc\xac\x7a\x75\x15\xe9\xa9\xd7\x61\x9f\xa7\x7a\x1f\xa7\x38\x11\x1f\x66\x72\x7e", " PCH", 18}, // eth / PITCH + { 1, "\x36\x18\x51\x6f\x45\xcd\x3c\x91\x3f\x81\xf9\x98\x7a\xf4\x10\x77\x93\x2b\xc4\x0d", " PCL", 8}, // eth / Peculium + { 1, "\x53\x14\x8b\xb4\x55\x17\x07\xed\xf5\x1a\x1e\x8d\x7a\x93\x69\x8d\x18\x93\x12\x25", " PCLOLD", 8}, // eth / PeculiumOLD + { 1, "\x58\x84\x96\x9e\xc0\x48\x05\x56\xe1\x1d\x11\x99\x80\x13\x6a\x4c\x17\xed\xde\xd1", " PET", 18}, // eth / PETHEREUM + { 1, "\xec\x18\xf8\x98\xb4\x07\x6a\x3e\x18\xf1\x08\x9d\x33\x37\x6c\xc3\x80\xbd\xe6\x1d", " PETRO", 18}, // eth / PETRO + { 1, "\x55\xc2\xa0\xc1\x71\xd9\x20\x84\x35\x60\x59\x4d\xe3\xd6\xee\xcc\x09\xef\xc0\x98", " PEXT", 4}, // eth / PEX-Token + { 1, "\xe6\x45\x09\xf0\xbf\x07\xce\x2d\x29\xa7\xef\x19\xa8\xa9\xbc\x06\x54\x77\xc1\xb4", " PIPL", 8}, // eth / PIPL Coin + { 1, "\x8e\xff\xd4\x94\xeb\x69\x8c\xc3\x99\xaf\x62\x31\xfc\xcd\x39\xe0\x8f\xd2\x0b\x15", " PIX", 0}, // eth / PIX + { 1, "\x59\x41\x6a\x25\x62\x8a\x76\xb4\x73\x0e\xc5\x14\x86\x11\x4c\x32\xe0\xb5\x82\xa1", " PLASMA", 6}, // eth / PLASMA + { 1, "\xe4\x77\x29\x2f\x1b\x32\x68\x68\x7a\x29\x37\x61\x16\xb0\xed\x27\xa9\xc7\x61\x70", " PLAY", 18}, // eth / HeroCoin + { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, // eth / Polybius + { 1, "\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", " PLR", 18}, // eth / Pillar Project + { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, // eth / Plutus + { 1, "\x0e\x09\x89\xb1\xf9\xb8\xa3\x89\x83\xc2\xba\x80\x53\x26\x9c\xa6\x2e\xc9\xb1\x95", " POE", 8}, // eth / Po.et Tokens + { 1, "\x43\xf6\xa1\xbe\x99\x2d\xee\x40\x87\x21\x74\x84\x90\x77\x2b\x15\x14\x3c\xe0\xa7", " POIN", 0}, // eth / Potatoin + { 1, "\x99\x92\xec\x3c\xf6\xa5\x5b\x00\x97\x8c\xdd\xf2\xb2\x7b\xc6\x88\x2d\x88\xd1\xec", " POLY", 18}, // eth / Polymath Network + { 1, "\x77\x9b\x7b\x71\x3c\x86\xe3\xe6\x77\x4f\x50\x40\xd9\xcc\xc2\xd4\x3a\xd3\x75\xf8", " POOL", 8}, // eth / Stake Pool + { 1, "\xee\x60\x9f\xe2\x92\x12\x8c\xad\x03\xb7\x86\xdb\xb9\xbc\x26\x34\xcc\xdb\xe7\xfc", " POS", 18}, // eth / PoSToken + { 1, "\x59\x58\x32\xf8\xfc\x6b\xf5\x9c\x85\xc5\x27\xfe\xc3\x74\x0a\x1b\x7a\x36\x12\x69", " POWR", 6}, // eth / PowerLedger + { 1, "\xc4\x22\x09\xac\xcc\x14\x02\x9c\x10\x12\xfb\x56\x80\xd9\x5f\xbd\x60\x36\xe2\xa0", " PPP", 18}, // eth / PayPie + { 1, "\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", " PPT", 8}, // eth / Populous + { 1, "\x88\xa3\xe4\xf3\x5d\x64\xaa\xd4\x1a\x6d\x40\x30\xac\x9a\xfe\x43\x56\xcb\x84\xfa", " PRE", 18}, // eth / Presearch + { 1, "\x77\x28\xdf\xef\x5a\xbd\x46\x86\x69\xeb\x7f\x9b\x48\xa7\xf7\x0a\x50\x1e\xd2\x9d", " PRG", 6}, // eth / PRG + { 1, "\x18\x44\xb2\x15\x93\x26\x26\x68\xb7\x24\x8d\x0f\x57\xa2\x20\xca\xab\xa4\x6a\xb9", " PRL", 18}, // eth / Oyster Pearl + { 1, "\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", " PRO", 8}, // eth / Propy + { 1, "\xa3\x14\x9e\x0f\xa0\x06\x1a\x90\x07\xfa\xf3\x07\x07\x4c\xdc\xd2\x90\xf0\xe2\xfd", " PRON", 8}, // eth / PronCoin + { 1, "\x76\x41\xb2\xca\x9d\xdd\x58\xad\xdf\x6e\x33\x81\xc1\xf9\x94\xaa\xc5\xf1\xa3\x2f", " PRPS", 18}, // eth / Purpose + { 1, "\xd9\x4f\x27\x78\xe2\xb3\x91\x3c\x53\x63\x7a\xe6\x06\x47\x59\x8b\xe5\x88\xc5\x70", " PRPS", 18}, // eth / Purpose + { 1, "\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b", " PRS", 18}, // eth / Persians + { 1, "\x0c\x04\xd4\xf3\x31\xda\x8d\xf7\x5f\x9e\x2e\x27\x1e\x3f\x3f\x14\x94\xc6\x6c\x36", " PRSP", 9}, // eth / PRSP + { 1, "\x66\x49\x7a\x28\x3e\x0a\x00\x7b\xa3\x97\x4e\x83\x77\x84\xc6\xae\x32\x34\x47\xde", " PT", 18}, // eth / PornToken + { 1, "\x2a\x8e\x98\xe2\x56\xf3\x22\x59\xb5\xe5\xcb\x55\xdd\x63\xc8\xe8\x91\x95\x06\x66", " PTC", 18}, // eth / ParrotCoin + { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, // eth / PTOY + { 1, "\x55\x12\xe1\xd6\xa7\xbe\x42\x4b\x43\x23\x12\x6b\x4f\x9e\x86\xd0\x23\xf9\x57\x64", " PTWO", 18}, // eth / PornTokenV2 + { 1, "\xef\x6b\x4c\xe8\xc9\xbc\x83\x74\x4f\xbc\xde\x26\x57\xb3\x2e\xc1\x87\x90\x45\x8a", " PUC", 0}, // eth / Pour Coin + { 1, "\xc1\x48\x30\xe5\x3a\xa3\x44\xe8\xc1\x46\x03\xa9\x12\x29\xa0\xb9\x25\xb0\xb2\x62", " PXT", 8}, // eth / Populous XBRL Token (PXT) + { 1, "\x61\x8e\x75\xac\x90\xb1\x2c\x60\x49\xba\x3b\x27\xf5\xd5\xf8\x65\x1b\x00\x37\xf6", " QASH", 6}, // eth / QASH + { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, // eth / QAU + { 1, "\x24\x67\xaa\x6b\x5a\x23\x51\x41\x6f\xd4\xc3\xde\xf8\x46\x2d\x84\x1f\xee\xec\xec", " QBX", 18}, // eth / qiibeeToken + { 1, "\xff\xaa\x5f\xfc\x45\x5d\x91\x31\xf8\xa2\x71\x3a\x74\x1f\xd1\x96\x03\x30\x50\x8b", " QRG", 18}, // eth / QRG + { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, // eth / QRL + { 1, "\x99\xea\x4d\xb9\xee\x77\xac\xd4\x0b\x11\x9b\xd1\xdc\x4e\x33\xe1\xc0\x70\xb8\x0d", " QSP", 18}, // eth / Quantstamp Token + { 1, "\x2c\x3c\x1f\x05\x18\x7d\xba\x7a\x5f\x2d\xd4\x7d\xca\x57\x28\x1c\x4d\x4f\x18\x3f", " QTQ", 18}, // eth / TiiQu's Q Token + { 1, "\x9a\x64\x2d\x6b\x33\x68\xdd\xc6\x62\xca\x24\x4b\xad\xf3\x2c\xda\x71\x60\x05\xbc", " QTUM", 18}, // eth / Qtum + { 1, "\x45\xed\xb5\x35\x94\x2a\x8c\x84\xd9\xf4\xb5\xd3\x7e\x1b\x25\xf9\x1e\xa4\x80\x4c", " RAO", 18}, // eth / RadioYo + { 1, "\xfc\x2c\x4d\x8f\x95\x00\x2c\x14\xed\x0a\x7a\xa6\x51\x02\xca\xc9\xe5\x95\x3b\x5e", " RBLX", 18}, // eth / Rublix + { 1, "\xf9\x70\xb8\xe3\x6e\x23\xf7\xfc\x3f\xd7\x52\xee\xa8\x6f\x8b\xe8\xd8\x33\x75\xa6", " RCN", 18}, // eth / Ripio Credit Network + { 1, "\x2a\x3a\xa9\xec\xa4\x1e\x72\x0e\xd4\x6b\x5a\x70\xd6\xc3\x7e\xfa\x47\xf7\x68\xac", " RCT", 18}, // eth / RCT + { 1, "\x25\x5a\xa6\xdf\x07\x54\x0c\xb5\xd3\xd2\x97\xf0\xd0\xd4\xd8\x4c\xb5\x2b\xc8\xe6", " RDN", 18}, // eth / Raiden Network + { 1, "\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05", " REA", 18}, // eth / Realisto + { 1, "\x5f\x53\xf7\xa8\x07\x56\x14\xb6\x99\xba\xad\x0b\xc2\xc8\x99\xf4\xba\xd8\xfb\xbf", " REBL", 18}, // eth / Rebellious + { 1, "\x76\x96\x0d\xcc\xd5\xa1\xfe\x79\x9f\x7c\x29\xbe\x9f\x19\xce\xb4\x62\x7a\xeb\x2f", " RED", 18}, // eth / Red Community Token + { 1, "\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38", " REN", 18}, // eth / Republic Token + { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, // eth / Augur + { 1, "\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a", " REQ", 18}, // eth / Request Network + { 1, "\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", " REX", 18}, // eth / REX + { 1, "\xd0\x92\x9d\x41\x19\x54\xc4\x74\x38\xdc\x1d\x87\x1d\xd6\x08\x1f\x5c\x5e\x14\x9c", " RFR", 4}, // eth / Refereum + { 1, "\xdd\x00\x72\x78\xb6\x67\xf6\xbe\xf5\x2f\xd0\xa4\xc2\x36\x04\xaa\x1f\x96\x03\x9a", " RIPT", 8}, // eth / RiptideCoin + { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, // eth / IEx.ec + { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, // eth / RLT + { 1, "\xbe\x99\xb0\x97\x09\xfc\x75\x3b\x09\xbc\xf5\x57\xa9\x92\xf6\x60\x5d\x59\x97\xb0", " RLTY", 8}, // eth / SMARTRealty + { 1, "\x4a\x42\xd2\xc5\x80\xf8\x3d\xce\x40\x4a\xca\xd1\x8d\xab\x26\xdb\x11\xa1\x75\x0e", " RLX", 18}, // eth / Relex + { 1, "\x09\x96\xbf\xb5\xd0\x57\xfa\xa2\x37\x64\x0e\x25\x06\xbe\x7b\x4f\x9c\x46\xde\x0b", " RNDR", 18}, // eth / Render Token + { 1, "\xa4\x01\x06\x13\x4c\x5b\xf4\xc4\x14\x11\x55\x4e\x6d\xb9\x9b\x95\xa1\x5e\xd9\xd8", " ROCK", 18}, // eth / Rocket Token + { 1, "\xc9\xde\x4b\x7f\x0c\x3d\x99\x1e\x96\x71\x58\xe4\xd4\xbf\xa4\xb5\x1e\xc0\xb1\x14", " ROK", 18}, // eth / Rocketchain + { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, // eth / ROUND + { 1, "\xb4\xef\xd8\x5c\x19\x99\x9d\x84\x25\x13\x04\xbd\xa9\x9e\x90\xb9\x23\x00\xbd\x93", " RPL", 18}, // eth / Rocket Pool + { 1, "\x54\xb2\x93\x22\x60\x00\xcc\xbf\xc0\x4d\xf9\x02\xee\xc5\x67\xcb\x4c\x35\xa9\x03", " RTN", 18}, // eth / RiderToken + { 1, "\x41\xf6\x15\xe2\x4f\xab\xd2\xb0\x97\xa3\x20\xe9\xe6\xc1\xf4\x48\xcb\x40\x52\x1c", " RVL", 18}, // eth / RVL + { 1, "\x3d\x1b\xa9\xbe\x9f\x66\xb8\xee\x10\x19\x11\xbc\x36\xd3\xfb\x56\x2e\xac\x22\x44", " RVT", 18}, // eth / Rivetz + { 1, "\x1e\xc8\xfe\x51\xa9\xb6\xa3\xa6\xc4\x27\xd1\x7d\x9e\xcc\x30\x60\xfb\xc4\xa4\x5c", " S-A-PAT", 18}, // eth / S-A-PAT + { 1, "\x3e\xb9\x1d\x23\x7e\x49\x1e\x0d\xee\x85\x82\xc4\x02\xd8\x5c\xb4\x40\xfb\x6b\x54", " S-ETH", 18}, // eth / S-ETH + { 1, "\x41\x56\xd3\x34\x2d\x5c\x38\x5a\x87\xd2\x64\xf9\x06\x53\x73\x35\x92\x00\x05\x81", " SALT", 8}, // eth / Salt Lending Token + { 1, "\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", " SAN", 18}, // eth / Santiment + { 1, "\x78\xfe\x18\xe4\x1f\x43\x6e\x19\x81\xa3\xa6\x0d\x15\x57\xc8\xa7\xa9\x37\x04\x61", " SCANDI", 2}, // eth / Scandiweb Coin + { 1, "\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8", " SCL", 8}, // eth / SocialCoin + { 1, "\x4c\xa7\x41\x85\x53\x2d\xc1\x78\x95\x27\x19\x4e\x5b\x9c\x86\x6d\xd3\x3f\x4e\x82", " SenSatorI", 18}, // eth / SenSatorI Token + { 1, "\x67\x45\xfa\xb6\x80\x1e\x37\x6c\xd2\x4f\x03\x57\x2b\x9c\x9b\x0d\x4e\xdd\xdc\xcf", " SENSE", 8}, // eth / Sensay + { 1, "\xe0\x6e\xda\x74\x35\xba\x74\x9b\x04\x73\x80\xce\xd4\x91\x21\xdd\xe9\x33\x34\xae", " SET", 0}, // eth / SET + { 1, "\x98\xf5\xe9\xb7\xf0\xe3\x39\x56\xc0\x44\x3e\x81\xbf\x7d\xeb\x8b\x5b\x1e\xd5\x45", " SEXY", 18}, // eth / Sexy Token + { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, // eth / SGELDER + { 1, "\x37\x42\x75\x76\x32\x4f\xe1\xf3\x62\x5c\x91\x02\x67\x47\x72\xd7\xcf\x71\x37\x7d", " SGT", 18}, // eth / SelfieYo Gold Token + { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, // eth / SGT + { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, // eth / SHIT + { 1, "\x8a\x18\x7d\x52\x85\xd3\x16\xbc\xbc\x9a\xda\xfc\x08\xb5\x1d\x70\xa0\xd8\xe0\x00", " SIFT", 0}, // eth / SIFT + { 1, "\x68\x88\xa1\x6e\xa9\x79\x2c\x15\xa4\xdc\xf2\xf6\xc6\x23\xd0\x55\xc8\xed\xe7\x92", " SIG", 18}, // eth / Signal + { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, // eth / SKIN + { 1, "\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97", " SKO1", 18}, // eth / Sikoba + { 1, "\x4c\x38\x2f\x8e\x09\x61\x5a\xc8\x6e\x08\xce\x58\x26\x6c\xc2\x27\xe7\xd4\xd9\x13", " SKR", 6}, // eth / SKR Token + { 1, "\x32\x4a\x48\xeb\xcb\xb4\x6e\x61\x99\x39\x31\xef\x9d\x35\xf6\x69\x7c\xd2\x90\x1b", " SKRP", 18}, // eth / Skraps + { 1, "\x6e\x34\xd8\xd8\x47\x64\xd4\x0f\x6d\x7b\x39\xcd\x56\x9f\xd0\x17\xbf\x53\x17\x7d", " SKRP", 18}, // eth / Skraps + { 1, "\xfd\xfe\x8b\x7a\xb6\xcf\x1b\xd1\xe3\xd1\x45\x38\xef\x40\x68\x62\x96\xc4\x20\x52", " SKRP", 18}, // eth / Skraps + { 1, "\x7a\x5f\xf2\x95\xdc\x82\x39\xd5\xc2\x37\x4e\x4d\x89\x42\x02\xaa\xf0\x29\xca\xb6", " SLT", 3}, // eth / Smartlands + { 1, "\x6f\x6d\xeb\x5d\xb0\xc4\x99\x4a\x82\x83\xa0\x1d\x6c\xfe\xeb\x27\xfc\x3b\xbe\x9c", " SMART", 0}, // eth / Smart Billions + { 1, "\x2d\xcf\xaa\xc1\x1c\x9e\xeb\xd8\xc6\xc4\x21\x03\xfe\x9e\x2a\x6a\xd2\x37\xaf\x27", " SMT", 18}, // eth / Smart Node + { 1, "\x55\xf9\x39\x85\x43\x1f\xc9\x30\x40\x77\x68\x7a\x35\xa1\xba\x10\x3d\xc1\xe0\x81", " SMT", 18}, // eth / SmartMesh + { 1, "\x78\xeb\x8d\xc6\x41\x07\x7f\x04\x9f\x91\x06\x59\xb6\xd5\x80\xe8\x0d\xc4\xd2\x37", " SMT", 8}, // eth / Social Media Market + { 1, "\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04", " SNC", 18}, // eth / SNC + { 1, "\xf3\x33\xb2\xac\xe9\x92\xac\x2b\xbd\x87\x98\xbf\x57\xbc\x65\xa0\x61\x84\xaf\xba", " SND", 0}, // eth / Sandcoin + { 1, "\xcf\xd6\xae\x8b\xf1\x3f\x42\xde\x14\x86\x73\x51\xea\xff\x7a\x8a\x3b\x9f\xbb\xe7", " SNG", 8}, // eth / SINERGIA + { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, // eth / SingularDTV + { 1, "\x44\xf5\x88\xae\xeb\x8c\x44\x47\x14\x39\xd1\x27\x0b\x36\x03\xc6\x6a\x92\x62\xf1", " SNIP", 18}, // eth / SNIP + { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, // eth / SNM + { 1, "\xbd\xc5\xba\xc3\x9d\xbe\x13\x2b\x1e\x03\x0e\x89\x8a\xe3\x83\x00\x17\xd7\xd9\x69", " SNOV", 18}, // eth / SNOV + { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, // eth / Status Network Token + { 1, "\x1f\x54\x63\x8b\x77\x37\x19\x3f\xfd\x86\xc1\x9e\xc5\x19\x07\xa7\xc4\x17\x55\xd8", " SOL", 6}, // eth / Sola Token + { 1, "\x42\xd6\x62\x2d\xec\xe3\x94\xb5\x49\x99\xfb\xd7\x3d\x10\x81\x23\x80\x6f\x6a\x18", " SPANK", 18}, // eth / SpankChain + { 1, "\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", " SPARC", 18}, // eth / SPARC + { 1, "\x24\xae\xf3\xbf\x1a\x47\x56\x15\x00\xf9\x43\x0d\x74\xed\x40\x97\xc4\x7f\x51\xf2", " SPARTA", 4}, // eth / SPARTA + { 1, "\x85\x08\x93\x89\xc1\x4b\xd9\xc7\x7f\xc2\xb8\xf0\xc3\xd1\xdc\x33\x63\xbf\x06\xef", " SPF", 18}, // eth / Sportify + { 1, "\x20\xf7\xa3\xdd\xf2\x44\xdc\x92\x99\x97\x5b\x4d\xa1\xc3\x9f\x8d\x5d\x75\xf0\x5a", " SPN", 6}, // eth / Sapien + { 1, "\x68\xd5\x7c\x9a\x1c\x35\xf6\x3e\x2c\x83\xee\x8e\x49\xa6\x4e\x9d\x70\x52\x8d\x25", " SRN", 18}, // eth / Sirin Labs + { 1, "\xb1\x5f\xe5\xa1\x23\xe6\x47\xba\x59\x4c\xea\x7a\x1e\x64\x86\x46\xf9\x5e\xb4\xaa", " SS", 18}, // eth / Sharder + { 1, "\xbb\xff\x86\x2d\x90\x6e\x34\x8e\x99\x46\xbf\xb2\x13\x2e\xcb\x15\x7d\xa3\xd4\xb4", " SS", 18}, // eth / Sharder + { 1, "\x6e\x20\x50\xcb\xfb\x3e\xd8\xa4\xd3\x9b\x64\xcc\x9f\x47\xe7\x11\xa0\x3a\x5a\x89", " SSH", 18}, // eth / StreamShares + { 1, "\x9a\x00\x5c\x9a\x89\xbd\x72\xa4\xbd\x27\x72\x1e\x7a\x09\xa3\xc1\x1d\x2b\x03\xc4", " STAC", 18}, // eth / Starter Coin + { 1, "\xf7\x0a\x64\x2b\xd3\x87\xf9\x43\x80\xff\xb9\x04\x51\xc2\xc8\x1d\x4e\xb8\x2c\xbc", " STAR", 18}, // eth / Star Token + { 1, "\x62\x9a\xee\x55\xed\x49\x58\x1c\x33\xab\x27\xf9\x40\x3f\x79\x92\xa2\x89\xff\xd5", " STC", 18}, // eth / StrikeCoin Token + { 1, "\xae\x73\xb3\x8d\x1c\x9a\x8b\x27\x41\x27\xec\x30\x16\x0a\x49\x27\xc4\xd7\x18\x24", " STK", 18}, // eth / STK Token + { 1, "\x59\x93\x46\x77\x9e\x90\xfc\x3f\x5f\x99\x7b\x5e\xa7\x15\x34\x98\x20\xf9\x15\x71", " STN", 4}, // eth / Saturn Network + { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, // eth / STORJ + { 1, "\xd0\xa4\xb8\x94\x6c\xb5\x2f\x06\x61\x27\x3b\xfb\xc6\xfd\x0e\x0c\x75\xfc\x64\x33", " STORM", 18}, // eth / Storm Token + { 1, "\xec\xd5\x70\xbb\xf7\x47\x61\xb9\x60\xfa\x04\xcc\x10\xfe\x2c\x4e\x86\xff\xda\x36", " STP", 8}, // eth / StashPay + { 1, "\x5c\x3a\x22\x85\x10\xd2\x46\xb7\x8a\x37\x65\xc2\x02\x21\xcb\xf3\x08\x2b\x44\xa4", " STQ", 18}, // eth / Storiqa + { 1, "\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96", " STRC", 8}, // eth / STRC + { 1, "\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45", " STX", 18}, // eth / StoxToken + { 1, "\x12\x48\x0e\x24\xeb\x5b\xec\x1a\x9d\x43\x69\xca\xb6\xa8\x0c\xad\x3c\x0a\x37\x7a", " SUB", 2}, // eth / Substratum + { 1, "\x9e\x88\x61\x34\x18\xcf\x03\xdc\xa5\x4d\x6a\x2c\xf6\xad\x93\x4a\x78\xc7\xa1\x7a", " SWM", 18}, // eth / Swarm Fund Token + { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, // eth / Swarm City Token + { 1, "\x12\xb3\x06\xfa\x98\xf4\xcb\xb8\xd4\x45\x7f\xdf\xf3\xa0\xa0\xa5\x6f\x07\xcc\xdf", " SXDT", 18}, // eth / Spectre.ai D-Token + { 1, "\x2c\x82\xc7\x3d\x5b\x34\xaa\x01\x59\x89\x46\x2b\x29\x48\xcd\x61\x6a\x37\x64\x1f", " SXUT", 18}, // eth / Spectre.ai U-Token + { 1, "\x10\xb1\x23\xfd\xdd\xe0\x03\x24\x31\x99\xaa\xd0\x35\x22\x06\x5d\xc0\x58\x27\xa0", " SYN", 18}, // eth / Synapse + { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, // eth / Token-as-a-Service + { 1, "\xc2\x7a\x2f\x05\xfa\x57\x7a\x83\xba\x0f\xdb\x4c\x38\x44\x3c\x07\x18\x35\x65\x01", " TAU", 18}, // eth / Lamden Tau + { 1, "\xfa\xcc\xd5\xfc\x83\xc3\xe4\xc3\xc1\xac\x1e\xf3\x5d\x15\xad\xf0\x6b\xcf\x20\x9c", " TBC2", 8}, // eth / TBC2 + { 1, "\xaf\xe6\x05\x11\x34\x1a\x37\x48\x8d\xe2\x5b\xef\x35\x19\x52\x56\x2e\x31\xfc\xc1", " TBT", 8}, // eth / TBitBot + { 1, "\x2a\x1d\xba\xbe\x65\xc5\x95\xb0\x02\x2e\x75\x20\x8c\x34\x01\x41\x39\xd5\xd3\x57", " TDH", 18}, // eth / TrustedHealth + { 1, "\x85\xe0\x76\x36\x1c\xc8\x13\xa9\x08\xff\x67\x2f\x9b\xad\x15\x41\x47\x44\x02\xb2", " TEL", 2}, // eth / Telcoin + { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, // eth / TrueFlip + { 1, "\x38\x83\xf5\xe1\x81\xfc\xca\xf8\x41\x0f\xa6\x1e\x12\xb5\x9b\xad\x96\x3f\xb6\x45", " THETA", 18}, // eth / Theta Token + { 1, "\xfe\x7b\x91\x5a\x0b\xaa\x0e\x79\xf8\x5c\x55\x53\x26\x65\x13\xf7\xc1\xc0\x3e\xd0", " THUG", 18}, // eth / THUG + { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, // eth / Chronobank + { 1, "\x80\xbc\x55\x12\x56\x1c\x7f\x85\xa3\xa9\x50\x8c\x7d\xf7\x90\x1b\x37\x0f\xa1\xdf", " TIO", 18}, // eth / TIO + { 1, "\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", " TIX", 18}, // eth / Blocktix + { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, // eth / TokenCard + { 1, "\x08\xf5\xa9\x23\x5b\x08\x17\x3b\x75\x69\xf8\x36\x45\xd2\xc7\xfb\x55\xe8\xcc\xd8", " TNT", 8}, // eth / Tierion Network Token + { 1, "\xcb\x3f\x90\x2b\xf9\x76\x26\x39\x1b\xf8\xba\x87\x26\x4b\xbc\x3d\xc1\x34\x69\xbe", " TRC", 18}, // eth / The Real Coin + { 1, "\x56\x6f\xd7\x99\x9b\x1f\xc3\x98\x80\x22\xbd\x38\x50\x7a\x48\xf0\xbc\xf2\x2c\x77", " TRCN", 18}, // eth / The Real Coin + { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, // eth / TRST + { 1, "\xf2\x30\xb7\x90\xe0\x53\x90\xfc\x82\x95\xf4\xd3\xf6\x03\x32\xc9\x3b\xed\x42\xe2", " TRX", 6}, // eth / Tron Lab Token + { 1, "\x2e\xf1\xab\x8a\x26\x18\x7c\x58\xbb\x8a\xae\xb1\x1b\x2f\xc6\xd2\x5c\x5c\x07\x16", " TWN", 18}, // eth / The World News + { 1, "\xfb\xd0\xd1\xc7\x7b\x50\x17\x96\xa3\x5d\x86\xcf\x91\xd6\x5d\x97\x78\xee\xe6\x95", " TWNKL", 3}, // eth / Twinkle + { 1, "\x24\x69\x27\x91\xbc\x44\x4c\x5c\xd0\xb8\x1e\x3c\xbc\xab\xa4\xb0\x4a\xcd\x1f\x3b", " UKG", 18}, // eth / UnikoinGold + { 1, "\x10\x5d\x97\xef\x2e\x72\x3f\x1c\xfb\x24\x51\x9b\xc6\xff\x15\xa6\xd0\x91\xa3\xf1", " UMKA", 4}, // eth / UMKA + { 1, "\x8e\x5a\xfc\x69\xf6\x22\x7a\x3a\xd7\x5e\xd3\x46\xc8\x72\x3b\xc6\x2c\xe9\x71\x23", " UMKA", 4}, // eth / UMKA + { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " Unicorn", 0}, // eth / Unicorn + { 1, "\xd0\x1d\xb7\x3e\x04\x78\x55\xef\xb4\x14\xe6\x20\x20\x98\xc4\xbe\x4c\xd2\x42\x3b", " UQC", 18}, // eth / Uquid Coin + { 1, "\xd7\x60\xad\xdf\xb2\x4d\x9c\x01\xfe\x4b\xfe\xa7\x47\x5c\x5e\x36\x36\x68\x40\x58", " USDM", 2}, // eth / Mether (USDM) + { 1, "\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", " USDT", 6}, // eth / USD Tether (erc20) + { 1, "\x70\xa7\x28\x33\xd6\xbf\x7f\x50\x8c\x82\x24\xce\x59\xea\x1e\xf3\xd0\xea\x3a\x38", " UTK", 18}, // eth / UTK + { 1, "\x9e\x33\x19\x63\x6e\x21\x26\xe3\xc0\xbc\x9e\x31\x34\xae\xc5\xe1\x50\x8a\x46\xc7", " UTN-P", 18}, // eth / Universa + { 1, "\x35\x43\x63\x8e\xd4\xa9\x00\x6e\x48\x40\xb1\x05\x94\x42\x71\xbc\xea\x15\x60\x5d", " UUU", 18}, // eth / U Networks + { 1, "\x82\xbd\x52\x6b\xdb\x71\x8c\x6d\x4d\xd2\x29\x1e\xd0\x13\xa5\x18\x6c\xae\x2d\xca", " VDOC", 18}, // eth / Duty of Care Token + { 1, "\x34\x0d\x2b\xde\x5e\xb2\x8c\x1e\xed\x91\xb2\xf7\x90\x72\x3e\x3b\x16\x06\x13\xb7", " VEE", 18}, // eth / BLOCKv + { 1, "\xeb\xed\x4f\xf9\xfe\x34\x41\x3d\xb8\xfc\x82\x94\x55\x6b\xbd\x15\x28\xa4\xda\xca", " VENUS", 3}, // eth / VENUS + { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, // eth / Veritas + { 1, "\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1", " VET", 18}, // eth / Vechain + { 1, "\x2c\x97\x4b\x2d\x0b\xa1\x71\x6e\x64\x4c\x1f\xc5\x99\x82\xa8\x9d\xdd\x2f\xf7\x24", " VIB", 18}, // eth / VIB + { 1, "\x88\x24\x48\xf8\x3d\x90\xb2\xbf\x47\x7a\xf2\xea\x79\x32\x7f\xde\xa1\x33\x5d\x93", " VIBEX", 18}, // eth / VIBEX Exchange Token + { 1, "\xe8\xff\x5c\x9c\x75\xde\xb3\x46\xac\xac\x49\x3c\x46\x3c\x89\x50\xbe\x03\xdf\xba", " VIBEX", 18}, // eth / VIBEX + { 1, "\xf0\x3f\x8d\x65\xba\xfa\x59\x86\x11\xc3\x49\x51\x24\x09\x3c\x56\xe8\xf6\x38\xf0", " VIEW", 18}, // eth / Viewly + { 1, "\x23\xb7\x5b\xc7\xaa\xf2\x8e\x2d\x66\x28\xc3\xf4\x24\xb3\x88\x2f\x8f\x07\x2a\x3c", " VIT", 18}, // eth / Vice Industry Token + { 1, "\x51\x94\x75\xb3\x16\x53\xe4\x6d\x20\xcd\x09\xf9\xfd\xcf\x3b\x12\xbd\xac\xb4\xf5", " VIU", 18}, // eth / VIU + { 1, "\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c", " VLD", 18}, // eth / VLD + { 1, "\xc3\xbc\x9e\xb7\x1f\x75\xec\x43\x9a\x6b\x6c\x8e\x8b\x74\x6f\xcf\x5b\x62\xf7\x03", " VOC", 18}, // eth / VORMACOIN + { 1, "\x83\xee\xa0\x0d\x83\x8f\x92\xde\xc4\xd1\x47\x56\x97\xb9\xf4\xd3\x53\x7b\x56\xe3", " VOISE", 8}, // eth / Voise + { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, // eth / Veros + { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, // eth / Vdice + { 1, "\x28\x6b\xda\x14\x13\xa2\xdf\x81\x73\x1d\x49\x30\xce\x2f\x86\x2a\x35\xa6\x09\xfe", " WaBi", 18}, // eth / WaBi + { 1, "\x39\xbb\x25\x9f\x66\xe1\xc5\x9d\x5a\xbe\xf8\x83\x75\x97\x9b\x4d\x20\xd9\x80\x22", " WAX", 8}, // eth / WAX + { 1, "\x74\x95\x1b\x67\x7d\xe3\x2d\x59\x6e\xe8\x51\xa2\x33\x33\x69\x26\xe6\xa2\xcd\x09", " WBA", 7}, // eth / WeBetCrypto + { 1, "\x8f\x93\x6f\xe0\xfa\xf0\x60\x4c\x9c\x0e\xf2\x40\x6b\xde\x0a\x65\x36\x55\x15\xd6", " WCN", 18}, // eth / WorldCoinNetwork + { 1, "\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63", " WCT", 18}, // eth / WePower + { 1, "\xc0\x2a\xaa\x39\xb2\x23\xfe\x8d\x0a\x0e\x5c\x4f\x27\xea\xd9\x08\x3c\x75\x6c\xc2", " WETH", 18}, // eth / WETH + { 1, "\xf4\xfe\x95\x60\x38\x81\xd0\xe0\x79\x54\xfd\x76\x05\xe0\xe9\xa9\x16\xe4\x2c\x44", " WHEN", 18}, // eth / WHEN Token + { 1, "\xe2\x00\x64\x18\x90\x77\x2f\xce\x8e\xe6\xed\xc5\x35\x4c\xce\xa3\x0a\xc9\x2f\x49", " WHO", 18}, // eth / WhoHas + { 1, "\xe9\x33\xc0\xcd\x97\x84\x41\x4d\x5f\x27\x8c\x11\x49\x04\xf5\xa8\x4b\x39\x69\x19", " WHO", 18}, // eth / WhoHas + { 1, "\x5e\x4a\xbe\x64\x19\x65\x0c\xa8\x39\xce\x5b\xb7\xdb\x42\x2b\x88\x1a\x60\x64\xbb", " WiC", 18}, // eth / Wi Coin + { 1, "\x62\xcd\x07\xd4\x14\xec\x50\xb6\x8c\x7e\xca\xa8\x63\xa2\x3d\x34\x4f\x2d\x06\x2f", " WIC", 0}, // eth / WickNote + { 1, "\xd3\xc0\x07\x72\xb2\x4d\x99\x7a\x81\x22\x49\xca\x63\x7a\x92\x1e\x81\x35\x77\x01", " WILD", 18}, // eth / WILD Token + { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, // eth / WINGS + { 1, "\x72\x87\x81\xe7\x57\x35\xdc\x09\x62\xdf\x3a\x51\xd7\xef\x47\xe7\x98\xa7\x10\x7e", " WOLK", 18}, // eth / WOLK + { 1, "\xf6\xb5\x5a\xcb\xbc\x49\xf4\x52\x4a\xa4\x8d\x19\x28\x1a\x9a\x77\xc5\x4d\xe1\x0f", " WOLK", 18}, // eth / Wolk Token + { 1, "\xd1\x8e\x45\x4d\x84\x4e\xb0\x00\x9d\x32\xe0\x7a\x0c\xde\x89\xe1\x8d\x64\xcf\xb4", " WORK", 18}, // eth / workTOKEN + { 1, "\x62\x08\x72\x45\x08\x71\x25\xd3\xdb\x5b\x9a\x3d\x71\x3d\x78\xe7\xbb\xc3\x1e\x54", " WPC", 18}, // eth / WorldPeaceCoin + { 1, "\x4c\xf4\x88\x38\x7f\x03\x5f\xf0\x8c\x37\x15\x15\x56\x2c\xba\x71\x2f\x90\x15\xd4", " WPR", 18}, // eth / WePower Token + { 1, "\x71\xe8\xd7\x4f\xf1\xc9\x23\xe3\x69\xd0\xe7\x0d\xfb\x09\x86\x66\x29\xc4\xdd\x35", " WRK", 18}, // eth / WorkCoin + { 1, "\xb7\xcb\x1c\x96\xdb\x6b\x22\xb0\xd3\xd9\x53\x6e\x01\x08\xd0\x62\xbd\x48\x8f\x74", " WTC", 18}, // eth / Walton + { 1, "\xd8\x95\x0f\xde\xaa\x10\x30\x4b\x7a\x7f\xd0\x3a\x2f\xc6\x6b\xc3\x9f\x3c\x71\x1a", " WYS", 18}, // eth / wystoken + { 1, "\x05\x60\x17\xc5\x5a\xe7\xae\x32\xd1\x2a\xef\x7c\x67\x9d\xf8\x3a\x85\xca\x75\xff", " WYV", 18}, // eth / WyvernToken + { 1, "\x91\x0d\xfc\x18\xd6\xea\x3d\x6a\x71\x24\xa6\xf8\xb5\x45\x8f\x28\x10\x60\xfa\x4c", " X8X", 18}, // eth / X8X + { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, // eth / Xaurum + { 1, "\x28\xde\xe0\x1d\x53\xfe\xd0\xed\xf5\xf6\xe3\x10\xbf\x8e\xf9\x31\x15\x13\xae\x40", " XBP", 18}, // eth / BlitzPredict + { 1, "\x4d\x82\x9f\x8c\x92\xa6\x69\x1c\x56\x30\x0d\x02\x0c\x9e\x0d\xb9\x84\xcf\xe2\xba", " XCC", 18}, // eth / CoinCrowd + { 1, "\x16\xaf\x5b\xfb\x4a\xe7\xe4\x75\xb9\xad\xc3\xbf\x5c\xb2\xf1\xe6\xa5\x0d\x79\x40", " XFS", 8}, // eth / Fanship + { 1, "\xf6\xb6\xaa\x0e\xf0\xf5\xed\xc2\xc1\xc5\xd9\x25\x47\x7f\x97\xea\xf6\x63\x03\xe7", " XGG", 8}, // eth / Going Gems + { 1, "\x53\x3e\xf0\x98\x4b\x2f\xaa\x22\x7a\xcc\x62\x0c\x67\xcc\xe1\x2a\xa3\x9c\xd8\xcd", " XGM", 8}, // eth / XGM + { 1, "\x30\xf4\xa3\xe0\xab\x7a\x76\x73\x3d\x8b\x60\xb8\x9d\xd9\x3c\x3d\x0b\x4c\x9e\x2f", " XGT", 18}, // eth / XGT + { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, // eth / XID + { 1, "\xbc\x86\x72\x7e\x77\x0d\xe6\x8b\x10\x60\xc9\x1f\x6b\xb6\x94\x5c\x73\xe1\x03\x88", " XNK", 18}, // eth / Ink Protocol + { 1, "\xab\x95\xe9\x15\xc1\x23\xfd\xed\x5b\xdf\xb6\x32\x5e\x35\xef\x55\x15\xf1\xea\x69", " XNN", 18}, // eth / XENON + { 1, "\x57\x2e\x6f\x31\x80\x56\xba\x0c\x5d\x47\xa4\x22\x65\x31\x13\x84\x3d\x25\x06\x91", " XNT", 0}, // eth / XNT + { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, // eth / XRL + { 1, "\x0f\x51\x3f\xfb\x49\x26\xff\x82\xd7\xf6\x0a\x05\x06\x90\x47\xac\xa2\x95\xc4\x13", " XSC", 18}, // eth / XSC + { 1, "\x6f\x7a\x4b\xac\x33\x15\xb5\x08\x2f\x79\x31\x61\xa2\x2e\x26\x66\x6d\x22\x71\x7f", " YEED", 18}, // eth / YEED + { 1, "\x0f\x33\xbb\x20\xa2\x82\xa7\x64\x9c\x7b\x3a\xff\x64\x4f\x08\x4a\x93\x48\xe9\x33", " YUPIE", 18}, // eth / YUPIE + { 1, "\x67\x81\xa0\xf8\x4c\x7e\x9e\x84\x6d\xcb\x84\xa9\xa5\xbd\x49\x33\x30\x67\xb1\x04", " ZAP", 18}, // eth / ZAP + { 1, "\x7a\x41\xe0\x51\x7a\x5e\xca\x4f\xdb\xc7\xfb\xeb\xa4\xd4\xc4\x7b\x9f\xf6\xdc\x63", " ZCS", 18}, // eth / Zeusshield + { 1, "\x05\xf4\xa4\x2e\x25\x1f\x2d\x52\xb8\xed\x15\xe9\xfe\xda\xac\xfc\xef\x1f\xad\x27", " ZIL", 12}, // eth / Zilliqa + { 1, "\x55\x4f\xfc\x77\xf4\x25\x1a\x9f\xb3\xc0\xe3\x59\x0a\x6a\x20\x5f\x8d\x4e\x06\x7d", " ZMN", 18}, // eth / ZMINE + { 1, "\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", " ZRX", 18}, // eth / 0x Project + { 1, "\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1", " ZST", 8}, // eth / Zeus Exchange + {42, "\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67", " Aeternity", 18}, // kov / Aeternity + {42, "\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83", " GUP", 3}, // kov / GUP + { 4, "\x39\x8a\x7a\x69\xf3\xc5\x91\x81\xa1\xff\xe3\x4b\xed\x11\xdc\xb5\xdf\x86\x3a\x8a", " AETH", 18}, // rin / AKASHA Tokens + { 4, "\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f", " BHNT", 0}, // rin / Berlin Hack&Tell winner token + { 4, "\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54", " CTGA", 18}, // rin / Convenient To Go + { 4, "\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a", " KC", 18}, // rin / Karma Token + { 4, "\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91", " NONE", 0}, // rin / None + { 4, "\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80", " PPD", 18}, // rin / PP Donation + { 4, "\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b", " WALL", 15}, // rin / WALLETH Community-Token + { 3, "\x6f\x95\xa3\xb6\x82\xf8\xe9\xaa\xcc\x86\xd0\x57\xa6\xdf\x88\xa0\xe6\x81\x45\xa8", " ILSC", 2}, // rop / IsraCoin + { 3, "\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31", " NONE", 0}, // rop / None + { 8, "\xff\x3b\xf0\x57\xad\xf3\xb0\xe0\x15\xb6\x46\x53\x31\xa6\x23\x6e\x55\x68\x82\x74", " BEER", 0}, // ubq / BEER + { 8, "\x08\x53\x3d\x6a\x06\xce\x36\x52\x98\xb1\x2e\xf9\x2e\xb4\x07\xcb\xa8\xaa\x82\x73", " CEFS", 8}, // ubq / CEFS + { 8, "\x94\xad\x7e\x41\xc1\xd4\x40\x22\xc4\xf4\x7c\xb1\xba\x01\x9f\xd1\xa0\x22\xc5\x36", " DOT", 8}, // ubq / DOT + { 8, "\x4b\x48\x99\xa1\x0f\x3e\x50\x7d\xb2\x07\xb0\xee\x24\x26\x02\x9e\xfa\x16\x8a\x67", " QWARK", 8}, // ubq / QWARK + { 8, "\x5e\x17\x15\xbb\x79\x80\x5b\xd6\x72\x72\x97\x60\xb3\xf7\xf3\x4d\x6f\x48\x50\x98", " RICKS", 8}, // ubq / RICKS }; const TokenType *UnknownToken = (const TokenType *)1; diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 5f3499f4d8..1b60e594e3 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 125 +#define TOKENS_COUNT 716 typedef struct { uint8_t chain_id; From 826b764085c0e637eed5bf631bacea964327289d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Jun 2018 17:52:38 +0200 Subject: [PATCH 0891/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index e74d966cf6..2f418817cc 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit e74d966cf6794553fb91f4f6980ce4f8466de504 +Subproject commit 2f418817cc92e3cd7370b680d3e0acd0b5231c07 From f35a74323b8e3cea11601fd84cb91e28fe529ee6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 09:47:21 +0200 Subject: [PATCH 0892/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 669acd7331..f586155d80 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 669acd7331fc02b6ef41c4a91112e6e6d6e831be +Subproject commit f586155d808be7467e31da907b0106b4c31a0d1d From dac7efadb86820ce4836b400d8dc8a1e682d03f2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 09:50:21 +0200 Subject: [PATCH 0893/1154] firmware: move storage_update for applyFlags --- firmware/fsm_msg_common.h | 1 - firmware/storage.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 6dfc2d0726..caa9c34b89 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -314,7 +314,6 @@ void fsm_msgApplyFlags(ApplyFlags *msg) { if (msg->has_flags) { storage_applyFlags(msg->flags); - storage_update(); } fsm_sendSuccess(_("Flags applied")); } diff --git a/firmware/storage.c b/firmware/storage.c index 743b21a010..ca77f3c539 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -849,6 +849,7 @@ void storage_applyFlags(uint32_t flags) } storageUpdate.has_flags = true; storageUpdate.flags |= flags; + storage_update(); } uint32_t storage_getFlags(void) From e96101e72ae51f183e33f07bde19f26a895a7d46 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 14:28:27 +0200 Subject: [PATCH 0894/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 2f418817cc..2dad4dcd51 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 2f418817cc92e3cd7370b680d3e0acd0b5231c07 +Subproject commit 2dad4dcd519662b9d69e276e737ac1bba655555d From e0b64b151df4aab3dec1e4941db2951bb2b91bc9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 15:01:47 +0200 Subject: [PATCH 0895/1154] build: fix fprint calculation in build.sh --- build.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build.sh b/build.sh index b62d226ae6..753901f5f3 100755 --- a/build.sh +++ b/build.sh @@ -44,10 +44,16 @@ from __future__ import print_function import hashlib import sys for arg in sys.argv[1:]: - (fn, max_size) = arg.split(':') + (fn, fprint_start, hashing, max_size) = arg.split(':') + fprint_start = int(fprint_start) + max_size = int(max_size) data = open(fn, 'rb').read() + if hashing == 'd': + fprint = hashlib.sha256(hashlib.sha256(data[fprint_start:]).digest()).hexdigest() + else: + fprint = hashlib.sha256(data[fprint_start:]).hexdigest() print('\n\n') print('Filename :', fn) - print('Fingerprint :', hashlib.sha256(hashlib.sha256(data).digest()).hexdigest()) - print('Size : %d bytes (out of %d maximum)' % (len(data), int(max_size, 10))) -" $BOOTLOADER_BINFILE:32768 $FIRMWARE_BINFILE:491520 + print('Fingerprint :', fprint) + print('Size : %d bytes (out of %d maximum)' % (len(data), max_size)) +" $BOOTLOADER_BINFILE:0:d:32768 $FIRMWARE_BINFILE:256:s:491520 From 9be09f255f080015132765b9e5cd14447ab416ca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 15:03:46 +0200 Subject: [PATCH 0896/1154] firmware: add hash of bootloader 1.5.0 --- firmware/bl_check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 35b1fd1ad7..6acc941a3c 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -39,6 +39,7 @@ int known_bootloader(int r, const uint8_t *hash) { // for more info, refer to "make -C bootloader align" and "firmware/bl_data.py". if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 + if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 return 0; } From 0148ec6b2359ad33428fcaf14e98986391206e98 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Jun 2018 15:25:37 +0200 Subject: [PATCH 0897/1154] build: update script to allow different source repo --- build.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/build.sh b/build.sh index 753901f5f3..dd8100c0ea 100755 --- a/build.sh +++ b/build.sh @@ -5,6 +5,13 @@ IMAGE=trezor-mcu-build BOOTLOADER_TAG=${1:-master} FIRMWARE_TAG=${2:-master} +REPOSITORY=${3:-trezor} + +if [ "$REPOSITORY" = "local" ]; then + REPOSITORY=file:///local/ +else + REPOSITORY=https://github.com/$REPOSITORY/trezor-mcu.git +fi BOOTLOADER_BINFILE=build/bootloader-$BOOTLOADER_TAG.bin BOOTLOADER_ELFFILE=build/bootloader-$BOOTLOADER_TAG.elf @@ -13,9 +20,9 @@ FIRMWARE_BINFILE=build/trezor-$FIRMWARE_TAG.bin FIRMWARE_ELFFILE=build/trezor-$FIRMWARE_TAG.elf docker build -t $IMAGE . -docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ +docker run -i -t -v $(pwd):/local -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cd /tmp && \ - git clone https://github.com/trezor/trezor-mcu.git trezor-mcu-bl && \ + git clone $REPOSITORY trezor-mcu-bl && \ cd trezor-mcu-bl && \ git checkout $BOOTLOADER_TAG && \ git submodule update --init --recursive && \ @@ -25,7 +32,7 @@ docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cp bootloader/bootloader.bin /$BOOTLOADER_BINFILE && \ cp bootloader/bootloader.elf /$BOOTLOADER_ELFFILE && \ cd /tmp && \ - git clone https://github.com/trezor/trezor-mcu.git trezor-mcu-fw && \ + git clone $REPOSITORY trezor-mcu-fw && \ cd trezor-mcu-fw && \ git checkout $FIRMWARE_TAG && \ git submodule update --init --recursive && \ From c9113fd3f5fcd78e9e560dbac75ed5aae359eb2d Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 18 Jun 2018 21:01:54 +0100 Subject: [PATCH 0898/1154] firmware: fix message processing, typos in recovery --- firmware/messages.c | 13 ++++++++----- firmware/messages.h | 3 +-- firmware/recovery.c | 6 ++++-- firmware/storage.c | 2 ++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 4638057a88..b388067fd6 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -233,7 +233,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * } } -void msg_read_common(char type, const uint8_t *buf, int len) +void msg_read_common(char type, const uint8_t *buf, uint32_t len) { static char read_state = READSTATE_IDLE; static CONFIDENTIAL uint8_t msg_in[MSG_IN_SIZE]; @@ -271,8 +271,12 @@ void msg_read_common(char type, const uint8_t *buf, int len) read_state = READSTATE_IDLE; return; } - memcpy(msg_in + msg_pos, buf + 1, len - 1); - msg_pos += len - 1; + /* raw data starts at buf + 1 with len - 1 bytes */ + buf++; + len = MIN(len - 1, MSG_IN_SIZE - msg_pos); + + memcpy(msg_in + msg_pos, buf, len); + msg_pos += len; } if (msg_pos >= msg_size) { @@ -329,8 +333,7 @@ void msg_read_tiny(const uint8_t *buf, int len) } const pb_field_t *fields = 0; - // upstream nanopb is missing const qualifier, so we have to cast :-/ - pb_istream_t stream = pb_istream_from_buffer((uint8_t *)buf + 9, msg_size); + pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); switch (msg_id) { case MessageType_MessageType_PinMatrixAck: diff --git a/firmware/messages.h b/firmware/messages.h index ace4a44480..030af0e698 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -42,11 +42,10 @@ const uint8_t *msg_debug_out_data(void); #endif -void msg_read_common(char type, const uint8_t *buf, int len); +void msg_read_common(char type, const uint8_t *buf, uint32_t len); bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr); void msg_read_tiny(const uint8_t *buf, int len); -void msg_debug_read_tiny(const uint8_t *buf, int len); extern uint8_t msg_tiny[128]; extern uint16_t msg_tiny_id; diff --git a/firmware/recovery.c b/firmware/recovery.c index 8990f29092..be5661af24 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -295,7 +295,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num) /* avoid picking out of range numbers */ for (int i = 0; i < displayedChoices; i++) { - if (word_matrix[i] > num) + if (word_matrix[i] >= num) word_matrix[i] = 0; } /* two column layout: middle column = right column */ @@ -405,11 +405,13 @@ static void recovery_digit(const char digit) { /* received final word */ /* Mark the chosen word for 250 ms */ - int y = 54 - ((digit - '1')/3)*11; + int y = 54 - ((digit - '1') / 3) * 11; int x = 64 * (((digit - '1') % 3) > 0); oledInvert(x + 1, y, x + 62, y + 9); oledRefresh(); + usbTiny(1); usbSleep(250); + usbTiny(0); /* index of the chosen word */ int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; diff --git a/firmware/storage.c b/firmware/storage.c index ca77f3c539..429a82e93f 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -565,6 +565,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; + char oldTiny = usbTiny(1); pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8); get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); for (int i = 0; i < 8; i++) { @@ -572,6 +573,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); } pbkdf2_hmac_sha512_Final(&pctx, secret); + usbTiny(oldTiny); aes_decrypt_ctx ctx; aes_decrypt_key256(secret, &ctx); aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); From bff45ecfff1eeb45f33fce6a677588242de88555 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 23 Jun 2018 13:25:18 +0200 Subject: [PATCH 0899/1154] docs: update changelogs --- bootloader/ChangeLog | 3 +++ firmware/ChangeLog | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index dc409aebdf..50dfb886ce 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,3 +1,6 @@ +Version 1.5.0 +* Make unofficial firmwares work again + Version 1.4.0 * More flash-write tests * Don't restore storage from unofficial firmware diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 98422c25d4..0490b387f5 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,14 @@ +Version 1.6.2 +* Stable release, optional update +* Add possibility to set custom auto-lock delay +* Bitcoin Cash cashaddr support +* Zcash Overwinter hardfork support +* Support for new coins: + - Decred, Bitcoin Private, Fujicoin, Groestlcoin, Vertcoin, Viacoin, Zcoin +* Support for new Ethereum networks: + - EOS Classic, Ethereum Social, Ellaism, Callisto, EtherGem, Wanchain +* Support for 500+ new Ethereum tokens + Version 1.6.1 * Stable release, optional update * Use fixed-width font for addresses From db19d24b877fd5c66591dc98fb943742f73cb393 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Jun 2018 13:33:41 +0200 Subject: [PATCH 0900/1154] firmware: fix changelog for 1.6.1 --- firmware/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 0490b387f5..cfe0edffbb 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -10,7 +10,7 @@ Version 1.6.2 * Support for 500+ new Ethereum tokens Version 1.6.1 -* Stable release, optional update +* Stable release, required update * Use fixed-width font for addresses * Lots of under-the-hood improvements * Fixed issue with write-protection settings From ddc51a39e2283ae968a038f2f92f5170fd9dff99 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Jun 2018 14:59:50 +0200 Subject: [PATCH 0901/1154] build: add more verbose output to build script --- build.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index dd8100c0ea..005ec9f883 100755 --- a/build.sh +++ b/build.sh @@ -20,6 +20,13 @@ FIRMWARE_BINFILE=build/trezor-$FIRMWARE_TAG.bin FIRMWARE_ELFFILE=build/trezor-$FIRMWARE_TAG.elf docker build -t $IMAGE . + +echo +echo "STARTING BUILD:" +echo +echo "Building bootloader '$BOOTLOADER_TAG' + firmware '$FIRMWARE_TAG' from repo: $REPOSITORY" +echo + docker run -i -t -v $(pwd):/local -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cd /tmp && \ git clone $REPOSITORY trezor-mcu-bl && \ @@ -46,6 +53,10 @@ docker run -i -t -v $(pwd):/local -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ cp firmware/trezor.elf /$FIRMWARE_ELFFILE " +echo +echo "FINISHED BUILD" +echo + /usr/bin/env python -c " from __future__ import print_function import hashlib @@ -59,7 +70,6 @@ for arg in sys.argv[1:]: fprint = hashlib.sha256(hashlib.sha256(data[fprint_start:]).digest()).hexdigest() else: fprint = hashlib.sha256(data[fprint_start:]).hexdigest() - print('\n\n') print('Filename :', fn) print('Fingerprint :', fprint) print('Size : %d bytes (out of %d maximum)' % (len(data), max_size)) From e8a46d46c20296b8bf165d0d72b2a59974c959b7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 27 Jun 2018 17:00:39 +0200 Subject: [PATCH 0902/1154] ethereum: update to new API --- firmware/ethereum.c | 2 +- firmware/fsm_msg_ethereum.h | 4 ++-- vendor/trezor-crypto | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index f06215c03f..b05661777e 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -293,7 +293,7 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui if (to_len) { char to_str[41]; - ethereum_address_checksum(to, to_str); + ethereum_address_checksum(to, to_str, false, 0); memcpy(_to1 + 5, to_str, 10); memcpy(_to2, to_str + 10, 15); memcpy(_to3, to_str + 25, 15); diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 0c9420e3fe..9a20aa8e53 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -36,7 +36,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) strlcpy(desc, "Address:", sizeof(desc)); char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2); + ethereum_address_checksum(resp->address.bytes, address + 2, false, 0); if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { return; @@ -80,7 +80,7 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) } char address[43] = { '0', 'x' }; - ethereum_address_checksum(msg->address.bytes, address + 2); + ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); layoutVerifyAddress(address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f586155d80..3e8974ff88 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f586155d808be7467e31da907b0106b4c31a0d1d +Subproject commit 3e8974ff8871263a70b7fbb9a27a1da5b0d810f7 From d1a48f32cef9a1fd2c7d291db0a71cbedf6a14e1 Mon Sep 17 00:00:00 2001 From: ZuluCrypto Date: Wed, 27 Jun 2018 09:36:51 -0600 Subject: [PATCH 0903/1154] Stellar: use strings instead of bytes for addresses (#372) * Use the new protobuf messages that send accounts as strings (fixes #367) * `stellar_signingAbort()` now takes an error message * Operations now check if a transaction is being signed (fixes #368) * Operations now return false on error or if the user cancels * Stellar `fsm_*` methods now check operation result and return early if the operation fails This PR also re-enables the stellar code in the firmware. --- firmware/Makefile | 2 +- firmware/fsm.c | 2 +- firmware/fsm_msg_stellar.h | 22 +- firmware/protob/Makefile | 2 +- firmware/protob/types.options | 2 +- firmware/stellar.c | 408 +++++++++++++++++++++++++--------- firmware/stellar.h | 35 ++- 7 files changed, 345 insertions(+), 128 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index cb61ea05c3..9cd23f6ef0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,7 @@ OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o -# OBJS += stellar.o +OBJS += stellar.o OBJS += debug.o diff --git a/firmware/fsm.c b/firmware/fsm.c index aca5fe0a40..5997db6a33 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -247,5 +247,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore #include "fsm_msg_ethereum.h" #include "fsm_msg_crypto.h" #include "fsm_msg_nem.h" -// #include "fsm_msg_stellar.h" +#include "fsm_msg_stellar.h" #include "fsm_msg_debug.h" diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index 38b176586c..f12ee8e017 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -96,7 +96,7 @@ void fsm_msgStellarSignTx(StellarSignTx *msg) void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) { - stellar_confirmCreateAccountOp(msg); + if (!stellar_confirmCreateAccountOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -116,7 +116,7 @@ void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) { // This will display additional dialogs to the user - stellar_confirmPaymentOp(msg); + if (!stellar_confirmPaymentOp(msg)) return; // Last operation was confirmed, send a StellarSignedTx if (stellar_allOperationsConfirmed()) { @@ -136,7 +136,7 @@ void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) { - stellar_confirmPathPaymentOp(msg); + if (!stellar_confirmPathPaymentOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -155,7 +155,7 @@ void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) { - stellar_confirmManageOfferOp(msg); + if (!stellar_confirmManageOfferOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -174,7 +174,7 @@ void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) { - stellar_confirmCreatePassiveOfferOp(msg); + if (!stellar_confirmCreatePassiveOfferOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -193,7 +193,7 @@ void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) { - stellar_confirmSetOptionsOp(msg); + if (!stellar_confirmSetOptionsOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -212,7 +212,7 @@ void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) { - stellar_confirmChangeTrustOp(msg); + if (!stellar_confirmChangeTrustOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -231,7 +231,7 @@ void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) { - stellar_confirmAllowTrustOp(msg); + if (!stellar_confirmAllowTrustOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -250,7 +250,7 @@ void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) { - stellar_confirmAccountMergeOp(msg); + if (!stellar_confirmAccountMergeOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -269,7 +269,7 @@ void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) { - stellar_confirmManageDataOp(msg); + if (!stellar_confirmManageDataOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); @@ -288,7 +288,7 @@ void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) { - stellar_confirmBumpSequenceOp(msg); + if (!stellar_confirmBumpSequenceOp(msg)) return; if (stellar_allOperationsConfirmed()) { RESP_INIT(StellarSignedTx); diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index a741bc4c57..74392afcb1 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -12,7 +12,7 @@ PYTHON ?= python protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py types_pb2.py - $(PYTHON) $< | grep -v -e MessageType_Lisk -e MessageType_Stellar > $@ + $(PYTHON) $< | grep -v -e MessageType_Lisk > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/types.options b/firmware/protob/types.options index 07d1db77e3..be97685eba 100644 --- a/firmware/protob/types.options +++ b/firmware/protob/types.options @@ -70,7 +70,7 @@ NEMCosignatoryModification.public_key max_size:32 NEMImportanceTransfer.public_key max_size:32 StellarAssetType.code max_size:13 -StellarAssetType.issuer max_size:32 +StellarAssetType.issuer max_size:57 # Lisk will be supported later diff --git a/firmware/stellar.c b/firmware/stellar.c index 195c82eb16..d33d0f11b1 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -14,13 +14,13 @@ * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . * - * Stellar signing has the following workflow: - * 1. Client sends first 1024 bytes of the transaction - * 2. Trezor parses the transaction header and confirms the details with the user - * 3. Trezor responds to the client with an offset for where to send the next chunk of bytes - * 4. Client sends next 1024 bytes starting at - * 5. Trezor parses and confirms the next operation - * 6. Trezor responds with either an offset for the next operation or a signature + * Stellar signing workflow: + * 1. Client sends a StellarSignTx method to the device with transaction header information + * 2. Device confirms transaction details with the user and requests first operation + * 3. Client sends protobuf message with details about the operation to sign + * 4. Device confirms operation with user + * 5a. If there are more operations in the transaction, device responds with StellarTxOpRequest. Go to 3 + * 5b. If the operation is the last one, device responds with StellarSignedTx */ #include @@ -41,6 +41,7 @@ #include "util.h" #include "layout2.h" #include "fonts.h" +#include "memzero.h" static bool stellar_signing = false; static StellarTransaction stellar_activeTx; @@ -151,11 +152,17 @@ void stellar_signingInit(StellarSignTx *msg) } } -void stellar_confirmSourceAccount(bool has_source_account, uint8_t *bytes) +bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) { if (!has_source_account) { stellar_hashupdate_bool(false); - return; + return true; + } + + // Convert account string to public key bytes + uint8_t bytes[32]; + if (!stellar_getAddressBytes(str_account, bytes)) { + return false; } const char **str_addr_rows = stellar_lineBreakAddress(bytes); @@ -168,21 +175,36 @@ void stellar_confirmSourceAccount(bool has_source_account, uint8_t *bytes) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: source account stellar_hashupdate_address(bytes); + + return true; } -void stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) +bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(0); - const char **str_addr_rows = stellar_lineBreakAddress(msg->new_account.bytes); + // Validate new account and convert to bytes + uint8_t new_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->new_account, new_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + + const char **str_addr_rows = stellar_lineBreakAddress(new_account_bytes); // Amount being funded char str_amount_line[32]; @@ -201,25 +223,39 @@ void stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) str_amount_line ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: address - stellar_hashupdate_address(msg->new_account.bytes); + stellar_hashupdate_address(new_account_bytes); // Hash: starting amount stellar_hashupdate_uint64(msg->starting_balance); stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmPaymentOp(StellarPaymentOp *msg) +bool stellar_confirmPaymentOp(StellarPaymentOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(1); - const char **str_addr_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + // Validate destination account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + + const char **str_addr_rows = stellar_lineBreakAddress(destination_account_bytes); // To: G... char str_to[32]; @@ -245,12 +281,12 @@ void stellar_confirmPaymentOp(StellarPaymentOp *msg) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash destination - stellar_hashupdate_address(msg->destination_account.bytes); + stellar_hashupdate_address(destination_account_bytes); // asset stellar_hashupdate_asset(&(msg->asset)); // amount (even though amount is signed it doesn't matter for hashing) @@ -258,15 +294,28 @@ void stellar_confirmPaymentOp(StellarPaymentOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) +bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(2); - const char **str_dest_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + // Validate destination account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + const char **str_dest_rows = stellar_lineBreakAddress(destination_account_bytes); // To: G... char str_to[32]; @@ -301,8 +350,8 @@ void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) str_dest_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Confirm what the sender is using to pay @@ -321,8 +370,8 @@ void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) _("from your account.") ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Note: no confirmation for intermediate steps since they don't impact the user @@ -331,7 +380,7 @@ void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) // send max (signed vs. unsigned doesn't matter wrt hashing) stellar_hashupdate_uint64(msg->send_max); // destination account - stellar_hashupdate_address(msg->destination_account.bytes); + stellar_hashupdate_address(destination_account_bytes); // destination asset stellar_hashupdate_asset(&(msg->destination_asset)); // destination amount @@ -345,11 +394,18 @@ void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmManageOfferOp(StellarManageOfferOp *msg) +bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(3); @@ -409,8 +465,8 @@ void stellar_confirmManageOfferOp(StellarManageOfferOp *msg) str_buying_asset ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash selling asset @@ -428,11 +484,18 @@ void stellar_confirmManageOfferOp(StellarManageOfferOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(4); @@ -482,8 +545,8 @@ void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) str_buying_asset ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash selling asset @@ -499,11 +562,18 @@ void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) +bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(5); @@ -517,7 +587,14 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) stellar_hashupdate_bool(msg->has_inflation_destination_account); if (msg->has_inflation_destination_account) { strlcpy(str_title, _("Set Inflation Destination"), sizeof(str_title)); - const char **str_addr_rows = stellar_lineBreakAddress(msg->inflation_destination_account.bytes); + + // Validate account and convert to bytes + uint8_t inflation_destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->inflation_destination_account, inflation_destination_account_bytes)) { + stellar_signingAbort(_("Invalid inflation destination account")); + return false; + } + const char **str_addr_rows = stellar_lineBreakAddress(inflation_destination_account_bytes); stellar_layoutTransactionDialog( str_title, @@ -527,12 +604,12 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // address - stellar_hashupdate_address(msg->inflation_destination_account.bytes); + stellar_hashupdate_address(inflation_destination_account_bytes); } // Clear flags @@ -559,8 +636,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } memset(rows, 0, sizeof(rows)); row_idx = 0; @@ -593,8 +670,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } memset(rows, 0, sizeof(rows)); row_idx = 0; @@ -666,8 +743,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } memset(rows, 0, sizeof(rows)); row_idx = 0; @@ -696,8 +773,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) NULL ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } memset(rows, 0, sizeof(rows)); row_idx = 0; @@ -738,8 +815,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } } if (msg->signer_type == 1) { @@ -755,8 +832,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("screen)") ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } } if (msg->signer_type == 2) { @@ -772,8 +849,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("screen)") ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } } @@ -792,8 +869,8 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } memset(rows, 0, sizeof(rows)); row_idx = 0; @@ -809,11 +886,18 @@ void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) +bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(6); @@ -840,8 +924,16 @@ void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) strlcat(str_amount_row, str_amount, sizeof(str_amount_row)); } + // Validate destination account and convert to bytes + uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) { + stellar_signingAbort(_("User canceled")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Invalid asset issuer")); + return false; + } + // Display full issuer address - const char **str_addr_rows = stellar_lineBreakAddress(msg->asset.issuer.bytes); + const char **str_addr_rows = stellar_lineBreakAddress(asset_issuer_bytes); stellar_layoutTransactionDialog( str_title, @@ -851,8 +943,8 @@ void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: asset @@ -862,11 +954,18 @@ void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) +bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(7); @@ -883,7 +982,14 @@ void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) char str_asset_row[32]; strlcpy(str_asset_row, msg->asset_code, sizeof(str_asset_row)); - const char **str_trustor_rows = stellar_lineBreakAddress(msg->trusted_account.bytes); + // Validate account and convert to bytes + uint8_t trusted_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->trusted_account, trusted_account_bytes)) { + stellar_signingAbort(_("Invalid trusted account")); + return false; + } + + const char **str_trustor_rows = stellar_lineBreakAddress(trusted_account_bytes); // By: G... char str_by[32]; @@ -898,12 +1004,12 @@ void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) str_trustor_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: trustor account (the account being allowed to access the asset) - stellar_hashupdate_address(msg->trusted_account.bytes); + stellar_hashupdate_address(trusted_account_bytes); // asset type stellar_hashupdate_uint32(msg->asset_type); // asset code @@ -924,15 +1030,29 @@ void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) +bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(8); - const char **str_destination_rows = stellar_lineBreakAddress(msg->destination_account.bytes); + // Validate account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + + const char **str_destination_rows = stellar_lineBreakAddress(destination_account_bytes); stellar_layoutTransactionDialog( _("Merge Account"), @@ -942,20 +1062,27 @@ void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) str_destination_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: destination account - stellar_hashupdate_address(msg->destination_account.bytes); + stellar_hashupdate_address(destination_account_bytes); // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmManageDataOp(StellarManageDataOp *msg) +bool stellar_confirmManageDataOp(StellarManageDataOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(10); @@ -978,8 +1105,8 @@ void stellar_confirmManageDataOp(StellarManageDataOp *msg) str_key_lines[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Confirm value by displaying sha256 hash since this can contain non-printable characters @@ -998,8 +1125,8 @@ void stellar_confirmManageDataOp(StellarManageDataOp *msg) str_hash_lines[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } } @@ -1018,11 +1145,18 @@ void stellar_confirmManageDataOp(StellarManageDataOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) +bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) { - stellar_confirmSourceAccount(msg->has_source_account, msg->source_account.bytes); + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + // Hash: operation type stellar_hashupdate_uint32(11); @@ -1037,8 +1171,8 @@ void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) NULL ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); - return; + stellar_signingAbort(_("User canceled")); + return false; } // Hash: bump to @@ -1046,12 +1180,17 @@ void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) // At this point, the operation is confirmed stellar_activeTx.confirmed_operations++; + return true; } -void stellar_signingAbort() +void stellar_signingAbort(const char *reason) { + if (!reason) { + reason = _("Unknown error"); + } + stellar_signing = false; - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ProcessError, reason); layoutHome(); } @@ -1207,8 +1346,6 @@ const char **stellar_lineBreakAddress(uint8_t *addrbytes) void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len) { char str_asset_code[12 + 1]; - // Full asset issuer string - char str_asset_issuer[56+1]; // truncated asset issuer, final length depends on length of asset code char str_asset_issuer_trunc[13 + 1]; @@ -1216,8 +1353,11 @@ void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t l memset(str_asset_code, 0, sizeof(str_asset_code)); memset(str_asset_issuer_trunc, 0, sizeof(str_asset_issuer_trunc)); - // Get string representation of address - stellar_publicAddressAsStr(asset->issuer.bytes, str_asset_issuer, sizeof(str_asset_issuer)); + // Validate issuer account for non-native assets + if (asset->type != 0 && !stellar_validateAddress(asset->issuer)) { + stellar_signingAbort(_("Invalid asset issuer")); + return; + } // Native asset if (asset->type == 0) { @@ -1229,7 +1369,7 @@ void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t l strlcpy(str_formatted, str_asset_code, len); // Truncate issuer to 13 chars - memcpy(str_asset_issuer_trunc, str_asset_issuer, 13); + memcpy(str_asset_issuer_trunc, asset->issuer, 13); } // 12-character custom if (asset->type == 2) { @@ -1237,7 +1377,7 @@ void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t l strlcpy(str_formatted, str_asset_code, len); // Truncate issuer to 5 characters - memcpy(str_asset_issuer_trunc, str_asset_issuer, 5); + memcpy(str_asset_issuer_trunc, asset->issuer, 5); } // Issuer is read the same way for both types of custom assets if (asset->type == 1 || asset->type == 2) { @@ -1267,6 +1407,65 @@ size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen) return 56; } +/** + * Stellar account string is a base32-encoded string that starts with "G" + * + * It decodes to the following format: + * Byte 0 - always 0x30 ("G" when base32 encoded), version byte indicating a public key + * Bytes 1-33 - 32-byte public key bytes + * Bytes 34-35 - 2-byte CRC16 checksum of the version byte + public key bytes (first 33 bytes) + * + * Note that the stellar "seed" (private key) also uses this format except the version byte + * is 0xC0 which encodes to "S" in base32 + */ +bool stellar_validateAddress(const char *str_address) +{ + bool valid = false; + uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; + + if (strlen(str_address) != STELLAR_ADDRESS_SIZE) { + return false; + } + + // Check that it decodes correctly + uint8_t *ret = base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, sizeof(decoded), BASE32_ALPHABET_RFC4648); + valid = (ret != NULL); + + // ... and that version byte is 0x30 + if (valid && decoded[0] != 0x30) { + valid = false; + } + + // ... and that checksums match + uint16_t checksum_expected = stellar_crc16(decoded, 33); + uint16_t checksum_actual = (decoded[34] << 8) | decoded[33]; // unsigned short (little endian) + if (valid && checksum_expected != checksum_actual) { + valid = false; + } + + memzero(decoded, sizeof(decoded)); + return valid; +} + +/** + * Converts a string address (G...) to the 32-byte raw address + */ +bool stellar_getAddressBytes(char* str_address, uint8_t *out_bytes) +{ + uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; + + // Ensure address is valid + if (!stellar_validateAddress(str_address)) return false; + + base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, sizeof(decoded), BASE32_ALPHABET_RFC4648); + + // The 32 bytes with offset 1-33 represent the public key + memcpy(out_bytes, &decoded[1], 32); + + memzero(decoded, sizeof(decoded)); + return true; +} + /* * CRC16 implementation compatible with the Stellar version * Ported from this implementation: http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java.html @@ -1406,6 +1605,13 @@ void stellar_hashupdate_asset(StellarAssetType *asset) { stellar_hashupdate_uint32(asset->type); + // For non-native assets, validate issuer account and convert to bytes + uint8_t issuer_bytes[STELLAR_KEY_SIZE]; + if (asset->type != 0 && !stellar_getAddressBytes(asset->issuer, issuer_bytes)) { + stellar_signingAbort(_("Invalid asset issuer")); + return; + } + // 4-character asset code if (asset->type == 1) { char code4[4+1]; @@ -1413,7 +1619,7 @@ void stellar_hashupdate_asset(StellarAssetType *asset) strlcpy(code4, asset->code, sizeof(code4)); stellar_hashupdate_bytes((uint8_t *)code4, 4); - stellar_hashupdate_address(asset->issuer.bytes); + stellar_hashupdate_address(issuer_bytes); } // 12-character asset code @@ -1423,7 +1629,7 @@ void stellar_hashupdate_asset(StellarAssetType *asset) strlcpy(code12, asset->code, sizeof(code12)); stellar_hashupdate_bytes((uint8_t *)code12, 12); - stellar_hashupdate_address(asset->issuer.bytes); + stellar_hashupdate_address(issuer_bytes); } } @@ -1475,7 +1681,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_addr_rows[2] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); + stellar_signingAbort(_("User canceled")); return; } @@ -1529,7 +1735,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[4] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); + stellar_signingAbort(_("User canceled")); return; } @@ -1577,7 +1783,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[3] ); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(); + stellar_signingAbort(_("User canceled")); return; } } diff --git a/firmware/stellar.h b/firmware/stellar.h index 81b287a35f..c7ab4fd0bd 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -23,6 +23,14 @@ #include "crypto.h" #include "messages.pb.h" #include "fsm.h" +#include "base32.h" + +// 56 character base-32 encoded string +#define STELLAR_ADDRESS_SIZE 56 +// Decodes to 35 bytes +#define STELLAR_ADDRESS_SIZE_RAW 35 +// Raw key size is 32 bytes +#define STELLAR_KEY_SIZE 32 typedef struct { // BIP32 path to the address being used for signing @@ -44,18 +52,19 @@ typedef struct { // Signing process void stellar_signingInit(StellarSignTx *tx); -void stellar_signingAbort(void); -void stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); -void stellar_confirmPaymentOp(StellarPaymentOp *msg); -void stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); -void stellar_confirmManageOfferOp(StellarManageOfferOp *msg); -void stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); -void stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg); -void stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg); -void stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg); -void stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); -void stellar_confirmManageDataOp(StellarManageDataOp *msg); -void stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); +void stellar_signingAbort(const char *reason); +bool stellar_confirmSourceAccount(bool has_source_account, char *str_account); +bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); +bool stellar_confirmPaymentOp(StellarPaymentOp *msg); +bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); +bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg); +bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); +bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg); +bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg); +bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg); +bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); +bool stellar_confirmManageDataOp(StellarManageDataOp *msg); +bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); // Layout void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); @@ -87,6 +96,8 @@ void stellar_format_stroops(uint64_t number, char *out, size_t outlen); void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len); void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); +bool stellar_validateAddress(const char *str_address); +bool stellar_getAddressBytes(char* str_address, uint8_t *out_bytes); uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); #endif \ No newline at end of file From 8f6a2045e678be01f8b1bf8245d0e862d548ecd9 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 25 Jun 2018 17:09:52 +0100 Subject: [PATCH 0904/1154] build: Refactor Docker build --- Dockerfile | 5 ++- build.sh | 75 +++---------------------------------- script/cibuild | 4 +- script/fingerprint | 41 ++++++++++++++++++++ script/fullbuild | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 72 deletions(-) create mode 100755 script/fingerprint create mode 100755 script/fullbuild diff --git a/Dockerfile b/Dockerfile index 4debc36f53..b5a3b7c3f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,10 @@ RUN apt-get update && \ ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -RUN unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d /usr + +# use zipfile module to extract files world-readable +RUN python3 -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc + RUN pip3 install "protobuf==${PROTOBUF_VERSION}" ecdsa RUN ln -s python3 /usr/bin/python diff --git a/build.sh b/build.sh index 005ec9f883..81dc2a8dc5 100755 --- a/build.sh +++ b/build.sh @@ -3,74 +3,9 @@ set -e IMAGE=trezor-mcu-build -BOOTLOADER_TAG=${1:-master} -FIRMWARE_TAG=${2:-master} -REPOSITORY=${3:-trezor} +BOOTLOADER_COMMIT=${1:-HEAD} +FIRMWARE_COMMIT=${2:-HEAD} -if [ "$REPOSITORY" = "local" ]; then - REPOSITORY=file:///local/ -else - REPOSITORY=https://github.com/$REPOSITORY/trezor-mcu.git -fi - -BOOTLOADER_BINFILE=build/bootloader-$BOOTLOADER_TAG.bin -BOOTLOADER_ELFFILE=build/bootloader-$BOOTLOADER_TAG.elf - -FIRMWARE_BINFILE=build/trezor-$FIRMWARE_TAG.bin -FIRMWARE_ELFFILE=build/trezor-$FIRMWARE_TAG.elf - -docker build -t $IMAGE . - -echo -echo "STARTING BUILD:" -echo -echo "Building bootloader '$BOOTLOADER_TAG' + firmware '$FIRMWARE_TAG' from repo: $REPOSITORY" -echo - -docker run -i -t -v $(pwd):/local -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ - cd /tmp && \ - git clone $REPOSITORY trezor-mcu-bl && \ - cd trezor-mcu-bl && \ - git checkout $BOOTLOADER_TAG && \ - git submodule update --init --recursive && \ - make -C vendor/libopencm3 && \ - make && \ - make -C bootloader align && \ - cp bootloader/bootloader.bin /$BOOTLOADER_BINFILE && \ - cp bootloader/bootloader.elf /$BOOTLOADER_ELFFILE && \ - cd /tmp && \ - git clone $REPOSITORY trezor-mcu-fw && \ - cd trezor-mcu-fw && \ - git checkout $FIRMWARE_TAG && \ - git submodule update --init --recursive && \ - make -C vendor/libopencm3 && \ - make -C vendor/nanopb/generator/proto && \ - make -C firmware/protob && \ - make && \ - cp /tmp/trezor-mcu-bl/bootloader/bootloader.bin bootloader/bootloader.bin - make -C firmware sign && \ - cp firmware/trezor.bin /$FIRMWARE_BINFILE && \ - cp firmware/trezor.elf /$FIRMWARE_ELFFILE - " - -echo -echo "FINISHED BUILD" -echo - -/usr/bin/env python -c " -from __future__ import print_function -import hashlib -import sys -for arg in sys.argv[1:]: - (fn, fprint_start, hashing, max_size) = arg.split(':') - fprint_start = int(fprint_start) - max_size = int(max_size) - data = open(fn, 'rb').read() - if hashing == 'd': - fprint = hashlib.sha256(hashlib.sha256(data[fprint_start:]).digest()).hexdigest() - else: - fprint = hashlib.sha256(data[fprint_start:]).hexdigest() - print('Filename :', fn) - print('Fingerprint :', fprint) - print('Size : %d bytes (out of %d maximum)' % (len(data), max_size)) -" $BOOTLOADER_BINFILE:0:d:32768 $FIRMWARE_BINFILE:256:s:491520 +docker build -t "$IMAGE" . +docker run -it -v $(pwd):/src:z --user="$(stat -c "%u:%g" .)" "$IMAGE" \ + /src/script/fullbuild "$BOOTLOADER_COMMIT" "$FIRMWARE_COMMIT" diff --git a/script/cibuild b/script/cibuild index 3b13af97fb..2c2382a8e7 100755 --- a/script/cibuild +++ b/script/cibuild @@ -14,9 +14,11 @@ else fi make + if [ "$EMULATOR" != 1 ]; then - make -C bootloader + make -C bootloader align fi + make -C vendor/nanopb/generator/proto make -C firmware/protob diff --git a/script/fingerprint b/script/fingerprint new file mode 100755 index 0000000000..de9d90ed5b --- /dev/null +++ b/script/fingerprint @@ -0,0 +1,41 @@ +#!/usr/bin/env python +from __future__ import print_function + +import binascii +import hashlib + + +def H(x): + return hashlib.sha256(x).digest() + + +def compute_fingerprint(x, double): + digest = H(H(x)) if double else H(x) + return binascii.hexlify(digest).decode() + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + + parser.add_argument("file", type=argparse.FileType("rb"), + help="input file") + parser.add_argument("--offset", type=int, default=0, + help="skip bytes at start of input") + parser.add_argument("--max-size", type=int, + help="maximum input file size") + parser.add_argument("--double", action="store_true", + help="use SHA-256d instead of SHA-256") + + args = parser.parse_args() + + data = args.file.read() + size = len(data) + fingerprint = compute_fingerprint(data[args.offset:], args.double) + + print("Filename :", args.file.name) + print("Fingerprint :", fingerprint) + + print("Size : {} bytes (out of {} maximum)" + .format(size, args.max_size)) diff --git a/script/fullbuild b/script/fullbuild new file mode 100755 index 0000000000..834d4e2538 --- /dev/null +++ b/script/fullbuild @@ -0,0 +1,93 @@ +#!/bin/bash + +# script/build: Build the TREZOR firmware in a clean working tree. +# + +set -eu + +cd "$(dirname "$0")/.." + +readonly ARTIFACT_EXTENSIONS=(bin elf) +readonly BUILD_DIR="$(readlink -f build)" + +readonly BOOTLOADER_DIR="$BUILD_DIR/bootloader" +readonly BOOTLOADER_FILENAME="bootloader/bootloader.bin" +readonly BOOTLOADER_PATH="$BOOTLOADER_DIR/$BOOTLOADER_FILENAME" + +readonly FIRMWARE_DIR="$BUILD_DIR/firmware" +readonly FIRMWARE_FILENAME="firmware/trezor.bin" +readonly FIRMWARE_PATH="$FIRMWARE_DIR/$FIRMWARE_FILENAME" + +worktree_setup() { + local path="$1" + local commit="$2" + + rm -rf "$path" + git clone -n --reference=. . "$path" --recurse-submodules + + # Use `git rev-parse` so that we can use any reference from the working repository. + git -C "$path" checkout "$(git rev-parse "$commit")" + + ( cd "$path" && script/setup ) +} + +worktree_build() { + local path="$1" + + ( cd "$path" && script/cibuild ) +} + +worktree_copy() { + local path="$1" + local filename="$2" + local pattern="$3" + + local describe="$(git -C "$path" describe --tags --match "$pattern")" + + local src="$path/$filename" + + local basename="$(basename "$filename")" + local dest="$BUILD_DIR/${basename%.*}-$describe.${basename##*.}" + + for extension in "${ARTIFACT_EXTENSIONS[@]}"; do + install -Dm0644 \ + "${src%.*}.$extension" \ + "${dest%.*}.$extension" + done + + printf "%s" "$dest" +} + +main() { + local bootloader_commit="$1" + local firmware_commit="$2" + + worktree_setup "$BOOTLOADER_DIR" "$bootloader_commit" + worktree_build "$BOOTLOADER_DIR" + + local bootloader_path="$(worktree_copy \ + "$BOOTLOADER_DIR" \ + "$BOOTLOADER_FILENAME" \ + "bl*")" + + worktree_setup "$FIRMWARE_DIR" "$firmware_commit" + cp "$BOOTLOADER_PATH" "$FIRMWARE_DIR/$BOOTLOADER_FILENAME" + worktree_build "$FIRMWARE_DIR" + + local firmware_path="$(worktree_copy \ + "$FIRMWARE_DIR" \ + "$FIRMWARE_FILENAME" \ + "v*")" + + printf "\n\n"; script/fingerprint \ + "$bootloader_path" \ + --max-size 32768 \ + --double + + printf "\n\n"; script/fingerprint \ + "$firmware_path" \ + --offset 256 \ + --max-size 491520 +} + +main "$@" From 67852dcaba370cf3bca9a2e4f80257c5192e3062 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 25 Jun 2018 20:13:07 +0100 Subject: [PATCH 0905/1154] script: Add toolchain-{download,run} Add scripts to download, verify and use GNU Arm Embedded 5 2016q2. 2016q2 (SVN revision 237715) generates identical output to Debian Stretch used by Docker build (SVN revision 241155). --- script/toolchain-download | 54 +++++++++++++++++++++++++++++++++++++++ script/toolchain-run | 18 +++++++++++++ vendor/.gitignore | 4 +++ 3 files changed, 76 insertions(+) create mode 100755 script/toolchain-download create mode 100755 script/toolchain-run create mode 100644 vendor/.gitignore diff --git a/script/toolchain-download b/script/toolchain-download new file mode 100755 index 0000000000..b5438037b5 --- /dev/null +++ b/script/toolchain-download @@ -0,0 +1,54 @@ +#!/bin/bash + +# script/toolchain-download: Download and extract the GNU Arm Embedded toolchain +# for building the TREZOR firmware. + +set -e + +cd "$(dirname "$0")/../vendor" + +readonly URL="https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q2-update/+download/gcc-arm-none-eabi-5_4-2016q2-20160622-linux.tar.bz2" +readonly SHA256SUM="9910b6b5df12efe564dbb3856bf1599d4c16178a6f28bd8a23c9e5c3edc219e4" + +readonly FILENAME="$(basename "$URL")" +readonly DIRECTORY="gcc-arm-none-eabi-5_4-2016q2" + +if [ "$(uname)" != "Linux" ]; then + printf "Unsupported platform\n" >&2 + exit 1 +fi + +validate_download() { + printf "$SHA256SUM $FILENAME" | sha256sum -c +} + +download_file() { + curl -LC- "$URL" -o "$FILENAME" +} + +extract_download() { + local temporary_dir="$(mktemp -d ./toolchain.XXXXXXXXXX)" + trap "rm -rf $temporary_dir" EXIT + + tar -xf "$FILENAME" -C "$temporary_dir" + mv "$temporary_dir/$DIRECTORY" . + rm -f "$FILENAME" +} + +if [ ! -d "$DIRECTORY" ]; then + if ! validate_download; then + download_file + validate_download + fi + + extract_download +fi + +# init toolchain as repository so Git will skip it +git init -q "$DIRECTORY" + +# update toolchain symlink +ln -snf "$DIRECTORY" toolchain + +# sanity-check extracted toolchain +toolchain/bin/arm-none-eabi-gcc --version >/dev/null diff --git a/script/toolchain-run b/script/toolchain-run new file mode 100755 index 0000000000..09e2a63d87 --- /dev/null +++ b/script/toolchain-run @@ -0,0 +1,18 @@ +#!/bin/bash + +# script/toolchain-run: Run command with downloaded GNU Arm Embedded toolchain. +# + +set -e + +readonly TOOLCHAIN_RELATIVE_DIR="vendor/toolchain" +readonly TOOLCHAIN_DIR="$(readlink -f "$(dirname "$0")/../$TOOLCHAIN_RELATIVE_DIR")" + +if [ ! -d "$TOOLCHAIN_DIR" ]; then + printf "Could not find toolchain in %s.\n" "$TOOLCHAIN_RELATIVE_DIR" >&2 + printf "Run script/toolchain-download to download it.\n" >&2 + exit 1 +fi + +export PATH="$TOOLCHAIN_DIR/bin:$PATH" +exec "$@" diff --git a/vendor/.gitignore b/vendor/.gitignore new file mode 100644 index 0000000000..47acdc5484 --- /dev/null +++ b/vendor/.gitignore @@ -0,0 +1,4 @@ +# toolchain-download +gcc-arm-none-eabi-* +toolchain +toolchain.*/ From 7949911748019d9769d61afd935258f421f92871 Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 25 Jun 2018 20:29:18 +0100 Subject: [PATCH 0906/1154] Makefile.include: Hide command invocation unless V=1 --- Makefile | 5 ++++- Makefile.include | 34 ++++++++++++++++++++++++---------- firmware/Makefile | 3 ++- firmware/protob/Makefile | 15 +++++++++++---- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index f77970f549..2d11f28ea4 100644 --- a/Makefile +++ b/Makefile @@ -24,10 +24,13 @@ OBJS += gen/bitmaps.o OBJS += gen/fonts.o libtrezor.a: $(OBJS) - $(AR) rcs libtrezor.a $(OBJS) include Makefile.include +libtrezor.a: + @printf " AR $@\n" + $(Q)$(AR) rcs $@ $^ + .PHONY: vendor vendor: diff --git a/Makefile.include b/Makefile.include index 9eca4fa482..cc517be78e 100644 --- a/Makefile.include +++ b/Makefile.include @@ -1,6 +1,10 @@ TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3 +ifneq ($(V),1) +Q := @ +endif + PYTHON ?= python ifeq ($(EMULATOR),1) @@ -152,34 +156,44 @@ release: $(NAME).bin xxd -p $(NAME)-$(APPVER).bin | tr -d '\n' > $(NAME)-$(APPVER).bin.hex $(NAME).bin: $(NAME).elf - $(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin + @printf " OBJCOPY $@\n" + $(Q)$(OBJCOPY) -Obinary $(NAME).elf $(NAME).bin $(NAME).hex: $(NAME).elf - $(OBJCOPY) -Oihex $(NAME).elf $(NAME).hex + @printf " OBJCOPY $@\n" + $(Q)$(OBJCOPY) -Oihex $(NAME).elf $(NAME).hex $(NAME).srec: $(NAME).elf - $(OBJCOPY) -Osrec $(NAME).elf $(NAME).srec + @printf " OBJCOPY $@\n" + $(Q)$(OBJCOPY) -Osrec $(NAME).elf $(NAME).srec $(NAME).list: $(NAME).elf - $(OBJDUMP) -S $(NAME).elf > $(NAME).list + @printf " OBJDUMP $@\n" + $(Q)$(OBJDUMP) -S $(NAME).elf > $(NAME).list $(NAME).elf: $(OBJS) $(LDSCRIPT) $(LIBDEPS) - $(LD) -o $(NAME).elf $(OBJS) $(LDLIBS) $(LDFLAGS) + @printf " LD $@\n" + $(Q)$(LD) -o $(NAME).elf $(OBJS) $(LDLIBS) $(LDFLAGS) %.o: %.s Makefile - $(AS) $(CPUFLAGS) -o $@ $< + @printf " AS $@\n" + $(Q)$(AS) $(CPUFLAGS) -o $@ $< %.o: %.c Makefile - $(CC) $(CFLAGS) -MMD -MP -o $@ -c $< + @printf " CC $@\n" + $(Q)$(CC) $(CFLAGS) -MMD -MP -o $@ -c $< %.small.o: %.c Makefile - $(CC) $(CFLAGS) -MMD -MP -o $@ -c $< + @printf " CC $@\n" + $(Q)$(CC) $(CFLAGS) -MMD -MP -o $@ -c $< %.d: %.c Makefile - @$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< + @printf " DEP $@\n" + $(Q)$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< %.small.d: %.c Makefile - @$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< + @printf " DEP $@\n" + $(Q)$(CC) $(CFLAGS) -MM -MP -MG -o $@ $< clean:: rm -f $(OBJS) diff --git a/firmware/Makefile b/firmware/Makefile index 9cd23f6ef0..ac5a5157ee 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -114,7 +114,8 @@ define GENERATE_CODE # $(3) - Additional output files $(1).h $(3): $(1).py $(2) - $(PYTHON) $(1).py + @printf " PYTHON $(1).py\n" + $(Q)$(PYTHON) $(1).py # Serialize build for parallel Make $(1).h: $(3) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 74392afcb1..cffe703a1c 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -1,18 +1,25 @@ +ifneq ($(V),1) +Q := @ +endif + all: messages.pb.c types.pb.c messages_map.h PYTHON ?= python %.pb.c: %.pb %.options - $(PYTHON) ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T + @printf " NANOPB $@\n" + $(Q)$(PYTHON) ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T %.pb: %.proto - protoc -I/usr/include -I. $< -o $@ + @printf " PROTOC $@\n" + $(Q)protoc -I/usr/include -I. $< -o $@ %_pb2.py: %.proto - protoc -I/usr/include -I. $< --python_out=. + @printf " PROTOC $@\n" + $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py types_pb2.py - $(PYTHON) $< | grep -v -e MessageType_Lisk > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Lisk > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From 632e55b1901be3405f793ab2b6650aa574ff9a51 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 27 Jun 2018 18:12:18 +0200 Subject: [PATCH 0907/1154] script: fix whitespace --- script/fullbuild | 30 +++++++++++++++--------------- script/toolchain-download | 6 +++--- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/script/fullbuild b/script/fullbuild index 834d4e2538..85b8290a99 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -50,9 +50,9 @@ worktree_copy() { local dest="$BUILD_DIR/${basename%.*}-$describe.${basename##*.}" for extension in "${ARTIFACT_EXTENSIONS[@]}"; do - install -Dm0644 \ - "${src%.*}.$extension" \ - "${dest%.*}.$extension" + install -Dm0644 \ + "${src%.*}.$extension" \ + "${dest%.*}.$extension" done printf "%s" "$dest" @@ -66,28 +66,28 @@ main() { worktree_build "$BOOTLOADER_DIR" local bootloader_path="$(worktree_copy \ - "$BOOTLOADER_DIR" \ - "$BOOTLOADER_FILENAME" \ - "bl*")" + "$BOOTLOADER_DIR" \ + "$BOOTLOADER_FILENAME" \ + "bl*")" worktree_setup "$FIRMWARE_DIR" "$firmware_commit" cp "$BOOTLOADER_PATH" "$FIRMWARE_DIR/$BOOTLOADER_FILENAME" worktree_build "$FIRMWARE_DIR" local firmware_path="$(worktree_copy \ - "$FIRMWARE_DIR" \ - "$FIRMWARE_FILENAME" \ - "v*")" + "$FIRMWARE_DIR" \ + "$FIRMWARE_FILENAME" \ + "v*")" printf "\n\n"; script/fingerprint \ - "$bootloader_path" \ - --max-size 32768 \ - --double + "$bootloader_path" \ + --max-size 32768 \ + --double printf "\n\n"; script/fingerprint \ - "$firmware_path" \ - --offset 256 \ - --max-size 491520 + "$firmware_path" \ + --offset 256 \ + --max-size 491520 } main "$@" diff --git a/script/toolchain-download b/script/toolchain-download index b5438037b5..6314e5dc8e 100755 --- a/script/toolchain-download +++ b/script/toolchain-download @@ -1,7 +1,7 @@ #!/bin/bash # script/toolchain-download: Download and extract the GNU Arm Embedded toolchain -# for building the TREZOR firmware. +# for building the TREZOR firmware. set -e @@ -37,8 +37,8 @@ extract_download() { if [ ! -d "$DIRECTORY" ]; then if ! validate_download; then - download_file - validate_download + download_file + validate_download fi extract_download From 18f8c0a173723f243bc1ac5f1ba3b57366387bab Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 27 Jun 2018 18:17:44 +0200 Subject: [PATCH 0908/1154] firmware: use full 1M flash --- memory.ld | 4 ++-- memory_app_0.0.0.ld | 4 ++-- memory_app_1.0.0.ld | 4 ++-- memory_app_fastflash.ld | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/memory.ld b/memory.ld index b022e15d3d..0bdd40b1ea 100644 --- a/memory.ld +++ b/memory.ld @@ -1,8 +1,8 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ +/* STM32F205RG - 1024K Flash, 128K RAM */ MEMORY { - rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } diff --git a/memory_app_0.0.0.ld b/memory_app_0.0.0.ld index ce3f3f7cc3..210e1c32d7 100644 --- a/memory_app_0.0.0.ld +++ b/memory_app_0.0.0.ld @@ -1,8 +1,8 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ +/* STM32F205RG - 1024K Flash, 128K RAM */ /* program starts at 0x08010000 */ MEMORY { - rom (rx) : ORIGIN = 0x08004000, LENGTH = 512K - 16K + rom (rx) : ORIGIN = 0x08004000, LENGTH = 1024K - 16K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index a59e5da489..cad296aaf6 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -1,8 +1,8 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ +/* STM32F205RG - 1024K Flash, 128K RAM */ /* program starts at 0x08010000 */ MEMORY { - rom (rx) : ORIGIN = 0x08010000, LENGTH = 512K - 64K + rom (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index fc17e75f25..9e00a54820 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -1,4 +1,5 @@ -/* STM32F205RE - 512K Flash, 128K RAM */ +/* STM32F205RG - 1024K Flash, 128K RAM */ + MEMORY { rom (rx) : ORIGIN = 0x20000000, LENGTH = 32K From ffa6567125b5abaedef3650719291ffa5532df56 Mon Sep 17 00:00:00 2001 From: HackyMiner Date: Thu, 28 Jun 2018 18:00:20 +0900 Subject: [PATCH 0909/1154] Ethersocial Network (ESN) support added (#377) --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index b05661777e..94046ca4fe 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -261,6 +261,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 64: suffix = " ELLA"; break; // Ellaism case 820: suffix = " CLO"; break; // Callisto case 1987: suffix = " EGEM"; break; // EtherGem + case 31102: suffix = " ESN"; break; // Ethersocial Network default : suffix = " UNKN"; break; // unknown chain } } From 9ba3f3f28d2c2a47056636071d68ff11e8a5d8d5 Mon Sep 17 00:00:00 2001 From: Ilan <36084092+ilanolkies@users.noreply.github.com> Date: Thu, 28 Jun 2018 06:27:27 -0300 Subject: [PATCH 0910/1154] RSK checksum address encoding (#376) --- firmware/ethereum.c | 10 +++++++++- firmware/fsm_msg_ethereum.h | 11 ++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 94046ca4fe..329e1b56e9 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -294,7 +294,15 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui if (to_len) { char to_str[41]; - ethereum_address_checksum(to, to_str, false, 0); + + bool rskip60 = false; + // constants from trezor-common/defs/ethereum/networks.json + switch (chain_id) { + case 30: rskip60 = true; break; + case 31: rskip60 = true; break; + } + + ethereum_address_checksum(to, to_str, rskip60, chain_id); memcpy(_to1 + 5, to_str, 10); memcpy(_to2, to_str + 10, 15); memcpy(_to3, to_str + 25, 15); diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 9a20aa8e53..323bced907 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -35,8 +35,17 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) char desc[16]; strlcpy(desc, "Address:", sizeof(desc)); + uint32_t slip44 = msg->address_n[1] & 0x7fffffff; + bool rskip60 = false; + uint32_t chain_id = 0; + // constants from trezor-common/defs/ethereum/networks.json + switch (slip44) { + case 137: rskip60 = true; chain_id = 30; break; + case 37310: rskip60 = true; chain_id = 31; break; + } + char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2, false, 0); + ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, chain_id); if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { return; From 4f512cff13baaf98542fd859da91686a15647c06 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 10 Jul 2018 16:04:16 +0200 Subject: [PATCH 0911/1154] travis: add protobuf to pipfile, to enable building new python-trezor --- Pipfile | 1 + Pipfile.lock | 67 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/Pipfile b/Pipfile index fa6c235957..4f11b4fc27 100644 --- a/Pipfile +++ b/Pipfile @@ -9,3 +9,4 @@ trezor = {git = "https://github.com/trezor/python-trezor", editable = true, ref pytest = "*" mock = "*" typing = "*" +protobuf = "==3.4.0" diff --git a/Pipfile.lock b/Pipfile.lock index e9c200aaa4..eab7261173 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "83b71604a8624c27e2076b38af223d180479f5511661e7642fe9faf00d4e53f3" + "sha256": "495d8a64b9cfa1479cf756fc05dddbf8ca34a12186478ee46a7fa8aba140e0cb" }, "pipfile-spec": 6, "requires": {}, @@ -14,6 +14,13 @@ ] }, "default": { + "atomicwrites": { + "hashes": [ + "sha256:240831ea22da9ab882b551b31d4225591e5e447a68c5e188db5b89ca1d487585", + "sha256:a24da68318b08ac9c9c45029f4a10371ab5b20e4226738e150e6e7c571630ae6" + ], + "version": "==1.1.5" + }, "attrs": { "hashes": [ "sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265", @@ -51,10 +58,10 @@ }, "idna": { "hashes": [ - "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", - "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" + "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", + "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" ], - "version": "==2.6" + "version": "==2.7" }, "libusb1": { "hashes": [ @@ -78,11 +85,11 @@ }, "more-itertools": { "hashes": [ - "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea", - "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e", - "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44" + "sha256:2b6b9893337bfd9166bee6a62c2b0c9fe7735dcf85948b387ec8cba30e85d8e8", + "sha256:6703844a52d3588f951883005efcf555e49566a48afd4db4e965d69b883980d3", + "sha256:a18d870ef2ffca2b8463c0070ad17b5978056f403fb64e3f15fe62a52db21cc0" ], - "version": "==4.1.0" + "version": "==4.2.0" }, "pbkdf2": { "hashes": [ @@ -92,10 +99,10 @@ }, "pbr": { "hashes": [ - "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19", - "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f" + "sha256:4f2b11d95917af76e936811be8361b2b19616e5ef3b55956a429ec7864378e0c", + "sha256:e0f23b61ec42473723b2fec2f33fb12558ff221ee551962f01dd4de9053c2055" ], - "version": "==4.0.2" + "version": "==4.1.0" }, "pluggy": { "hashes": [ @@ -105,12 +112,26 @@ ], "version": "==0.6.0" }, + "protobuf": { + "hashes": [ + "sha256:1fcb9b704bc2e30767352d86b2664d8f65f8ed49654d7a80e7a150739724e80a", + "sha256:36d871fa54ec039b9153e7cbae1fa52a7cfdcd8105e47fb7efc8292b131d0a5c", + "sha256:41c4555d9754b985352ce5289fa3ba6b21ed715f595111e46e2b90ca53112475", + "sha256:4d4815467f8a61b06d648699842b233017b201f7a16275d680ec5480f10e30e9", + "sha256:5b816951df388f4ab2adbd3f9ae5619b9a5d7033d14b005c345dc3ee88a7faf4", + "sha256:61dbf86993a9312c3a0816b5252079a3943856003bf0380fea3098c929084ad4", + "sha256:9f3be25ad48b051186ee88f9567a3f3f548facd360e0cb62568e2736d9cfda11", + "sha256:ef02609ef445987976a3a26bff77119c518e0915c96661c3a3b17856d0ef6374" + ], + "index": "pypi", + "version": "==3.4.0" + }, "py": { "hashes": [ - "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881", - "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a" + "sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7", + "sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e" ], - "version": "==1.5.3" + "version": "==1.5.4" }, "pyblake2": { "hashes": [ @@ -128,18 +149,18 @@ }, "pytest": { "hashes": [ - "sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8", - "sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526" + "sha256:0453c8676c2bee6feb0434748b068d5510273a916295fd61d306c4f22fbfd752", + "sha256:4b208614ae6d98195430ad6bde03641c78553acee7c83cec2e85d613c0cd383d" ], "index": "pypi", - "version": "==3.5.1" + "version": "==3.6.3" }, "requests": { "hashes": [ - "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", - "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", + "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" ], - "version": "==2.18.4" + "version": "==2.19.1" }, "six": { "hashes": [ @@ -164,10 +185,10 @@ }, "urllib3": { "hashes": [ - "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", - "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", + "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" ], - "version": "==1.22" + "version": "==1.23" } }, "develop": {} From 0febd07dfc16bf9f49a556c587e7c9f8686dd0ad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 16:58:00 +0200 Subject: [PATCH 0912/1154] firmware: update code to use new nested messages in trezor-common --- firmware/Makefile | 9 +- firmware/crypto.c | 4 +- firmware/crypto.h | 5 +- firmware/ethereum.c | 37 +-- firmware/ethereum.h | 2 +- firmware/fsm.c | 48 ++-- firmware/fsm.h | 12 +- firmware/fsm_msg_coin.h | 28 +- firmware/fsm_msg_common.h | 56 ++-- firmware/fsm_msg_crypto.h | 38 +-- firmware/fsm_msg_ethereum.h | 14 +- firmware/fsm_msg_nem.h | 26 +- firmware/fsm_msg_stellar.h | 12 +- firmware/layout2.c | 12 +- firmware/layout2.h | 11 +- firmware/messages.c | 10 +- firmware/nem2.c | 162 ++++++------ firmware/nem2.h | 55 ++-- firmware/nem_mosaics.py | 16 +- firmware/protect.c | 19 +- firmware/protect.h | 4 +- firmware/protob/Makefile | 10 +- firmware/protob/common.options | 3 + firmware/protob/common.proto | 1 + firmware/protob/messages-bitcoin.options | 49 ++++ firmware/protob/messages-bitcoin.proto | 1 + firmware/protob/messages-crypto.options | 38 +++ firmware/protob/messages-crypto.proto | 1 + firmware/protob/messages-debug.options | 15 ++ firmware/protob/messages-debug.proto | 1 + firmware/protob/messages-ethereum.options | 26 ++ firmware/protob/messages-ethereum.proto | 1 + firmware/protob/messages-management.options | 47 ++++ firmware/protob/messages-management.proto | 1 + firmware/protob/messages-nem.options | 48 ++++ firmware/protob/messages-nem.proto | 1 + firmware/protob/messages-stellar.options | 36 +++ firmware/protob/messages-stellar.proto | 1 + firmware/protob/messages.options | 269 -------------------- firmware/protob/messages_map.py | 13 +- firmware/protob/types.options | 81 ------ firmware/protob/types.proto | 1 - firmware/recovery.c | 29 +-- firmware/reset.c | 16 +- firmware/signing.c | 159 ++++++------ firmware/signing.h | 5 +- firmware/stellar.c | 52 ++-- firmware/storage.h | 3 +- firmware/transaction.c | 51 ++-- firmware/transaction.h | 28 +- vendor/trezor-common | 2 +- 51 files changed, 754 insertions(+), 815 deletions(-) create mode 100644 firmware/protob/common.options create mode 120000 firmware/protob/common.proto create mode 100644 firmware/protob/messages-bitcoin.options create mode 120000 firmware/protob/messages-bitcoin.proto create mode 100644 firmware/protob/messages-crypto.options create mode 120000 firmware/protob/messages-crypto.proto create mode 100644 firmware/protob/messages-debug.options create mode 120000 firmware/protob/messages-debug.proto create mode 100644 firmware/protob/messages-ethereum.options create mode 120000 firmware/protob/messages-ethereum.proto create mode 100644 firmware/protob/messages-management.options create mode 120000 firmware/protob/messages-management.proto create mode 100644 firmware/protob/messages-nem.options create mode 120000 firmware/protob/messages-nem.proto create mode 100644 firmware/protob/messages-stellar.options create mode 120000 firmware/protob/messages-stellar.proto delete mode 100644 firmware/protob/types.options delete mode 120000 firmware/protob/types.proto diff --git a/firmware/Makefile b/firmware/Makefile index ac5a5157ee..0f823bd23b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,8 +82,15 @@ OBJS += ../vendor/nanopb/pb_common.o OBJS += ../vendor/nanopb/pb_decode.o OBJS += ../vendor/nanopb/pb_encode.o +OBJS += protob/common.pb.o OBJS += protob/messages.pb.o -OBJS += protob/types.pb.o +OBJS += protob/messages-bitcoin.pb.o +OBJS += protob/messages-crypto.pb.o +OBJS += protob/messages-debug.pb.o +OBJS += protob/messages-ethereum.pb.o +OBJS += protob/messages-management.pb.o +OBJS += protob/messages-nem.pb.o +OBJS += protob/messages-stellar.pb.o OPTFLAGS ?= -Os diff --git a/firmware/crypto.c b/firmware/crypto.c index e538aeb608..1643acb5b1 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -335,7 +335,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le } */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath) +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const MultisigRedeemScriptType_HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; @@ -365,7 +365,7 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { - static const HDNodePathType *ptr[15], *swap; + static const MultisigRedeemScriptType_HDNodePathType *ptr[15], *swap; const uint32_t n = multisig->pubkeys_count; if (n < 1 || n > 15) { return 0; diff --git a/firmware/crypto.h b/firmware/crypto.h index 2f72a48bcf..f6133b3609 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -29,7 +29,8 @@ #include #include "coins.h" #include "hasher.h" -#include "types.pb.h" +#include "messages-bitcoin.pb.h" +#include "messages-crypto.pb.h" #define ser_length_size(len) ((len) < 253 ? 1 : (len) < 0x10000 ? 3 : 5) @@ -51,7 +52,7 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath); +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const MultisigRedeemScriptType_HDNodePathType *hdnodepath); int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 329e1b56e9..87b7f529da 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -34,6 +34,7 @@ #include "gettext.h" #include "ethereum_tokens.h" #include "memzero.h" +#include "messages.pb.h" /* maximum supported chain id. v must fit in an uint32_t. */ #define MAX_CHAIN_ID 2147483630 @@ -190,7 +191,7 @@ static void send_signature(void) keccak_Final(&keccak_ctx, hash); if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); ethereum_signing_abort(); return; } @@ -461,7 +462,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { if (msg->chain_id < 1 || msg->chain_id > MAX_CHAIN_ID) { - fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Chain Id out of bounds")); ethereum_signing_abort(); return; } @@ -475,7 +476,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->tx_type == 1 || msg->tx_type == 6) { tx_type = msg->tx_type; } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Txtype out of bounds")); ethereum_signing_abort(); return; } @@ -485,7 +486,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); ethereum_signing_abort(); return; } @@ -493,7 +494,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) * prevent exceeding the limit we use a stricter limit on data length. */ if (msg->data_length > 16000000) { - fsm_sendFailure(FailureType_Failure_DataError, _("Data length exceeds limit")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Data length exceeds limit")); ethereum_signing_abort(); return; } @@ -502,14 +503,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) data_total = 0; } if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid size of initial chunk")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid size of initial chunk")); ethereum_signing_abort(); return; } // safety checks if (!ethereum_signing_check(msg)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Safety check failed")); ethereum_signing_abort(); return; } @@ -528,16 +529,16 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL); } - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } if (token == NULL && data_total > 0) { layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -546,8 +547,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes, msg->gas_price.size, msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -601,19 +602,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { if (!ethereum_signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); layoutHome(); return; } if (tx->data_chunk.size > data_left) { - fsm_sendFailure(FailureType_Failure_DataError, _("Too much data")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Too much data")); ethereum_signing_abort(); return; } if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Empty data chunk received")); ethereum_signing_abort(); return; } @@ -671,7 +672,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu uint8_t v; if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); return; } @@ -684,7 +685,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu int ethereum_message_verify(EthereumVerifyMessage *msg) { if (msg->signature.size != 65 || msg->address.size != 20) { - fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Malformed data")); return 1; } diff --git a/firmware/ethereum.h b/firmware/ethereum.h index 5327b845fb..374c885e67 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -23,7 +23,7 @@ #include #include #include "bip32.h" -#include "messages.pb.h" +#include "messages-ethereum.pb.h" void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); void ethereum_signing_abort(void); diff --git a/firmware/fsm.c b/firmware/fsm.c index 5997db6a33..5e2dcdf57b 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -58,6 +58,8 @@ #include "supervise.h" #include "stellar.h" +#include "messages-management.pb.h" + // message methods static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); @@ -69,13 +71,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_INITIALIZED \ if (!storage_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ + fsm_sendFailure(Failure_FailureType_Failure_NotInitialized, NULL); \ return; \ } #define CHECK_NOT_INITIALIZED \ if (storage_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ return; \ } @@ -93,7 +95,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_PARAM(cond, errormsg) \ if (!(cond)) { \ - fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ + fsm_sendFailure(Failure_FailureType_Failure_DataError, (errormsg)); \ layoutHome(); \ return; \ } @@ -109,9 +111,9 @@ void fsm_sendSuccess(const char *text) } #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) +void fsm_sendFailureDebug(Failure_FailureType code, const char *text, const char *source) #else -void fsm_sendFailure(FailureType code, const char *text) +void fsm_sendFailure(Failure_FailureType code, const char *text) #endif { if (protectAbortedByCancel) { @@ -127,43 +129,43 @@ void fsm_sendFailure(FailureType code, const char *text) resp->code = code; if (!text) { switch (code) { - case FailureType_Failure_UnexpectedMessage: + case Failure_FailureType_Failure_UnexpectedMessage: text = _("Unexpected message"); break; - case FailureType_Failure_ButtonExpected: + case Failure_FailureType_Failure_ButtonExpected: text = _("Button expected"); break; - case FailureType_Failure_DataError: + case Failure_FailureType_Failure_DataError: text = _("Data error"); break; - case FailureType_Failure_ActionCancelled: + case Failure_FailureType_Failure_ActionCancelled: text = _("Action cancelled by user"); break; - case FailureType_Failure_PinExpected: + case Failure_FailureType_Failure_PinExpected: text = _("PIN expected"); break; - case FailureType_Failure_PinCancelled: + case Failure_FailureType_Failure_PinCancelled: text = _("PIN cancelled"); break; - case FailureType_Failure_PinInvalid: + case Failure_FailureType_Failure_PinInvalid: text = _("PIN invalid"); break; - case FailureType_Failure_InvalidSignature: + case Failure_FailureType_Failure_InvalidSignature: text = _("Invalid signature"); break; - case FailureType_Failure_ProcessError: + case Failure_FailureType_Failure_ProcessError: text = _("Process error"); break; - case FailureType_Failure_NotEnoughFunds: + case Failure_FailureType_Failure_NotEnoughFunds: text = _("Not enough funds"); break; - case FailureType_Failure_NotInitialized: + case Failure_FailureType_Failure_NotInitialized: text = _("Device not initialized"); break; - case FailureType_Failure_PinMismatch: + case Failure_FailureType_Failure_PinMismatch: text = _("PIN mismatch"); break; - case FailureType_Failure_FirmwareError: + case Failure_FailureType_Failure_FirmwareError: text = _("Firmware error"); break; } @@ -192,7 +194,7 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name) coin = coinByName("Bitcoin"); } if (!coin) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid coin name")); layoutHome(); return 0; } @@ -206,7 +208,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, *fingerprint = 0; } if (!storage_getRootNode(&node, curve, true)) { - fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); + fsm_sendFailure(Failure_FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); return 0; } @@ -214,7 +216,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); layoutHome(); return 0; } @@ -230,11 +232,11 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore display_addr += prefixlen; } layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count); - if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + if (protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Address, false)) { return true; } if (protectAbortedByCancel || protectAbortedByInitialize) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return false; } diff --git a/firmware/fsm.h b/firmware/fsm.h index dc80280a61..703be51150 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -20,18 +20,24 @@ #ifndef __FSM_H__ #define __FSM_H__ -#include "messages.pb.h" +#include "messages-bitcoin.pb.h" +#include "messages-crypto.pb.h" +#include "messages-debug.pb.h" +#include "messages-ethereum.pb.h" +#include "messages-management.pb.h" +#include "messages-nem.pb.h" +#include "messages-stellar.pb.h" // message functions void fsm_sendSuccess(const char *text); #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); +void fsm_sendFailureDebug(Failure_FailureType code, const char *text, const char *source); #define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") #else -void fsm_sendFailure(FailureType code, const char *text); +void fsm_sendFailure(Failure_FailureType code, const char *text); #endif void fsm_msgInitialize(Initialize *msg); diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 15942e2be0..7a002ed606 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -20,8 +20,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -165,7 +165,7 @@ void fsm_msgGetAddress(GetAddress *msg) layoutProgress(_("Computing address"), 0); } if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Can't encode address")); layoutHome(); return; } @@ -188,8 +188,8 @@ void fsm_msgGetAddress(GetAddress *msg) if (mismatch) { layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -214,8 +214,8 @@ void fsm_msgSignMessage(SignMessage *msg) CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -232,7 +232,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->has_address = true; hdnode_fill_public_key(node); if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error computing address")); layoutHome(); return; } @@ -240,7 +240,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error signing message")); } layoutHome(); } @@ -255,20 +255,20 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) layoutProgressSwipe(_("Verifying"), 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { layoutVerifyAddress(msg->address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } fsm_sendSuccess(_("Message verified")); } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid signature")); } layoutHome(); } diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index caa9c34b89..c42b5c3ffe 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -61,8 +61,8 @@ void fsm_msgPing(Ping *msg) if (msg->has_button_protection && msg->button_protection) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -74,7 +74,7 @@ void fsm_msgPing(Ping *msg) if (msg->has_passphrase_protection && msg->passphrase_protection) { if (!protectPassphrase()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); return; } } @@ -104,8 +104,8 @@ void fsm_msgChangePin(ChangePin *msg) layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); } } - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -120,7 +120,7 @@ void fsm_msgChangePin(ChangePin *msg) if (protectChangePin()) { fsm_sendSuccess(_("PIN changed")); } else { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); } } layoutHome(); @@ -130,8 +130,8 @@ void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_WipeDevice, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -146,8 +146,8 @@ void fsm_msgGetEntropy(GetEntropy *msg) { #if !DEBUG_RNG layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -168,15 +168,15 @@ void fsm_msgLoadDevice(LoadDevice *msg) CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); layoutHome(); return; } @@ -230,7 +230,7 @@ void fsm_msgCancel(Cancel *msg) recovery_abort(); signing_abort(); ethereum_signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); } void fsm_msgClearSession(ClearSession *msg) @@ -250,32 +250,32 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_language) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_use_passphrase) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_homescreen) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -283,8 +283,8 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_auto_lock_delay_ms) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -331,8 +331,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) if (!dry_run) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -359,8 +359,8 @@ void fsm_msgWordAck(WordAck *msg) void fsm_msgSetU2FCounter(SetU2FCounter *msg) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index c7fbc5cce8..1a3a42433b 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -16,8 +16,8 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { layoutCipherKeyValue(encrypt, msg->key); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -53,8 +53,8 @@ void fsm_msgSignIdentity(SignIdentity *msg) CHECK_INITIALIZED layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -63,7 +63,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -117,7 +117,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error signing identity")); } layoutHome(); } @@ -129,8 +129,8 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) CHECK_INITIALIZED layoutDecryptIdentity(&msg->identity); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -139,7 +139,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -165,7 +165,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) resp->session_key.size = result_size; msg_write(MessageType_MessageType_ECDHSessionKey, resp); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error getting ECDH session key")); } layoutHome(); } @@ -197,14 +197,14 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) hdnode_get_address_raw(node, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutProgressSwipe(_("Encrypting"), 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error encrypting message")); layoutHome(); return; } @@ -238,7 +238,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) bool signing = false; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -246,7 +246,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); } layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); - protectButton(ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); if (display_only) { resp->has_address = false; resp->has_message = false; @@ -270,8 +270,8 @@ void fsm_msgCosiCommit(CosiCommit *msg) CHECK_PARAM(msg->has_data, _("No data provided")); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -310,8 +310,8 @@ void fsm_msgCosiSign(CosiSign *msg) CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 323bced907..15e62b9cd9 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -63,8 +63,8 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -84,21 +84,21 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) CHECK_PARAM(msg->has_message, _("No message provided")); if (ethereum_message_verify(msg) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid signature")); return; } char address[43] = { '0', 'x' }; ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); layoutVerifyAddress(address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h index 25fae20cc8..fb3c964619 100644 --- a/firmware/fsm_msg_nem.h +++ b/firmware/fsm_msg_nem.h @@ -77,7 +77,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } @@ -90,7 +90,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { hdnode_fill_public_key(node); - const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + const NEMSignTx_NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; char address[NEM_ADDRESS_SIZE + 1]; hdnode_get_nem_address(node, common->network, address); @@ -100,37 +100,37 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { } if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } @@ -241,8 +241,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) _("Decrypt message"), _("Confirm address?"), address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -267,7 +267,7 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) size, resp->payload.bytes); if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to decrypt payload")); layoutHome(); return; } @@ -276,8 +276,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index f12ee8e017..4e626d183c 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -8,7 +8,7 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); if (!node) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); return; } @@ -21,8 +21,8 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) NULL, NULL, NULL ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -46,7 +46,7 @@ void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); if (!node) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); return; } @@ -61,8 +61,8 @@ void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) str_pubkey_rows[3], NULL, NULL ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/layout2.c b/firmware/layout2.c index 9e3d42ee14..a046d1cf0b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -244,7 +244,7 @@ void layoutHome(void) system_millis_lock_start = timer_ms(); } -void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) +void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out) { char str_out[32 + 3]; bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); @@ -713,7 +713,7 @@ void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, NULL); } -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { +void layoutNEMTransferMosaic(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { char str_out[32], str_levy[32]; nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); @@ -782,8 +782,8 @@ void layoutNEMMosaicDescription(const char *description) { str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { - const NEMMosaicDefinition *mosaic; +void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint8_t network) { + const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *mosaic; if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic, network)) { mosaic = definition; } else { @@ -798,7 +798,7 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { char str_out[32]; switch (definition->levy) { - case NEMMosaicLevy_MosaicLevy_Percentile: + case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Percentile: bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, @@ -813,7 +813,7 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { NULL); break; - case NEMMosaicLevy_MosaicLevy_Absolute: + case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Absolute: default: nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, diff --git a/firmware/layout2.h b/firmware/layout2.h index 43f1d76a8a..f5743859a8 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -21,12 +21,15 @@ #define __LAYOUT2_H__ #include "layout.h" -#include "types.pb.h" #include "coins.h" #include "bitmaps.h" #include "bignum.h" #include "trezor.h" +#include "messages-bitcoin.pb.h" +#include "messages-crypto.pb.h" +#include "messages-nem.pb.h" + extern void *layoutLast; #if DEBUG_LINK @@ -40,7 +43,7 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); -void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); @@ -60,11 +63,11 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); +void layoutNEMTransferMosaic(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); void layoutNEMMosaicDescription(const char *description); -void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); +void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint8_t network); void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); diff --git a/firmware/messages.c b/firmware/messages.c index b388067fd6..aa947f3f28 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -229,7 +229,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * if (status) { MessageProcessFunc(type, 'i', msg_id, msg_data); } else { - fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); + fsm_sendFailure(Failure_FailureType_Failure_DataError, stream.errmsg); } } @@ -253,11 +253,11 @@ void msg_read_common(char type, const uint8_t *buf, uint32_t len) fields = MessageFields(type, 'i', msg_id); if (!fields) { // unknown message - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Unknown message")); return; } if (msg_size > MSG_IN_SIZE) { // message is too big :( - fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Message too big")); return; } @@ -365,11 +365,11 @@ void msg_read_tiny(const uint8_t *buf, int len) if (status) { msg_tiny_id = msg_id; } else { - fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); + fsm_sendFailure(Failure_FailureType_Failure_DataError, stream.errmsg); msg_tiny_id = 0xFFFF; } } else { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Unknown message")); msg_tiny_id = 0xFFFF; } } diff --git a/firmware/nem2.c b/firmware/nem2.c index 216791a56f..b973136742 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -27,7 +27,7 @@ #include "rng.h" #include "secp256k1.h" -const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { +const char *nem_validate_common(NEMSignTx_NEMTransactionCommon *common, bool inner) { if (!common->has_network) { common->has_network = true; common->network = NEM_NETWORK_MAINNET; @@ -60,7 +60,7 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { return NULL; } -const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { +const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t network) { if (!transfer->has_recipient) return _("No recipient provided"); if (!transfer->has_amount) return _("No amount provided"); @@ -71,7 +71,7 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; if (!mosaic->has_namespace) return _("No mosaic namespace provided"); if (!mosaic->has_mosaic) return _("No mosaic name provided"); @@ -81,7 +81,7 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) return NULL; } -const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network) { +const char *nem_validate_provision_namespace(const NEMSignTx_NEMProvisionNamespace *provision_namespace, uint8_t network) { if (!provision_namespace->has_namespace) return _("No namespace provided"); if (!provision_namespace->has_sink) return _("No rental sink provided"); if (!provision_namespace->has_fee) return _("No rental sink fee provided"); @@ -91,7 +91,7 @@ const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provis return NULL; } -const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) { +const char *nem_validate_mosaic_creation(const NEMSignTx_NEMMosaicCreation *mosaic_creation, uint8_t network) { if (!mosaic_creation->has_definition) return _("No mosaic definition provided"); if (!mosaic_creation->has_sink) return _("No creation sink provided"); if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); @@ -126,7 +126,7 @@ const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creatio return NULL; } -const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change) { +const char *nem_validate_supply_change(const NEMSignTx_NEMMosaicSupplyChange *supply_change) { if (!supply_change->has_namespace) return _("No namespace provided"); if (!supply_change->has_mosaic) return _("No mosaic provided"); if (!supply_change->has_type) return _("No type provided"); @@ -135,19 +135,19 @@ const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_chang return NULL; } -const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation) { +const char *nem_validate_aggregate_modification(const NEMSignTx_NEMAggregateModification *aggregate_modification, bool creation) { if (creation && aggregate_modification->modifications_count == 0) { return _("No modifications provided"); } for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; if (!modification->has_type) return _("No modification type provided"); if (!modification->has_public_key) return _("No cosignatory public key provided"); if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided"); - if (creation && modification->type == NEMModificationType_CosignatoryModification_Delete) { + if (creation && modification->type == NEMSignTx_NEMAggregateModification_NEMCosignatoryModification_NEMModificationType_CosignatoryModification_Delete) { return _("Cannot remove cosignatory when converting account"); } } @@ -155,7 +155,7 @@ const char *nem_validate_aggregate_modification(const NEMAggregateModification * return NULL; } -const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer) { +const char *nem_validate_importance_transfer(const NEMSignTx_NEMImportanceTransfer *importance_transfer) { if (!importance_transfer->has_mode) return _("No mode provided"); if (!importance_transfer->has_public_key) return _("No remote account provided"); if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided"); @@ -163,15 +163,15 @@ const char *nem_validate_importance_transfer(const NEMImportanceTransfer *import return NULL; } -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { +bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { - const NEMMosaic *xem = NULL; + const NEMSignTx_NEMTransfer_NEMMosaic *xem = NULL; bool unknownMosaic = false; - const NEMMosaicDefinition *definitions[transfer->mosaics_count]; + const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definitions[transfer->mosaics_count]; for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; definitions[i] = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); @@ -196,18 +196,18 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; if (mosaic == xem) { continue; @@ -219,20 +219,20 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaic->quantity, &multiplier); } - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } } else { layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } if (transfer->has_payload) { layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, transfer->has_public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -243,14 +243,14 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran desc, _("Confirm transfer to"), transfer->recipient); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) { +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer) { static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; const uint8_t *payload = transfer->payload.bytes; @@ -258,7 +258,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM if (transfer->has_public_key) { if (node == NULL) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); return false; } @@ -277,7 +277,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM buffer); if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to encrypt payload")); return false; } @@ -299,12 +299,12 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM transfer->mosaics_count); if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); return false; } for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; ret = nem_transaction_write_mosaic(context, mosaic->namespace, @@ -312,7 +312,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM mosaic->quantity); if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to attach mosaics")); return false; } } @@ -320,7 +320,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM return true; } -bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { +bool nem_askProvisionNamespace(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -331,19 +331,19 @@ bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProv provision_namespace->has_parent ? provision_namespace->parent : NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), provision_namespace->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) { +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace) { return nem_transaction_create_provision_namespace(context, common->network, common->timestamp, @@ -356,7 +356,7 @@ bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactio provision_namespace->fee); } -bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { +bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -367,12 +367,12 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr mosaic_creation->definition.namespace, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMMosaicDescription(mosaic_creation->definition.description); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -397,13 +397,13 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"), NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } if (mosaic_creation->definition.has_levy) { layoutNEMLevy(&mosaic_creation->definition, common->network); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -427,20 +427,20 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr mosaic_creation->definition.levy_address); } - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) { +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation) { return nem_transaction_create_mosaic_creation(context, common->network, common->timestamp, @@ -463,7 +463,7 @@ bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCom mosaic_creation->fee); } -bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) { +bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -474,7 +474,7 @@ bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupp supply_change->namespace, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -485,25 +485,25 @@ bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupp _("Cancel"), _("Next"), desc, - supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), + supply_change->type == NEMSignTx_NEMMosaicSupplyChange_NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), str_out, _("whole units"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) { +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change) { return nem_transaction_create_mosaic_supply_change(context, common->network, common->timestamp, @@ -516,7 +516,7 @@ bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommo supply_change->delta); } -bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { +bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { if (creation) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), @@ -528,7 +528,7 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -536,16 +536,16 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA char address[NEM_ADDRESS_SIZE + 1]; for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; nem_get_address(modification->public_key.bytes, common->network, address); layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Next"), desc, - modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), + modification->type == NEMSignTx_NEMAggregateModification_NEMCosignatoryModification_NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), address); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -572,20 +572,20 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) { +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification) { bool ret = nem_transaction_create_aggregate_modification(context, common->network, common->timestamp, @@ -597,7 +597,7 @@ bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransac if (!ret) return false; for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; ret = nem_transaction_write_cosignatory_modification(context, modification->type, @@ -613,30 +613,30 @@ bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransac return true; } -bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) { +bool nem_askImportanceTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, - importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), + importance_transfer->mode == NEMSignTx_NEMImportanceTransfer_NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), _("harvesting?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) { +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer) { return nem_transaction_create_importance_transfer(context, common->network, common->timestamp, @@ -654,19 +654,19 @@ bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint desc, cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), address); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } return true; } -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { bool ret; if (cosigning) { ret = nem_transaction_create_multisig_signature(context, @@ -687,16 +687,16 @@ bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *c } if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); return false; } return true; } -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { - const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; + const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; if (nem_mosaicMatches(definition, namespace, mosaic, network)) { return definition; @@ -706,7 +706,7 @@ const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *m return NULL; } -static inline size_t format_amount(const NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { +static inline size_t format_amount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { bignum256 val; memcpy(&val, amnt, sizeof(bignum256)); @@ -725,7 +725,7 @@ static inline size_t format_amount(const NEMMosaicDefinition *definition, const size); } -size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { +size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t mosaics_count) { if (mosaics_count <= 1) { return mosaics_count; } @@ -739,16 +739,16 @@ size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { for (size_t i = 0; i < mosaics_count; i++) { if (skip[i]) continue; - NEMMosaic *mosaic = &mosaics[actual_count]; + NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &mosaics[actual_count]; if (actual_count++ != i) { - memcpy(mosaic, &mosaics[i], sizeof(NEMMosaic)); + memcpy(mosaic, &mosaics[i], sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); } for (size_t j = i + 1; j < mosaics_count; j++) { if (skip[j]) continue; - const NEMMosaic *new_mosaic = &mosaics[j]; + const NEMSignTx_NEMTransfer_NEMMosaic *new_mosaic = &mosaics[j]; if (nem_mosaicCompare(mosaic, new_mosaic) == 0) { skip[j] = true; @@ -757,19 +757,19 @@ size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { } } - NEMMosaic temp; + NEMSignTx_NEMTransfer_NEMMosaic temp; // Sort mosaics for (size_t i = 0; i < actual_count - 1; i++) { - NEMMosaic *a = &mosaics[i]; + NEMSignTx_NEMTransfer_NEMMosaic *a = &mosaics[i]; for (size_t j = i + 1; j < actual_count; j++) { - NEMMosaic *b = &mosaics[j]; + NEMSignTx_NEMTransfer_NEMMosaic *b = &mosaics[j]; if (nem_mosaicCompare(a, b) > 0) { - memcpy(&temp, a, sizeof(NEMMosaic)); - memcpy(a, b, sizeof(NEMMosaic)); - memcpy(b, &temp, sizeof(NEMMosaic)); + memcpy(&temp, a, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); + memcpy(a, b, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); + memcpy(b, &temp, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); } } } @@ -777,14 +777,14 @@ size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { return actual_count; } -void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { +void nem_mosaicFormatAmount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { bignum256 amnt; bn_read_uint64(quantity, &amnt); format_amount(definition, &amnt, multiplier, 0, str_out, size); } -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { +bool nem_mosaicFormatLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { if (!definition->has_levy || !definition->has_fee) { return false; } @@ -793,13 +793,13 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti bn_read_uint64(quantity, &amnt); bn_read_uint64(definition->fee, &fee); - const NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); + const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); switch (definition->levy) { - case NEMMosaicLevy_MosaicLevy_Absolute: + case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Absolute: return format_amount(mosaic, &fee, NULL, 0, str_out, size); - case NEMMosaicLevy_MosaicLevy_Percentile: + case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Percentile: bn_multiply(&fee, &amnt, &secp256k1.prime); return format_amount(mosaic, &amnt, multiplier, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); diff --git a/firmware/nem2.h b/firmware/nem2.h index ed7c90fba1..f26f1220ff 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -23,45 +23,44 @@ #include "nem.h" #include "nem_mosaics.h" -#include "messages.pb.h" -#include "types.pb.h" +#include "messages-nem.pb.h" #include -const char *nem_validate_common(NEMTransactionCommon *common, bool inner); -const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); -const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); -const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); -const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); -const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); -const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); +const char *nem_validate_common(NEMSignTx_NEMTransactionCommon *common, bool inner); +const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t network); +const char *nem_validate_provision_namespace(const NEMSignTx_NEMProvisionNamespace *provision_namespace, uint8_t network); +const char *nem_validate_mosaic_creation(const NEMSignTx_NEMMosaicCreation *mosaic_creation, uint8_t network); +const char *nem_validate_supply_change(const NEMSignTx_NEMMosaicSupplyChange *supply_change); +const char *nem_validate_aggregate_modification(const NEMSignTx_NEMAggregateModification *aggregate_modification, bool creation); +const char *nem_validate_importance_transfer(const NEMSignTx_NEMImportanceTransfer *importance_transfer); -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer, const char *desc); +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer); -bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); +bool nem_askProvisionNamespace(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace, const char *desc); +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace); -bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); +bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation); -bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); +bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change, const char *desc); +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change); -bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); +bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification, const char *desc, bool creation); +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification); -bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); +bool nem_askImportanceTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer, const char *desc); +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer); bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); -size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); -void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); +size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t mosaics_count); +void nem_mosaicFormatAmount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); +bool nem_mosaicFormatLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { strlcpy(str_out, namespace, size); @@ -69,7 +68,7 @@ static inline void nem_mosaicFormatName(const char *namespace, const char *mosai strlcat(str_out, mosaic, size); } -static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { +static inline bool nem_mosaicMatches(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { if (definition->networks_count == 0) { return true; @@ -85,7 +84,7 @@ static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, cons return false; } -static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) { +static inline int nem_mosaicCompare(const NEMSignTx_NEMTransfer_NEMMosaic *a, const NEMSignTx_NEMTransfer_NEMMosaic *b) { size_t namespace_length = strlen(a->namespace); // Ensure that strlen(a->namespace) <= strlen(b->namespace) diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py index 49fc026c12..708790dc66 100755 --- a/firmware/nem_mosaics.py +++ b/firmware/nem_mosaics.py @@ -20,12 +20,12 @@ HEADER_TEMPLATE = """ #ifndef __NEM_MOSAICS_H__ #define __NEM_MOSAICS_H__ -#include "types.pb.h" +#include "messages-nem.pb.h" #define NEM_MOSAIC_DEFINITIONS_COUNT ({count}) -extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; -extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; +extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; +extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; #endif """.lstrip() # noqa: E501 @@ -35,9 +35,9 @@ CODE_TEMPLATE = """ #include "nem_mosaics.h" -const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {code}; +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {code}; -const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; """.lstrip() # noqa: E501 @@ -67,7 +67,7 @@ def format_field(field, value): if field.message_type is not None: raise TypeError elif field.enum_type: - type_name = field.enum_type.name + type_name = field.enum_type.full_name.replace('.', '_') enum_name = field.enum_type.values_by_number[value].name return "{0}_{1}".format(type_name, enum_name) elif hasattr(value, "_values"): @@ -107,7 +107,7 @@ if __name__ == "__main__": os.chdir(os.path.abspath(os.path.dirname(__file__))) sys.path.insert(0, "protob") - import types_pb2 as types + import messages_nem_pb2 messages = json.load(open("defs/nem/nem_mosaics.json")) @@ -118,5 +118,5 @@ if __name__ == "__main__": with open("nem_mosaics.c", "w+") as f: f.write(CODE_TEMPLATE.format( - code=format_messages(messages, types.NEMMosaicDefinition)) + code=format_messages(messages, messages_nem_pb2.NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition)) ) diff --git a/firmware/protect.c b/firmware/protect.c index b66e3520e5..a9f5a1dc0a 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -31,13 +31,14 @@ #include "debug.h" #include "gettext.h" #include "memzero.h" +#include "messages.pb.h" #define MAX_WRONG_PINS 15 bool protectAbortedByCancel = false; bool protectAbortedByInitialize = false; -bool protectButton(ButtonRequestType type, bool confirm_only) +bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only) { ButtonRequest resp; bool result = false; @@ -110,7 +111,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) return result; } -const char *requestPin(PinMatrixRequestType type, const char *text) +const char *requestPin(PinMatrixRequest_PinMatrixRequestType type, const char *text) { PinMatrixRequest resp; memset(&resp, 0, sizeof(PinMatrixRequest)); @@ -186,20 +187,20 @@ bool protectPin(bool use_cached) protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinCancelled, NULL); return false; } wait--; } usbTiny(0); const char *pin; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinCancelled, NULL); return false; } if (!storage_increasePinFails(fails)) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinInvalid, NULL); return false; } if (storage_containsPin(pin)) { @@ -208,7 +209,7 @@ bool protectPin(bool use_cached) return true; } else { protectCheckMaxTry(storage_getPinWait(fails)); - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinInvalid, NULL); return false; } } @@ -217,7 +218,7 @@ bool protectChangePin(void) { static CONFIDENTIAL char pin_compare[17]; - const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + const char *pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); if (!pin) { return false; @@ -225,7 +226,7 @@ bool protectChangePin(void) strlcpy(pin_compare, pin, sizeof(pin_compare)); - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); const bool result = pin && (strncmp(pin_compare, pin, sizeof(pin_compare)) == 0); diff --git a/firmware/protect.h b/firmware/protect.h index 0836f565f3..d8c9cde64f 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -21,9 +21,9 @@ #define __PROTECT_H__ #include -#include "types.pb.h" +#include "messages-management.pb.h" -bool protectButton(ButtonRequestType type, bool confirm_only); +bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only); bool protectPin(bool use_cached); bool protectChangePin(void); bool protectPassphrase(void); diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index cffe703a1c..21af3cde6f 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -2,7 +2,7 @@ ifneq ($(V),1) Q := @ endif -all: messages.pb.c types.pb.c messages_map.h +all: messages_map.h common.pb.c messages-bitcoin.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages_nem_pb2.py PYTHON ?= python @@ -14,12 +14,16 @@ PYTHON ?= python @printf " PROTOC $@\n" $(Q)protoc -I/usr/include -I. $< -o $@ +messages_%_pb2.py: messages-%.proto + @printf " PROTOC $@\n" + $(Q)protoc -I/usr/include -I. $< --python_out=. + %_pb2.py: %.proto @printf " PROTOC $@\n" $(Q)protoc -I/usr/include -I. $< --python_out=. -messages_map.h: messages_map.py messages_pb2.py types_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Lisk > $@ +messages_map.h: messages_map.py messages_pb2.py + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/common.options b/firmware/protob/common.options new file mode 100644 index 0000000000..875029177c --- /dev/null +++ b/firmware/protob/common.options @@ -0,0 +1,3 @@ +HDNodeType.chain_code max_size:32 +HDNodeType.private_key max_size:32 +HDNodeType.public_key max_size:33 diff --git a/firmware/protob/common.proto b/firmware/protob/common.proto new file mode 120000 index 0000000000..1bc14a7384 --- /dev/null +++ b/firmware/protob/common.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/common.proto \ No newline at end of file diff --git a/firmware/protob/messages-bitcoin.options b/firmware/protob/messages-bitcoin.options new file mode 100644 index 0000000000..34e8f6134e --- /dev/null +++ b/firmware/protob/messages-bitcoin.options @@ -0,0 +1,49 @@ +GetPublicKey.address_n max_count:8 +GetPublicKey.ecdsa_curve_name max_size:32 +GetPublicKey.coin_name max_size:21 + +PublicKey.xpub max_size:113 + +GetAddress.address_n max_count:8 +GetAddress.coin_name max_size:21 + +Address.address max_size:130 + +SignTx.coin_name max_size:21 + +SignMessage.address_n max_count:8 +SignMessage.message max_size:1024 +SignMessage.coin_name max_size:21 + +VerifyMessage.address max_size:130 +VerifyMessage.signature max_size:65 +VerifyMessage.message max_size:1024 +VerifyMessage.coin_name max_size:21 + +MessageSignature.address max_size:130 +MessageSignature.signature max_size:65 + +TxAck.TransactionType.inputs max_count:1 +TxAck.TransactionType.bin_outputs max_count:1 +TxAck.TransactionType.outputs max_count:1 +TxAck.TransactionType.extra_data max_size:1024 + +TxAck.TransactionType.TxInputType.address_n max_count:8 +TxAck.TransactionType.TxInputType.prev_hash max_size:32 +TxAck.TransactionType.TxInputType.script_sig max_size:1650 + +TxAck.TransactionType.TxOutputType.address max_size:130 +TxAck.TransactionType.TxOutputType.address_n max_count:8 +TxAck.TransactionType.TxOutputType.op_return_data max_size:80 + +TxAck.TransactionType.TxOutputBinType.script_pubkey max_size:520 + +TxRequest.TxRequestDetailsType.tx_hash max_size:32 + +TxRequest.TxRequestSerializedType.signature max_size:73 +TxRequest.TxRequestSerializedType.serialized_tx max_size:2048 + +MultisigRedeemScriptType.pubkeys max_count:15 +MultisigRedeemScriptType.signatures max_count:15 max_size:73 + +MultisigRedeemScriptType.HDNodePathType.address_n max_count:8 diff --git a/firmware/protob/messages-bitcoin.proto b/firmware/protob/messages-bitcoin.proto new file mode 120000 index 0000000000..5775266a0a --- /dev/null +++ b/firmware/protob/messages-bitcoin.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-bitcoin.proto \ No newline at end of file diff --git a/firmware/protob/messages-crypto.options b/firmware/protob/messages-crypto.options new file mode 100644 index 0000000000..5825b4d350 --- /dev/null +++ b/firmware/protob/messages-crypto.options @@ -0,0 +1,38 @@ +CipherKeyValue.address_n max_count:8 +CipherKeyValue.key max_size:256 +CipherKeyValue.value max_size:1024 +CipherKeyValue.iv max_size:16 + +CipheredKeyValue.value max_size:1024 + +CosiCommit.address_n max_count:8 +CosiCommit.data max_size:32 + +CosiCommitment.commitment max_size:32 +CosiCommitment.pubkey max_size:32 + +CosiSign.address_n max_count:8 +CosiSign.data max_size:32 +CosiSign.global_commitment max_size:32 +CosiSign.global_pubkey max_size:32 + +CosiSignature.signature max_size:32 + +SignIdentity.challenge_hidden max_size:256 +SignIdentity.challenge_visual max_size:256 +SignIdentity.ecdsa_curve_name max_size:32 + +SignedIdentity.address max_size:130 +SignedIdentity.public_key max_size:33 +SignedIdentity.signature max_size:65 + +IdentityType.proto max_size:9 +IdentityType.user max_size:64 +IdentityType.host max_size:64 +IdentityType.port max_size:6 +IdentityType.path max_size:256 + +GetECDHSessionKey.peer_public_key max_size:65 +GetECDHSessionKey.ecdsa_curve_name max_size:32 + +ECDHSessionKey.session_key max_size:65 diff --git a/firmware/protob/messages-crypto.proto b/firmware/protob/messages-crypto.proto new file mode 120000 index 0000000000..9461d737a3 --- /dev/null +++ b/firmware/protob/messages-crypto.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-crypto.proto \ No newline at end of file diff --git a/firmware/protob/messages-debug.options b/firmware/protob/messages-debug.options new file mode 100644 index 0000000000..8e1e6617f8 --- /dev/null +++ b/firmware/protob/messages-debug.options @@ -0,0 +1,15 @@ +DebugLinkDecision.input max_size:33 + +DebugLinkState.layout max_size:1024 +DebugLinkState.pin max_size:10 +DebugLinkState.matrix max_size:10 +DebugLinkState.mnemonic max_size:241 +DebugLinkState.reset_word max_size:12 +DebugLinkState.reset_entropy max_size:128 +DebugLinkState.recovery_fake_word max_size:12 + +DebugLinkLog.bucket max_size:33 +DebugLinkLog.text max_size:256 + +DebugLinkMemory.memory max_size:1024 +DebugLinkMemoryWrite.memory max_size:1024 diff --git a/firmware/protob/messages-debug.proto b/firmware/protob/messages-debug.proto new file mode 120000 index 0000000000..52a032f939 --- /dev/null +++ b/firmware/protob/messages-debug.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-debug.proto \ No newline at end of file diff --git a/firmware/protob/messages-ethereum.options b/firmware/protob/messages-ethereum.options new file mode 100644 index 0000000000..c32f6813ed --- /dev/null +++ b/firmware/protob/messages-ethereum.options @@ -0,0 +1,26 @@ +EthereumSignTx.address_n max_count:8 +EthereumSignTx.nonce max_size:32 +EthereumSignTx.gas_price max_size:32 +EthereumSignTx.gas_limit max_size:32 +EthereumSignTx.to max_size:20 +EthereumSignTx.value max_size:32 +EthereumSignTx.data_initial_chunk max_size:1024 + +EthereumTxRequest.signature_r max_size:32 +EthereumTxRequest.signature_s max_size:32 + +EthereumTxAck.data_chunk max_size:1024 + +EthereumSignMessage.address_n max_count:8 +EthereumSignMessage.message max_size:1024 + +EthereumVerifyMessage.address max_size:20 +EthereumVerifyMessage.signature max_size:65 +EthereumVerifyMessage.message max_size:1024 + +EthereumMessageSignature.address max_size:20 +EthereumMessageSignature.signature max_size:65 + +EthereumGetAddress.address_n max_count:8 + +EthereumAddress.address max_size:20 diff --git a/firmware/protob/messages-ethereum.proto b/firmware/protob/messages-ethereum.proto new file mode 120000 index 0000000000..1795e5e496 --- /dev/null +++ b/firmware/protob/messages-ethereum.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-ethereum.proto \ No newline at end of file diff --git a/firmware/protob/messages-management.options b/firmware/protob/messages-management.options new file mode 100644 index 0000000000..039b1b6d54 --- /dev/null +++ b/firmware/protob/messages-management.options @@ -0,0 +1,47 @@ +Initialize.state max_size:64 + +Features.vendor max_size:33 +Features.device_id max_size:25 +Features.language max_size:17 +Features.label max_size:33 +Features.revision max_size:20 +Features.bootloader_hash max_size:32 +Features.model max_size:17 +Features.fw_vendor max_size:256 +Features.fw_vendor_keys max_size:32 + +ApplySettings.language max_size:17 +ApplySettings.label max_size:33 +ApplySettings.homescreen max_size:1024 + +Ping.message max_size:256 + +Success.message max_size:256 + +Failure.message max_size:256 + +ButtonRequest.data max_size:256 + +PinMatrixAck.pin max_size:10 + +PassphraseAck.passphrase max_size:51 +PassphraseAck.state max_size:64 + +PassphraseStateRequest.state max_size:64 + +LoadDevice.mnemonic max_size:241 +LoadDevice.pin max_size:10 +LoadDevice.language max_size:17 +LoadDevice.label max_size:33 + +ResetDevice.language max_size:17 +ResetDevice.label max_size:33 + +Entropy.entropy max_size:1024 + +EntropyAck.entropy max_size:128 + +RecoveryDevice.language max_size:17 +RecoveryDevice.label max_size:33 + +WordAck.word max_size:12 diff --git a/firmware/protob/messages-management.proto b/firmware/protob/messages-management.proto new file mode 120000 index 0000000000..046a2a6eb4 --- /dev/null +++ b/firmware/protob/messages-management.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-management.proto \ No newline at end of file diff --git a/firmware/protob/messages-nem.options b/firmware/protob/messages-nem.options new file mode 100644 index 0000000000..546c580da1 --- /dev/null +++ b/firmware/protob/messages-nem.options @@ -0,0 +1,48 @@ +NEMGetAddress.address_n max_count:8 + +NEMAddress.address max_size:41 + +NEMDecryptMessage.address_n max_count:8 +NEMDecryptMessage.public_key max_size:32 +NEMDecryptMessage.payload max_size:1072 + +NEMDecryptedMessage.payload max_size:1024 + +NEMSignTx.NEMTransactionCommon.address_n max_count:8 +NEMSignTx.NEMTransactionCommon.signer max_size:32 + +NEMSignTx.NEMTransfer.recipient max_size:41 +NEMSignTx.NEMTransfer.public_key max_size:32 +NEMSignTx.NEMTransfer.payload max_size:1024 +NEMSignTx.NEMTransfer.mosaics max_count:16 + +NEMSignTx.NEMTransfer.NEMMosaic.namespace max_size:145 +NEMSignTx.NEMTransfer.NEMMosaic.mosaic max_size:33 + +NEMSignTx.NEMProvisionNamespace.namespace max_size:65 +NEMSignTx.NEMProvisionNamespace.parent max_size:81 +NEMSignTx.NEMProvisionNamespace.sink max_size:41 + +NEMSignTx.NEMMosaicCreation.sink max_size:41 + +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.name max_size:32 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.ticker max_size:16 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.namespace max_size:145 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.mosaic max_size:33 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_address max_size:41 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_namespace max_size:145 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_mosaic max_size:33 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.description max_size:513 +NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.networks max_count:8 + +NEMSignTx.NEMMosaicSupplyChange.namespace max_size:145 +NEMSignTx.NEMMosaicSupplyChange.mosaic max_size:33 + +NEMSignTx.NEMAggregateModification.modifications max_count:16 + +NEMSignTx.NEMAggregateModification.NEMCosignatoryModification.public_key max_size:32 + +NEMSignTx.NEMImportanceTransfer.public_key max_size:32 + +NEMSignedTx.data max_size:2048 +NEMSignedTx.signature max_size:64 diff --git a/firmware/protob/messages-nem.proto b/firmware/protob/messages-nem.proto new file mode 120000 index 0000000000..228ff1b068 --- /dev/null +++ b/firmware/protob/messages-nem.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-nem.proto \ No newline at end of file diff --git a/firmware/protob/messages-stellar.options b/firmware/protob/messages-stellar.options new file mode 100644 index 0000000000..59cc6c0606 --- /dev/null +++ b/firmware/protob/messages-stellar.options @@ -0,0 +1,36 @@ +StellarAssetType.code max_size:13 +StellarAssetType.issuer max_size:57 +StellarGetAddress.address_n max_count:10 + +StellarAddress.address max_size:57 + +StellarGetPublicKey.address_n max_count:10 + +StellarPublicKey.public_key max_size:32 + +StellarSignTx.address_n max_count:10 +StellarSignTx.network_passphrase max_size:1024 +StellarSignTx.memo_text max_size:29 +StellarSignTx.memo_hash max_size:32 + +StellarPaymentOp.destination_account max_size:57 + +StellarCreateAccountOp.new_account max_size:57 + +StellarPathPaymentOp.destination_account max_size:57 +StellarPathPaymentOp.paths max_count:5 + +StellarSetOptionsOp.inflation_destination_account max_size:57 +StellarSetOptionsOp.home_domain max_size:33 +StellarSetOptionsOp.signer_key max_size:32 + +StellarAllowTrustOp.trusted_account max_size:57 +StellarAllowTrustOp.asset_code max_size:13 + +StellarAccountMergeOp.destination_account max_size:57 + +StellarManageDataOp.key max_size:65 +StellarManageDataOp.value max_size:65 + +StellarSignedTx.public_key max_size:32 +StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint diff --git a/firmware/protob/messages-stellar.proto b/firmware/protob/messages-stellar.proto new file mode 120000 index 0000000000..79eb91585c --- /dev/null +++ b/firmware/protob/messages-stellar.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-stellar.proto \ No newline at end of file diff --git a/firmware/protob/messages.options b/firmware/protob/messages.options index c93f182496..e69de29bb2 100644 --- a/firmware/protob/messages.options +++ b/firmware/protob/messages.options @@ -1,269 +0,0 @@ -Initialize.state max_size:64 - -Features.vendor max_size:33 -Features.device_id max_size:25 -Features.language max_size:17 -Features.label max_size:33 -Features.revision max_size:20 -Features.bootloader_hash max_size:32 -Features.model max_size:17 -Features.fw_vendor max_size:256 -Features.fw_vendor_keys max_size:32 - -ApplySettings.language max_size:17 -ApplySettings.label max_size:33 -ApplySettings.homescreen max_size:1024 - -Ping.message max_size:256 - -Success.message max_size:256 - -Failure.message max_size:256 - -ButtonRequest.data max_size:256 - -PinMatrixAck.pin max_size:10 - -PassphraseAck.passphrase max_size:51 -PassphraseAck.state max_size:64 - -PassphraseStateRequest.state max_size:64 - -Entropy.entropy max_size:1024 - -GetPublicKey.address_n max_count:8 -GetPublicKey.ecdsa_curve_name max_size:32 -GetPublicKey.coin_name max_size:21 - -PublicKey.xpub max_size:113 - -GetAddress.address_n max_count:8 -GetAddress.coin_name max_size:21 - -Address.address max_size:130 - -EthereumGetAddress.address_n max_count:8 -EthereumAddress.address max_size:20 - -LoadDevice.mnemonic max_size:241 -LoadDevice.pin max_size:10 -LoadDevice.language max_size:17 -LoadDevice.label max_size:33 - -ResetDevice.language max_size:17 -ResetDevice.label max_size:33 - -EntropyAck.entropy max_size:128 - -RecoveryDevice.language max_size:17 -RecoveryDevice.label max_size:33 - -WordAck.word max_size:12 - -SignMessage.address_n max_count:8 -SignMessage.message max_size:1024 -SignMessage.coin_name max_size:21 - -VerifyMessage.address max_size:130 -VerifyMessage.signature max_size:65 -VerifyMessage.message max_size:1024 -VerifyMessage.coin_name max_size:21 - -MessageSignature.address max_size:130 -MessageSignature.signature max_size:65 - -EthereumSignMessage.address_n max_count:8 -EthereumSignMessage.message max_size:1024 - -EthereumVerifyMessage.address max_size:20 -EthereumVerifyMessage.signature max_size:65 -EthereumVerifyMessage.message max_size:1024 - -EthereumMessageSignature.address max_size:20 -EthereumMessageSignature.signature max_size:65 - -# deprecated -EncryptMessage skip_message:true -# EncryptMessage.pubkey max_size:33 -# EncryptMessage.message max_size:1024 -# EncryptMessage.address_n max_count:8 -# EncryptMessage.coin_name max_size:21 - -# deprecated -EncryptedMessage skip_message:true -# EncryptedMessage.nonce max_size:33 -# EncryptedMessage.message max_size:1120 -# EncryptedMessage.hmac max_size:8 - -# deprecated -DecryptMessage skip_message:true -# DecryptMessage.address_n max_count:8 -# DecryptMessage.nonce max_size:33 -# DecryptMessage.message max_size:1120 # 1 + 9 + 1024 + 21 + 65 -# DecryptMessage.hmac max_size:8 - -# deprecated -DecryptedMessage skip_message:true -# DecryptedMessage.address max_size:130 -# DecryptedMessage.message max_size:1024 - -CipherKeyValue.address_n max_count:8 -CipherKeyValue.key max_size:256 -CipherKeyValue.value max_size:1024 -CipherKeyValue.iv max_size:16 - -CipheredKeyValue.value max_size:1024 - -# deprecated -EstimateTxSize skip_message:true -# EstimateTxSize.coin_name max_size:21 - -# deprecated -TxSize skip_message:true - -SignTx.coin_name max_size:21 - -EthereumSignTx.address_n max_count:8 -EthereumSignTx.nonce max_size:32 -EthereumSignTx.gas_price max_size:32 -EthereumSignTx.gas_limit max_size:32 -EthereumSignTx.to max_size:20 -EthereumSignTx.value max_size:32 -EthereumSignTx.data_initial_chunk max_size:1024 - -EthereumTxRequest.signature_r max_size:32 -EthereumTxRequest.signature_s max_size:32 - -EthereumTxAck.data_chunk max_size:1024 - -SignIdentity.challenge_hidden max_size:256 -SignIdentity.challenge_visual max_size:256 -SignIdentity.ecdsa_curve_name max_size:32 - -SignedIdentity.address max_size:130 -SignedIdentity.public_key max_size:33 -SignedIdentity.signature max_size:65 - -GetECDHSessionKey.peer_public_key max_size:65 -GetECDHSessionKey.ecdsa_curve_name max_size:32 - -ECDHSessionKey.session_key max_size:65 - -NEMGetAddress.address_n max_count:8 - -NEMAddress.address max_size:41 - -NEMSignedTx.data max_size:2048 -NEMSignedTx.signature max_size:64 - -NEMDecryptMessage.address_n max_count:8 -NEMDecryptMessage.public_key max_size:32 -NEMDecryptMessage.payload max_size:1072 - -NEMDecryptedMessage.payload max_size:1024 - -CosiCommit.address_n max_count:8 -CosiCommit.data max_size:32 - -CosiCommitment.commitment max_size:32 -CosiCommitment.pubkey max_size:32 - -CosiSign.address_n max_count:8 -CosiSign.data max_size:32 -CosiSign.global_commitment max_size:32 -CosiSign.global_pubkey max_size:32 - -CosiSignature.signature max_size:32 - -# Stellar - -StellarGetAddress.address_n max_count:10 - -StellarAddress.address max_size:57 - -StellarGetPublicKey.address_n max_count:10 - -StellarPublicKey.public_key max_size:32 - -StellarSignTx.address_n max_count:10 -StellarSignTx.network_passphrase max_size:1024 -StellarSignTx.source_account max_size:57 -StellarSignTx.memo_text max_size:29 -StellarSignTx.memo_hash max_size:32 - -StellarPaymentOp.source_account max_size:57 -StellarPaymentOp.destination_account max_size:57 - -StellarCreateAccountOp.source_account max_size:57 -StellarCreateAccountOp.new_account max_size:57 - -StellarPathPaymentOp.source_account max_size:57 -StellarPathPaymentOp.destination_account max_size:57 -StellarPathPaymentOp.paths max_count:5 - -StellarManageOfferOp.source_account max_size:57 - -StellarCreatePassiveOfferOp.source_account max_size:57 - -StellarSetOptionsOp.source_account max_size:57 -StellarSetOptionsOp.inflation_destination_account max_size:57 -StellarSetOptionsOp.home_domain max_size:33 -StellarSetOptionsOp.signer_key max_size:32 - -StellarChangeTrustOp.source_account max_size:57 - -StellarAllowTrustOp.source_account max_size:57 -StellarAllowTrustOp.trusted_account max_size:57 -StellarAllowTrustOp.asset_code max_size:13 - -StellarAccountMergeOp.source_account max_size:57 -StellarAccountMergeOp.destination_account max_size:57 - -StellarManageDataOp.source_account max_size:57 -StellarManageDataOp.key max_size:65 -StellarManageDataOp.value max_size:65 - -StellarBumpSequenceOp.source_account max_size:57 - -StellarSignedTx.public_key max_size:32 -StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint - -# deprecated -SimpleSignTx skip_message:true - -# not used in firmware, just in bootloader - -FirmwareErase skip_message:true -FirmwareRequest skip_message:true -FirmwareUpload skip_message:true -SelfTest skip_message:true - -# Lisk will be supported later - -LiskGetAddress skip_message:true -LiskSignTx skip_message:true -LiskGetPublicKey skip_message:true -LiskAddress skip_message:true -LiskSignedTx skip_message:true -LiskPublicKey skip_message:true -LiskSignMessage skip_message:true -LiskMessageSignature skip_message:true -LiskVerifyMessage skip_message:true - -# used only in debug firmware - -DebugLinkDecision.input max_size:33 - -DebugLinkState.layout max_size:1024 -DebugLinkState.pin max_size:10 -DebugLinkState.matrix max_size:10 -DebugLinkState.mnemonic max_size:241 -DebugLinkState.reset_word max_size:12 -DebugLinkState.reset_entropy max_size:128 -DebugLinkState.recovery_fake_word max_size:12 - -DebugLinkLog.bucket max_size:33 -DebugLinkLog.text max_size:256 - -DebugLinkMemory.memory max_size:1024 -DebugLinkMemoryWrite.memory max_size:1024 diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index 00dc2f7ce2..ef98014954 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -1,10 +1,9 @@ #!/usr/bin/env python from collections import defaultdict from messages_pb2 import MessageType - -from types_pb2 import wire_in, wire_out -from types_pb2 import wire_debug_in, wire_debug_out -from types_pb2 import wire_bootloader, wire_tiny +from messages_pb2 import wire_in, wire_out +from messages_pb2 import wire_debug_in, wire_debug_out +from messages_pb2 import wire_bootloader, wire_no_fsm # len("MessageType_MessageType_") - len("_fields") == 17 TEMPLATE = "\t{{ {type} {dir} {msg_id:46} {fields:29} {process_func} }}," @@ -27,14 +26,14 @@ def handle_message(message, extension): options = message.GetOptions() bootloader = options.Extensions[wire_bootloader] - tiny = options.Extensions[wire_tiny] and direction == "i" + no_fsm = options.Extensions[wire_no_fsm] if getattr(options, 'deprecated', None): return '\t// Message %s is deprecated' % short_name if bootloader: return '\t// Message %s is used in bootloader mode only' % short_name - if tiny: - return '\t// Message %s is used in tiny mode' % short_name + if no_fsm: + return '\t// Message %s is not used in FSM' % short_name if direction == "i": process_func = "(void (*)(void *)) fsm_msg%s" % short_name diff --git a/firmware/protob/types.options b/firmware/protob/types.options deleted file mode 100644 index be97685eba..0000000000 --- a/firmware/protob/types.options +++ /dev/null @@ -1,81 +0,0 @@ -HDNodeType.chain_code max_size:32 -HDNodeType.private_key max_size:32 -HDNodeType.public_key max_size:33 - -HDNodePathType.address_n max_count:8 - -TxInputType.address_n max_count:8 -TxInputType.prev_hash max_size:32 -TxInputType.script_sig max_size:1650 - -TxOutputType.address max_size:130 -TxOutputType.address_n max_count:8 -TxOutputType.op_return_data max_size:80 - -TxOutputBinType.script_pubkey max_size:520 - -TransactionType.inputs max_count:1 -TransactionType.bin_outputs max_count:1 -TransactionType.outputs max_count:1 -TransactionType.extra_data max_size:1024 - -TxRequestDetailsType.tx_hash max_size:32 - -TxRequestSerializedType.signature max_size:73 -TxRequestSerializedType.serialized_tx max_size:2048 - -MultisigRedeemScriptType.pubkeys max_count:15 -MultisigRedeemScriptType.signatures max_count:15 max_size:73 - -IdentityType.proto max_size:9 -IdentityType.user max_size:64 -IdentityType.host max_size:64 -IdentityType.port max_size:6 -IdentityType.path max_size:256 - -NEMTransactionCommon.address_n max_count:8 -NEMTransactionCommon.signer max_size:32 - -NEMTransfer.recipient max_size:41 -NEMTransfer.public_key max_size:32 -NEMTransfer.payload max_size:1024 -NEMTransfer.mosaics max_count:16 - -NEMMosaic.namespace max_size:145 -NEMMosaic.mosaic max_size:33 - -NEMProvisionNamespace.namespace max_size:65 -NEMProvisionNamespace.parent max_size:81 -NEMProvisionNamespace.sink max_size:41 - -NEMMosaicCreation.sink max_size:41 - -NEMMosaicDefinition.name max_size:32 -NEMMosaicDefinition.ticker max_size:16 -NEMMosaicDefinition.namespace max_size:145 -NEMMosaicDefinition.mosaic max_size:33 -NEMMosaicDefinition.levy_address max_size:41 -NEMMosaicDefinition.levy_namespace max_size:145 -NEMMosaicDefinition.levy_mosaic max_size:33 -NEMMosaicDefinition.description max_size:513 -NEMMosaicDefinition.networks max_count:8 - -NEMMosaicSupplyChange.namespace max_size:145 -NEMMosaicSupplyChange.mosaic max_size:33 - -NEMAggregateModification.modifications max_count:16 - -NEMCosignatoryModification.public_key max_size:32 - -NEMImportanceTransfer.public_key max_size:32 - -StellarAssetType.code max_size:13 -StellarAssetType.issuer max_size:57 - -# Lisk will be supported later - -LiskTransactionCommon skip_message:true -LiskTransactionAsset skip_message:true -LiskSignatureType skip_message:true -LiskDelegateType skip_message:true -LiskMultisignatureType skip_message:true diff --git a/firmware/protob/types.proto b/firmware/protob/types.proto deleted file mode 120000 index 8eed39a0a4..0000000000 --- a/firmware/protob/types.proto +++ /dev/null @@ -1 +0,0 @@ -../../vendor/trezor-common/protob/types.proto \ No newline at end of file diff --git a/firmware/recovery.c b/firmware/recovery.c index be5661af24..8dd2299fa0 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -24,16 +24,15 @@ #include "storage.h" #include "layout2.h" #include "protect.h" -#include "types.pb.h" #include "messages.h" #include "rng.h" #include "bip39.h" #include "oled.h" #include "usb.h" #include "gettext.h" -#include "types.pb.h" #include "recovery-table.h" #include "memzero.h" +#include "messages.pb.h" /* number of words expected in the new seed */ static uint32_t word_count; @@ -144,9 +143,9 @@ static void recovery_request(void) { WordRequest resp; memset(&resp, 0, sizeof(WordRequest)); resp.has_type = true; - resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain - : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 - : WordRequestType_WordRequestType_Matrix9; + resp.type = awaiting_word == 1 ? WordRequest_WordRequestType_WordRequestType_Plain + : (word_index % 4 == 3) ? WordRequest_WordRequestType_WordRequestType_Matrix6 + : WordRequest_WordRequestType_WordRequestType_Matrix9; msg_write(MessageType_MessageType_WordRequest, &resp); } @@ -182,15 +181,15 @@ static void recovery_done(void) { _("The seed is valid"), _("and MATCHES"), _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); fsm_sendSuccess(_("The seed is valid and matches the one in the device")); } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is valid"), _("but does NOT MATCH"), _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - fsm_sendFailure(FailureType_Failure_DataError, + protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("The seed is valid but does not match the one in the device")); } } @@ -202,9 +201,9 @@ static void recovery_done(void) { } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); } - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); } awaiting_word = 0; layoutHome(); @@ -459,7 +458,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr if (!dry_run) { if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } @@ -471,7 +470,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_update(); } - if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { + if ((type & RecoveryDevice_RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { awaiting_word = 2; word_index = 0; word_pincode = 0; @@ -497,7 +496,7 @@ static void recovery_scrambledword(const char *word) if (!dry_run) { session_clear(true); } - fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Wrong word retyped")); layoutHome(); return; } @@ -516,7 +515,7 @@ static void recovery_scrambledword(const char *word) if (!dry_run) { session_clear(true); } - fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Word not found in a wordlist")); layoutHome(); return; } @@ -545,7 +544,7 @@ void recovery_word(const char *word) recovery_scrambledword(word); break; default: - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); break; } } diff --git a/firmware/reset.c b/firmware/reset.c index 332463b93c..b0013939d9 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -24,11 +24,11 @@ #include "messages.h" #include "fsm.h" #include "layout2.h" -#include "types.pb.h" #include "protect.h" #include "bip39.h" #include "util.h" #include "gettext.h" +#include "messages.pb.h" static uint32_t strength; static uint8_t int_entropy[32]; @@ -52,15 +52,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect if (display_random) { layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ResetDevice, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } @@ -80,7 +80,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { if (!awaiting_entropy) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } SHA256_CTX ctx; @@ -109,7 +109,7 @@ static char current_word[10]; void reset_backup(bool separated) { if (!storage_needsBackup()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } @@ -136,13 +136,13 @@ void reset_backup(bool separated) i++; } layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { storage_clear_update(); session_clear(true); } layoutHome(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); return; } word_pos++; diff --git a/firmware/signing.c b/firmware/signing.c index 83503a9186..95e038f77b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -27,6 +27,7 @@ #include "crypto.h" #include "secp256k1.h" #include "gettext.h" +#include "messages.pb.h" static uint32_t inputs_count; static uint32_t outputs_count; @@ -51,8 +52,8 @@ enum { static uint32_t idx1, idx2; static uint32_t signatures; static TxRequest resp; -static TxInputType input; -static TxOutputBinType bin_output; +static TxAck_TransactionType_TxInputType input; +static TxAck_TransactionType_TxOutputBinType bin_output; static TxStruct to, tp, ti; static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check, hasher_preimage; static uint8_t CONFIDENTIAL privkey[32]; @@ -210,7 +211,7 @@ void send_req_1_input(void) { signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -221,7 +222,7 @@ void send_req_2_prev_meta(void) { signing_stage = STAGE_REQUEST_2_PREV_META; resp.has_request_type = true; - resp.request_type = RequestType_TXMETA; + resp.request_type = TxRequest_RequestType_TXMETA; resp.has_details = true; resp.details.has_tx_hash = true; resp.details.tx_hash.size = input.prev_hash.size; @@ -233,7 +234,7 @@ void send_req_2_prev_input(void) { signing_stage = STAGE_REQUEST_2_PREV_INPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -247,7 +248,7 @@ void send_req_2_prev_output(void) { signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; + resp.request_type = TxRequest_RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -261,7 +262,7 @@ void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) { signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; resp.has_request_type = true; - resp.request_type = RequestType_TXEXTRADATA; + resp.request_type = TxRequest_RequestType_TXEXTRADATA; resp.has_details = true; resp.details.has_extra_data_offset = true; resp.details.extra_data_offset = chunk_offset; @@ -277,7 +278,7 @@ void send_req_3_output(void) { signing_stage = STAGE_REQUEST_3_OUTPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; + resp.request_type = TxRequest_RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -288,7 +289,7 @@ void send_req_4_input(void) { signing_stage = STAGE_REQUEST_4_INPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -299,7 +300,7 @@ void send_req_4_output(void) { signing_stage = STAGE_REQUEST_4_OUTPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; + resp.request_type = TxRequest_RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -310,7 +311,7 @@ void send_req_segwit_input(void) { signing_stage = STAGE_REQUEST_SEGWIT_INPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -321,7 +322,7 @@ void send_req_segwit_witness(void) { signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -332,7 +333,7 @@ void send_req_decred_witness(void) { signing_stage = STAGE_REQUEST_DECRED_WITNESS; resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; + resp.request_type = TxRequest_RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -343,7 +344,7 @@ void send_req_5_output(void) { signing_stage = STAGE_REQUEST_5_OUTPUT; resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; + resp.request_type = TxRequest_RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -353,7 +354,7 @@ void send_req_5_output(void) void send_req_finished(void) { resp.has_request_type = true; - resp.request_type = RequestType_TXFINISHED; + resp.request_type = TxRequest_RequestType_TXFINISHED; msg_write(MessageType_MessageType_TxRequest, &resp); } @@ -384,7 +385,7 @@ void phase2_request_next_input(void) } } -void extract_input_bip32_path(const TxInputType *tinput) +void extract_input_bip32_path(const TxAck_TransactionType_TxInputType *tinput) { if (in_address_n_count == BIP32_NOCHANGEALLOWED) { return; @@ -417,7 +418,7 @@ void extract_input_bip32_path(const TxInputType *tinput) } } -bool check_change_bip32_path(const TxOutputType *toutput) +bool check_change_bip32_path(const TxAck_TransactionType_TxOutputType *toutput) { size_t count = toutput->address_n_count; @@ -434,7 +435,7 @@ bool check_change_bip32_path(const TxOutputType *toutput) && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } -bool compile_input_script_sig(TxInputType *tinput) +bool compile_input_script_sig(TxAck_TransactionType_TxInputType *tinput) { if (!multisig_fp_mismatch) { // check that this is still multisig @@ -496,7 +497,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) spending = 0; change_spend = 0; authorized_amount = 0; - memset(&input, 0, sizeof(TxInputType)); + memset(&input, 0, sizeof(TxAck_TransactionType_TxInputType)); memset(&resp, 0, sizeof(TxRequest)); signing = true; @@ -543,13 +544,13 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) #define MIN(a,b) (((a)<(b))?(a):(b)) -static bool signing_check_input(TxInputType *txinput) { +static bool signing_check_input(TxAck_TransactionType_TxInputType *txinput) { /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ if (txinput->has_multisig && !multisig_fp_mismatch) { uint8_t h[32]; if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); signing_abort(); return false; } @@ -572,7 +573,7 @@ static bool signing_check_input(TxInputType *txinput) { tx_sequence_hash(&hasher_sequence, txinput); if (coin->decred) { if (txinput->decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); signing_abort(); return false; } @@ -596,7 +597,7 @@ static bool signing_check_prevtx_hash(void) { uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Encountered invalid prevhash")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Encountered invalid prevhash")); signing_abort(); return false; } @@ -604,7 +605,7 @@ static bool signing_check_prevtx_hash(void) { return true; } -static bool signing_check_output(TxOutputType *txoutput) { +static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { // Phase1: Check outputs // add it to hash_outputs // ask user for permission @@ -613,7 +614,7 @@ static bool signing_check_output(TxOutputType *txoutput) { bool is_change = false; if (txoutput->address_n_count > 0) { if (txoutput->has_address) { - fsm_sendFailure(FailureType_Failure_DataError, _("Address in change output")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Address in change output")); signing_abort(); return false; } @@ -636,8 +637,8 @@ static bool signing_check_output(TxOutputType *txoutput) { * to make sure the user is not tricked to use witness change output * instead of regular one therefore creating ANYONECANSPEND output */ - if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS - || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) + if ((txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS + || txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS) && txoutput->amount > authorized_amount) { is_change = false; } @@ -653,7 +654,7 @@ static bool signing_check_output(TxOutputType *txoutput) { } if (spending + txoutput->amount < spending) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return false; } @@ -663,11 +664,11 @@ static bool signing_check_output(TxOutputType *txoutput) { layoutProgress(_("Signing transaction"), progress); } if (co < 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return false; } @@ -688,23 +689,23 @@ static bool signing_check_output(TxOutputType *txoutput) { static bool signing_check_fee(void) { // check fees if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); + fsm_sendFailure(Failure_FailureType_Failure_NotEnoughFunds, _("Not enough funds")); signing_abort(); return false; } uint64_t fee = to_spend - spending; if (fee > ((uint64_t) tx_weight * coin->maxfee_kb)/4000) { layoutFeeOverThreshold(coin, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } } // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } @@ -747,7 +748,7 @@ static void phase1_request_next_output(void) { } } -static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { +static void signing_hash_bip143(const TxAck_TransactionType_TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); hasher_Reset(&hasher_preimage); hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion @@ -763,7 +764,7 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { hasher_Final(&hasher_preimage, hash); } -static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { +static void signing_hash_zip143(const TxAck_TransactionType_TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); hasher_Reset(&hasher_preimage); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered @@ -795,13 +796,13 @@ static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { hasher_Final(&hasher_preimage, hash); } -static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { +static bool signing_sign_hash(TxAck_TransactionType_TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(coin->curve->params, private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); signing_abort(); return false; } @@ -812,7 +813,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Pubkey not found in multisig script")); signing_abort(); return false; } @@ -820,7 +821,7 @@ static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; txinput->script_sig.size = serialize_script_multisig(coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); if (txinput->script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); signing_abort(); return false; } @@ -834,7 +835,7 @@ static bool signing_sign_input(void) { uint8_t hash[32]; hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -849,19 +850,19 @@ static bool signing_sign_input(void) { return true; } -static bool signing_sign_segwit_input(TxInputType *txinput) { +static bool signing_sign_segwit_input(TxAck_TransactionType_TxInputType *txinput) { // idx1: index to sign uint8_t hash[32]; if (txinput->script_type == InputScriptType_SPENDWITNESS || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return false; } if (txinput->amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -917,7 +918,7 @@ static bool signing_sign_segwit_input(TxInputType *txinput) { return true; } -static bool signing_sign_decred_input(TxInputType *txinput) { +static bool signing_sign_decred_input(TxAck_TransactionType_TxInputType *txinput) { uint8_t hash[32], hash_witness[32]; tx_hash_final(&ti, hash_witness, false); signing_hash_decred(hash_witness, hash); @@ -930,10 +931,10 @@ static bool signing_sign_decred_input(TxInputType *txinput) { #define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 -void signing_txack(TransactionType *tx) +void signing_txack(TxAck_TransactionType *tx) { if (!signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); + fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); layoutHome(); return; } @@ -957,11 +958,11 @@ void signing_txack(TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - memcpy(&input, tx->inputs, sizeof(TxInputType)); + memcpy(&input, tx->inputs, sizeof(TxAck_TransactionType_TxInputType)); #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -969,12 +970,12 @@ void signing_txack(TransactionType *tx) if (coin->force_bip143 || overwintered) { if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -991,22 +992,22 @@ void signing_txack(TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (coin->decred) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred does not support Segwit")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred does not support Segwit")); signing_abort(); return; } if (!coin->has_segwit) { - fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Segwit not enabled on this coin")); signing_abort(); return; } if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Segwit input without amount")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Segwit input without amount")); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -1018,7 +1019,7 @@ void signing_txack(TransactionType *tx) if (idx1 == 0) { to.is_segwit = true; } else if (to.is_segwit == false) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -1029,19 +1030,19 @@ void signing_txack(TransactionType *tx) authorized_amount += tx->inputs[0].amount; phase1_request_next_input(); } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Wrong input script type")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Wrong input script type")); signing_abort(); return; } return; case STAGE_REQUEST_2_PREV_META: if (tx->outputs_cnt <= input.prev_index) { - fsm_sendFailure(FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); signing_abort(); return; } if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -1062,7 +1063,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_INPUT: progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1077,18 +1078,18 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_2_PREV_OUTPUT: progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } if (idx2 == input.prev_index) { if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred script version does not match previous output")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred script version does not match previous output")); signing_abort(); return; } @@ -1108,7 +1109,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_2_PREV_EXTRADATA: if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize extra data")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize extra data")); signing_abort(); return; } @@ -1136,7 +1137,7 @@ void signing_txack(TransactionType *tx) hasher_Update(&hasher_check, (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1152,7 +1153,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.size = 0; } if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1163,7 +1164,7 @@ void signing_txack(TransactionType *tx) uint8_t hash[32]; hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } @@ -1175,14 +1176,14 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_OUTPUT: progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } // check hashOutputs tx_output_hash(&hasher_check, &bin_output, coin->decred); if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } @@ -1216,17 +1217,17 @@ void signing_txack(TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { if (!(coin->force_bip143 || overwintered)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } if (tx->inputs[0].amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } @@ -1248,7 +1249,7 @@ void signing_txack(TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1267,7 +1268,7 @@ void signing_txack(TransactionType *tx) tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1287,7 +1288,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_5_OUTPUT: if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } @@ -1336,7 +1337,7 @@ void signing_txack(TransactionType *tx) ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1350,7 +1351,7 @@ void signing_txack(TransactionType *tx) } if (!r) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1374,7 +1375,7 @@ void signing_txack(TransactionType *tx) return; } - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing error")); signing_abort(); } diff --git a/firmware/signing.h b/firmware/signing.h index 68c3ccf537..90475d9a4a 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -25,11 +25,10 @@ #include "bip32.h" #include "coins.h" #include "hasher.h" -#include "messages.pb.h" -#include "types.pb.h" +#include "messages-bitcoin.pb.h" void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root); void signing_abort(void); -void signing_txack(TransactionType *tx); +void signing_txack(TxAck_TransactionType *tx); #endif diff --git a/firmware/stellar.c b/firmware/stellar.c index d33d0f11b1..a909f3fa6e 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -222,7 +222,7 @@ bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) str_addr_rows[2], str_amount_line ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -280,7 +280,7 @@ bool stellar_confirmPaymentOp(StellarPaymentOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -349,7 +349,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) str_dest_rows[1], str_dest_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -369,7 +369,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) _("This is the amount debited"), _("from your account.") ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -464,7 +464,7 @@ bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) str_buying, str_buying_asset ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -544,7 +544,7 @@ bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) str_buying, str_buying_asset ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -603,7 +603,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -635,7 +635,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -669,7 +669,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -742,7 +742,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -772,7 +772,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) NULL, NULL ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -814,7 +814,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -831,7 +831,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("(confirm hash on next"), _("screen)") ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -848,7 +848,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("(confirm hash on next"), _("screen)") ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -868,7 +868,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -928,7 +928,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE]; if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) { stellar_signingAbort(_("User canceled")); - fsm_sendFailure(FailureType_Failure_ProcessError, _("Invalid asset issuer")); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Invalid asset issuer")); return false; } @@ -942,7 +942,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1003,7 +1003,7 @@ bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) str_trustor_rows[1], str_trustor_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1061,7 +1061,7 @@ bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) str_destination_rows[1], str_destination_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1104,7 +1104,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) str_key_lines[2], str_key_lines[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1124,7 +1124,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) str_hash_lines[2], str_hash_lines[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1170,7 +1170,7 @@ bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) NULL, NULL ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1190,7 +1190,7 @@ void stellar_signingAbort(const char *reason) } stellar_signing = false; - fsm_sendFailure(FailureType_Failure_ProcessError, reason); + fsm_sendFailure(Failure_FailureType_Failure_ProcessError, reason); layoutHome(); } @@ -1680,7 +1680,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } @@ -1734,7 +1734,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[3], str_lines[4] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } @@ -1782,7 +1782,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[2], str_lines[3] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } diff --git a/firmware/storage.h b/firmware/storage.h index f0aabe9ca6..6924f9b4f5 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -20,9 +20,8 @@ #ifndef __STORAGE_H__ #define __STORAGE_H__ -#include "types.pb.h" -#include "messages.pb.h" #include "bip32.h" +#include "messages-management.pb.h" #define STORAGE_FIELD(TYPE, NAME) \ bool has_##NAME; \ diff --git a/firmware/transaction.c b/firmware/transaction.c index 7d12749b34..aa77039b61 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -30,7 +30,6 @@ #include "base58.h" #include "address.h" #include "messages.pb.h" -#include "types.pb.h" #include "segwit_addr.h" #include "cash_addr.h" @@ -187,22 +186,22 @@ bool compute_address(const CoinInfo *coin, return 1; } -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) +int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionType_TxOutputType *in, TxAck_TransactionType_TxOutputBinType *out, bool needs_confirm) { - memset(out, 0, sizeof(TxOutputBinType)); + memset(out, 0, sizeof(TxAck_TransactionType_TxOutputBinType)); out->amount = in->amount; out->decred_script_version = in->decred_script_version; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; size_t addr_raw_len; - if (in->script_type == OutputScriptType_PAYTOOPRETURN) { + if (in->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOOPRETURN) { // only 0 satoshi allowed for OP_RETURN if (in->amount != 0) { return 0; // failed to compile output } if (needs_confirm) { layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } } @@ -219,16 +218,16 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T InputScriptType input_script_type; switch (in->script_type) { - case OutputScriptType_PAYTOADDRESS: + case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOADDRESS: input_script_type = InputScriptType_SPENDADDRESS; break; - case OutputScriptType_PAYTOMULTISIG: + case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOMULTISIG: input_script_type = InputScriptType_SPENDMULTISIG; break; - case OutputScriptType_PAYTOWITNESS: + case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS: input_script_type = InputScriptType_SPENDWITNESS; break; - case OutputScriptType_PAYTOP2SHWITNESS: + case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS: input_script_type = InputScriptType_SPENDP2SHWITNESS; break; default: @@ -308,7 +307,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T if (needs_confirm) { layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } } @@ -421,7 +420,7 @@ uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScr // tx methods -uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) +uint32_t tx_prevout_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input) { for (int i = 0; i < 32; i++) { hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); @@ -437,13 +436,13 @@ uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) return r + size; } -uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) +uint32_t tx_sequence_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input) { hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); return 4; } -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) +uint32_t tx_output_hash(Hasher *hasher, const TxAck_TransactionType_TxOutputBinType *output, bool decred) { uint32_t r = 0; hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; @@ -500,7 +499,7 @@ uint32_t tx_serialize_header_hash(TxStruct *tx) return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) +uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -529,7 +528,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out return r; } -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -554,7 +553,7 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) return r; } -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out) { static const uint64_t amount = 0; static const uint32_t block_height = 0x00000000; @@ -579,7 +578,7 @@ uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uin return r; } -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -641,7 +640,7 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx) return 4; } -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) +uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output, uint8_t *out) { if (tx->have_inputs < tx->inputs_len) { // not all inputs provided @@ -670,7 +669,7 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_ return r; } -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output) { if (tx->have_inputs < tx->inputs_len) { // not all inputs provided @@ -743,7 +742,7 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -static uint32_t tx_input_script_size(const TxInputType *txinput) { +static uint32_t tx_input_script_size(const TxAck_TransactionType_TxInputType *txinput) { uint32_t input_script_size; if (txinput->has_multisig) { uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT @@ -758,7 +757,7 @@ static uint32_t tx_input_script_size(const TxInputType *txinput) { return input_script_size; } -uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) { +uint32_t tx_input_weight(const CoinInfo *coin, const TxAck_TransactionType_TxInputType *txinput) { if (coin->decred) { return 4 * (TXSIZE_INPUT + 1); // Decred tree } @@ -782,16 +781,16 @@ uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) { return weight; } -uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { +uint32_t tx_output_weight(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *txoutput) { uint32_t output_script_size = 0; - if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { + if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOOPRETURN) { output_script_size = 1 + op_push_size(txoutput->op_return_data.size) + txoutput->op_return_data.size; } else if (txoutput->address_n_count > 0) { - if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS) { output_script_size = txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; - } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { + } else if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS) { output_script_size = TXSIZE_P2SCRIPT; } else { output_script_size = txoutput->has_multisig @@ -834,7 +833,7 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { return 4 * (size + output_script_size); } -uint32_t tx_decred_witness_weight(const TxInputType *txinput) { +uint32_t tx_decred_witness_weight(const TxAck_TransactionType_TxInputType *txinput) { uint32_t input_script_size = tx_input_script_size(txinput); uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; diff --git a/firmware/transaction.h b/firmware/transaction.h index 22c2522994..90aa6f9fa3 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -26,7 +26,7 @@ #include "bip32.h" #include "coins.h" #include "hasher.h" -#include "types.pb.h" +#include "messages-bitcoin.pb.h" #define TX_OVERWINTERED 0x80000000 @@ -58,29 +58,29 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); +int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionType_TxOutputType *in, TxAck_TransactionType_TxOutputBinType *out, bool needs_confirm); -uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_prevout_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); -uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); +uint32_t tx_sequence_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input); +uint32_t tx_output_hash(Hasher *hasher, const TxAck_TransactionType_TxOutputBinType *output, bool decred); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); +uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output, uint8_t *out); +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered); uint32_t tx_serialize_header_hash(TxStruct *tx); -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input); +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput); -uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput); -uint32_t tx_decred_witness_weight(const TxInputType *txinput); +uint32_t tx_input_weight(const CoinInfo *coin, const TxAck_TransactionType_TxInputType *txinput); +uint32_t tx_output_weight(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *txoutput); +uint32_t tx_decred_witness_weight(const TxAck_TransactionType_TxInputType *txinput); #endif diff --git a/vendor/trezor-common b/vendor/trezor-common index 2dad4dcd51..51eeb0ed5f 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 2dad4dcd519662b9d69e276e737ac1bba655555d +Subproject commit 51eeb0ed5fedf1506eb607036e9f16ef43dd8580 From 520cd69f25e4f34504ea03897ee2b6b3242e75e9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 17:19:55 +0200 Subject: [PATCH 0913/1154] firmware: fix stellar after the messages change --- firmware/stellar.c | 162 +++++++++++---------------------------------- firmware/stellar.h | 5 +- 2 files changed, 40 insertions(+), 127 deletions(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index a909f3fa6e..d60648842b 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -152,47 +152,10 @@ void stellar_signingInit(StellarSignTx *msg) } } -bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) -{ - if (!has_source_account) { - stellar_hashupdate_bool(false); - return true; - } - - // Convert account string to public key bytes - uint8_t bytes[32]; - if (!stellar_getAddressBytes(str_account, bytes)) { - return false; - } - - const char **str_addr_rows = stellar_lineBreakAddress(bytes); - - stellar_layoutTransactionDialog( - _("Op src account OK?"), - NULL, - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // Hash: source account - stellar_hashupdate_address(bytes); - - return true; -} - bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(0); @@ -239,11 +202,7 @@ bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) bool stellar_confirmPaymentOp(StellarPaymentOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(1); @@ -300,11 +259,7 @@ bool stellar_confirmPaymentOp(StellarPaymentOp *msg) bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(2); @@ -400,11 +355,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(3); @@ -490,11 +441,7 @@ bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(4); @@ -568,11 +515,7 @@ bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(5); @@ -892,11 +835,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(6); @@ -960,11 +899,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(7); @@ -1036,11 +971,7 @@ bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(8); @@ -1077,11 +1008,7 @@ bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) bool stellar_confirmManageDataOp(StellarManageDataOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(10); @@ -1151,11 +1078,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) { if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); // Hash: operation type stellar_hashupdate_uint32(11); @@ -1194,44 +1117,10 @@ void stellar_signingAbort(const char *reason) layoutHome(); } -/** - * Populates the fields of resp with the signature of the active transaction - */ -void stellar_fillSignedTx(StellarSignedTx *resp) -{ - StellarTransaction *activeTx = stellar_getActiveTx(); - - // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union - stellar_hashupdate_uint32(0); - - // Add the public key for verification that the right account was used for signing - memcpy(resp->public_key.bytes, &(activeTx->signing_pubkey), 32); - resp->public_key.size = 32; - resp->has_public_key = true; - - // Add the signature (note that this does not include the 4-byte hint since it can be calculated from the public key) - uint8_t signature[64]; - // Note: this calls sha256_Final on the hash context - stellar_getSignatureForActiveTx(signature); - memcpy(resp->signature.bytes, signature, sizeof(signature)); - resp->signature.size = sizeof(signature); - resp->has_signature = true; -} - -uint8_t stellar_allOperationsConfirmed() -{ - return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; -} - -StellarTransaction *stellar_getActiveTx() -{ - return &stellar_activeTx; -} - /* * Calculates and sets the signature for the active transaction */ -void stellar_getSignatureForActiveTx(uint8_t *out_signature) +static void stellar_getSignatureForActiveTx(uint8_t *out_signature) { HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); @@ -1246,6 +1135,33 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature) memcpy(out_signature, signature, sizeof(signature)); } +/** + * Populates the fields of resp with the signature of the active transaction + */ +void stellar_fillSignedTx(StellarSignedTx *resp) +{ + // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union + stellar_hashupdate_uint32(0); + + // Add the public key for verification that the right account was used for signing + memcpy(resp->public_key.bytes, stellar_activeTx.signing_pubkey, 32); + resp->public_key.size = 32; + resp->has_public_key = true; + + // Add the signature (note that this does not include the 4-byte hint since it can be calculated from the public key) + uint8_t signature[64]; + // Note: this calls sha256_Final on the hash context + stellar_getSignatureForActiveTx(signature); + memcpy(resp->signature.bytes, signature, sizeof(signature)); + resp->signature.size = sizeof(signature); + resp->has_signature = true; +} + +bool stellar_allOperationsConfirmed() +{ + return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; +} + /* * Returns number (representing stroops) formatted as XLM * For example, if number has value 1000000000 then it will be returned as "100.0" diff --git a/firmware/stellar.h b/firmware/stellar.h index c7ab4fd0bd..eb1fd256c6 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -53,7 +53,6 @@ typedef struct { // Signing process void stellar_signingInit(StellarSignTx *tx); void stellar_signingAbort(const char *reason); -bool stellar_confirmSourceAccount(bool has_source_account, char *str_account); bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); bool stellar_confirmPaymentOp(StellarPaymentOp *msg); bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); @@ -85,10 +84,8 @@ void stellar_hashupdate_address(uint8_t *address_bytes); void stellar_hashupdate_asset(StellarAssetType *asset); void stellar_hashupdate_bytes(uint8_t *data, size_t len); -StellarTransaction *stellar_getActiveTx(void); void stellar_fillSignedTx(StellarSignedTx *resp); -uint8_t stellar_allOperationsConfirmed(void); -void stellar_getSignatureForActiveTx(uint8_t *out_signature); +bool stellar_allOperationsConfirmed(void); void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen); From dbb3e927eccc565bbc767fcd002d3c286fc23e5c Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Tue, 19 Jun 2018 20:06:59 +0100 Subject: [PATCH 0914/1154] messages: Use pb_get_encoded_size --- firmware/messages.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index aa947f3f28..69473ef5d7 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -169,10 +169,8 @@ bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) return false; } - pb_ostream_t sizestream = {0, 0, SIZE_MAX, 0, 0}; - bool status = pb_encode(&sizestream, fields, msg_ptr); - - if (!status) { + size_t len; + if (!pb_get_encoded_size(&len, fields, msg_ptr)) { return false; } @@ -193,7 +191,6 @@ bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) return false; } - uint32_t len = sizestream.bytes_written; append('#'); append('#'); append((msg_id >> 8) & 0xFF); @@ -203,7 +200,7 @@ bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) append((len >> 8) & 0xFF); append(len & 0xFF); pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0}; - status = pb_encode(&stream, fields, msg_ptr); + bool status = pb_encode(&stream, fields, msg_ptr); if (type == 'n') { msg_out_pad(); } From c02c1979ed2b87c9a802dcd6c425cb29f0c529f0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 20:28:07 +0200 Subject: [PATCH 0915/1154] Revert "firmware: fix stellar after the messages change" This reverts commit 520cd69f25e4f34504ea03897ee2b6b3242e75e9. --- firmware/stellar.c | 146 +++++++++++++++++++++++++++++++++++---------- firmware/stellar.h | 5 +- 2 files changed, 119 insertions(+), 32 deletions(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index d60648842b..a909f3fa6e 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -152,10 +152,47 @@ void stellar_signingInit(StellarSignTx *msg) } } +bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) +{ + if (!has_source_account) { + stellar_hashupdate_bool(false); + return true; + } + + // Convert account string to public key bytes + uint8_t bytes[32]; + if (!stellar_getAddressBytes(str_account, bytes)) { + return false; + } + + const char **str_addr_rows = stellar_lineBreakAddress(bytes); + + stellar_layoutTransactionDialog( + _("Op src account OK?"), + NULL, + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2] + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash: source account + stellar_hashupdate_address(bytes); + + return true; +} + bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(0); @@ -202,7 +239,11 @@ bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) bool stellar_confirmPaymentOp(StellarPaymentOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(1); @@ -259,7 +300,11 @@ bool stellar_confirmPaymentOp(StellarPaymentOp *msg) bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(2); @@ -355,7 +400,11 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(3); @@ -441,7 +490,11 @@ bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(4); @@ -515,7 +568,11 @@ bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(5); @@ -835,7 +892,11 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(6); @@ -899,7 +960,11 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(7); @@ -971,7 +1036,11 @@ bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(8); @@ -1008,7 +1077,11 @@ bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) bool stellar_confirmManageDataOp(StellarManageDataOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(10); @@ -1078,7 +1151,11 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) { if (!stellar_signing) return false; - stellar_hashupdate_bool(false); // stellar_hashupdate_address(stellar_activeTx.signing_pubkey); + + if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } // Hash: operation type stellar_hashupdate_uint32(11); @@ -1117,34 +1194,18 @@ void stellar_signingAbort(const char *reason) layoutHome(); } -/* - * Calculates and sets the signature for the active transaction - */ -static void stellar_getSignatureForActiveTx(uint8_t *out_signature) -{ - HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); - - // Signature is the ed25519 detached signature of the sha256 of all the bytes - // that have been read so far - uint8_t to_sign[32]; - sha256_Final(&(stellar_activeTx.sha256_ctx), to_sign); - - uint8_t signature[64]; - ed25519_sign(to_sign, sizeof(to_sign), node->private_key, node->public_key + 1, signature); - - memcpy(out_signature, signature, sizeof(signature)); -} - /** * Populates the fields of resp with the signature of the active transaction */ void stellar_fillSignedTx(StellarSignedTx *resp) { + StellarTransaction *activeTx = stellar_getActiveTx(); + // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union stellar_hashupdate_uint32(0); // Add the public key for verification that the right account was used for signing - memcpy(resp->public_key.bytes, stellar_activeTx.signing_pubkey, 32); + memcpy(resp->public_key.bytes, &(activeTx->signing_pubkey), 32); resp->public_key.size = 32; resp->has_public_key = true; @@ -1157,11 +1218,34 @@ void stellar_fillSignedTx(StellarSignedTx *resp) resp->has_signature = true; } -bool stellar_allOperationsConfirmed() +uint8_t stellar_allOperationsConfirmed() { return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; } +StellarTransaction *stellar_getActiveTx() +{ + return &stellar_activeTx; +} + +/* + * Calculates and sets the signature for the active transaction + */ +void stellar_getSignatureForActiveTx(uint8_t *out_signature) +{ + HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); + + // Signature is the ed25519 detached signature of the sha256 of all the bytes + // that have been read so far + uint8_t to_sign[32]; + sha256_Final(&(stellar_activeTx.sha256_ctx), to_sign); + + uint8_t signature[64]; + ed25519_sign(to_sign, sizeof(to_sign), node->private_key, node->public_key + 1, signature); + + memcpy(out_signature, signature, sizeof(signature)); +} + /* * Returns number (representing stroops) formatted as XLM * For example, if number has value 1000000000 then it will be returned as "100.0" diff --git a/firmware/stellar.h b/firmware/stellar.h index eb1fd256c6..c7ab4fd0bd 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -53,6 +53,7 @@ typedef struct { // Signing process void stellar_signingInit(StellarSignTx *tx); void stellar_signingAbort(const char *reason); +bool stellar_confirmSourceAccount(bool has_source_account, char *str_account); bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); bool stellar_confirmPaymentOp(StellarPaymentOp *msg); bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); @@ -84,8 +85,10 @@ void stellar_hashupdate_address(uint8_t *address_bytes); void stellar_hashupdate_asset(StellarAssetType *asset); void stellar_hashupdate_bytes(uint8_t *data, size_t len); +StellarTransaction *stellar_getActiveTx(void); void stellar_fillSignedTx(StellarSignedTx *resp); -bool stellar_allOperationsConfirmed(void); +uint8_t stellar_allOperationsConfirmed(void); +void stellar_getSignatureForActiveTx(uint8_t *out_signature); void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen); From 277a01a24c4d90796af027f3916c292e574fa4a6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 10 Jul 2018 20:44:30 +0200 Subject: [PATCH 0916/1154] firmware: fix stuff broken in the last commit --- firmware/protob/Makefile | 2 +- firmware/protob/messages-bitcoin.options | 70 ++++++++++++------------ firmware/protob/messages-stellar.options | 17 ++++++ firmware/stellar.c | 13 +---- firmware/stellar.h | 3 +- vendor/trezor-common | 2 +- 6 files changed, 59 insertions(+), 48 deletions(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 21af3cde6f..e0b9e10ebb 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -23,7 +23,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/messages-bitcoin.options b/firmware/protob/messages-bitcoin.options index 34e8f6134e..26e06de98c 100644 --- a/firmware/protob/messages-bitcoin.options +++ b/firmware/protob/messages-bitcoin.options @@ -1,49 +1,51 @@ -GetPublicKey.address_n max_count:8 -GetPublicKey.ecdsa_curve_name max_size:32 -GetPublicKey.coin_name max_size:21 +GetPublicKey.address_n max_count:8 +GetPublicKey.ecdsa_curve_name max_size:32 +GetPublicKey.coin_name max_size:21 -PublicKey.xpub max_size:113 +PublicKey.xpub max_size:113 -GetAddress.address_n max_count:8 -GetAddress.coin_name max_size:21 +GetAddress.address_n max_count:8 +GetAddress.coin_name max_size:21 -Address.address max_size:130 +Address.address max_size:130 -SignTx.coin_name max_size:21 +SignTx.coin_name max_size:21 -SignMessage.address_n max_count:8 -SignMessage.message max_size:1024 -SignMessage.coin_name max_size:21 +SignMessage.address_n max_count:8 +SignMessage.message max_size:1024 +SignMessage.coin_name max_size:21 -VerifyMessage.address max_size:130 -VerifyMessage.signature max_size:65 -VerifyMessage.message max_size:1024 -VerifyMessage.coin_name max_size:21 +VerifyMessage.address max_size:130 +VerifyMessage.signature max_size:65 +VerifyMessage.message max_size:1024 +VerifyMessage.coin_name max_size:21 -MessageSignature.address max_size:130 -MessageSignature.signature max_size:65 +MessageSignature.address max_size:130 +MessageSignature.signature max_size:65 -TxAck.TransactionType.inputs max_count:1 -TxAck.TransactionType.bin_outputs max_count:1 -TxAck.TransactionType.outputs max_count:1 -TxAck.TransactionType.extra_data max_size:1024 +TxAck.TransactionType.inputs max_count:1 +TxAck.TransactionType.bin_outputs max_count:1 +TxAck.TransactionType.outputs max_count:1 +TxAck.TransactionType.extra_data max_size:1024 -TxAck.TransactionType.TxInputType.address_n max_count:8 -TxAck.TransactionType.TxInputType.prev_hash max_size:32 -TxAck.TransactionType.TxInputType.script_sig max_size:1650 +TxAck.TransactionType.TxInputType.address_n max_count:8 +TxAck.TransactionType.TxInputType.prev_hash max_size:32 +TxAck.TransactionType.TxInputType.script_sig max_size:1650 +TxAck.TransactionType.TxInputType.prev_block_hash_bip115 max_size:32 -TxAck.TransactionType.TxOutputType.address max_size:130 -TxAck.TransactionType.TxOutputType.address_n max_count:8 -TxAck.TransactionType.TxOutputType.op_return_data max_size:80 +TxAck.TransactionType.TxOutputType.address max_size:130 +TxAck.TransactionType.TxOutputType.address_n max_count:8 +TxAck.TransactionType.TxOutputType.op_return_data max_size:80 +TxAck.TransactionType.TxOutputType.block_hash_bip115 max_size:32 -TxAck.TransactionType.TxOutputBinType.script_pubkey max_size:520 +TxAck.TransactionType.TxOutputBinType.script_pubkey max_size:520 -TxRequest.TxRequestDetailsType.tx_hash max_size:32 +TxRequest.TxRequestDetailsType.tx_hash max_size:32 -TxRequest.TxRequestSerializedType.signature max_size:73 -TxRequest.TxRequestSerializedType.serialized_tx max_size:2048 +TxRequest.TxRequestSerializedType.signature max_size:73 +TxRequest.TxRequestSerializedType.serialized_tx max_size:2048 -MultisigRedeemScriptType.pubkeys max_count:15 -MultisigRedeemScriptType.signatures max_count:15 max_size:73 +MultisigRedeemScriptType.pubkeys max_count:15 +MultisigRedeemScriptType.signatures max_count:15 max_size:73 -MultisigRedeemScriptType.HDNodePathType.address_n max_count:8 +MultisigRedeemScriptType.HDNodePathType.address_n max_count:8 diff --git a/firmware/protob/messages-stellar.options b/firmware/protob/messages-stellar.options index 59cc6c0606..ecfb295f7a 100644 --- a/firmware/protob/messages-stellar.options +++ b/firmware/protob/messages-stellar.options @@ -8,29 +8,46 @@ StellarGetPublicKey.address_n max_count:10 StellarPublicKey.public_key max_size:32 +StellarSignTx.source_account max_size:57 StellarSignTx.address_n max_count:10 StellarSignTx.network_passphrase max_size:1024 StellarSignTx.memo_text max_size:29 StellarSignTx.memo_hash max_size:32 +StellarPaymentOp.source_account max_size:57 StellarPaymentOp.destination_account max_size:57 +StellarCreateAccountOp.source_account max_size:57 StellarCreateAccountOp.new_account max_size:57 +StellarPathPaymentOp.source_account max_size:57 StellarPathPaymentOp.destination_account max_size:57 StellarPathPaymentOp.paths max_count:5 + +StellarManageOfferOp.source_account max_size:57 + +StellarCreatePassiveOfferOp.source_account max_size:57 + +StellarSetOptionsOp.source_account max_size:57 StellarSetOptionsOp.inflation_destination_account max_size:57 StellarSetOptionsOp.home_domain max_size:33 StellarSetOptionsOp.signer_key max_size:32 +StellarChangeTrustOp.source_account max_size:57 + +StellarAllowTrustOp.source_account max_size:57 StellarAllowTrustOp.trusted_account max_size:57 StellarAllowTrustOp.asset_code max_size:13 +StellarAccountMergeOp.source_account max_size:57 StellarAccountMergeOp.destination_account max_size:57 +StellarManageDataOp.source_account max_size:57 StellarManageDataOp.key max_size:65 StellarManageDataOp.value max_size:65 +StellarBumpSequenceOp.source_account max_size:57 + StellarSignedTx.public_key max_size:32 StellarSignedTx.signature max_size:64 # ed25519 signatures are 64 bytes, this does not include the hint diff --git a/firmware/stellar.c b/firmware/stellar.c index a909f3fa6e..8666e0d5df 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -174,7 +174,7 @@ bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1199,13 +1199,11 @@ void stellar_signingAbort(const char *reason) */ void stellar_fillSignedTx(StellarSignedTx *resp) { - StellarTransaction *activeTx = stellar_getActiveTx(); - // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union stellar_hashupdate_uint32(0); // Add the public key for verification that the right account was used for signing - memcpy(resp->public_key.bytes, &(activeTx->signing_pubkey), 32); + memcpy(resp->public_key.bytes, stellar_activeTx.signing_pubkey, 32); resp->public_key.size = 32; resp->has_public_key = true; @@ -1218,16 +1216,11 @@ void stellar_fillSignedTx(StellarSignedTx *resp) resp->has_signature = true; } -uint8_t stellar_allOperationsConfirmed() +bool stellar_allOperationsConfirmed() { return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; } -StellarTransaction *stellar_getActiveTx() -{ - return &stellar_activeTx; -} - /* * Calculates and sets the signature for the active transaction */ diff --git a/firmware/stellar.h b/firmware/stellar.h index c7ab4fd0bd..404832650c 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -85,9 +85,8 @@ void stellar_hashupdate_address(uint8_t *address_bytes); void stellar_hashupdate_asset(StellarAssetType *asset); void stellar_hashupdate_bytes(uint8_t *data, size_t len); -StellarTransaction *stellar_getActiveTx(void); void stellar_fillSignedTx(StellarSignedTx *resp); -uint8_t stellar_allOperationsConfirmed(void); +bool stellar_allOperationsConfirmed(void); void stellar_getSignatureForActiveTx(uint8_t *out_signature); void stellar_format_uint32(uint32_t number, char *out, size_t outlen); diff --git a/vendor/trezor-common b/vendor/trezor-common index 51eeb0ed5f..32850a6262 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 51eeb0ed5fedf1506eb607036e9f16ef43dd8580 +Subproject commit 32850a62624ce1a6612ff545beb706560c3716da From 06fbb91f128fbb45bd3527463d0ad21838db8ca5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Jul 2018 14:44:34 +0200 Subject: [PATCH 0917/1154] build: added --recursive to git clone in Makefile and script/bootstrap --- Makefile | 2 +- script/bootstrap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2d11f28ea4..32a61bca29 100644 --- a/Makefile +++ b/Makefile @@ -34,4 +34,4 @@ libtrezor.a: .PHONY: vendor vendor: - git submodule update --init + git submodule update --init --recursive diff --git a/script/bootstrap b/script/bootstrap index 4f687bf0eb..500e9a0612 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -7,4 +7,4 @@ set -e cd "$(dirname "$0")/.." -git submodule update --init +git submodule update --init --recursive From c3291c37afde96e1bcce2df5236f5ecccf9809e5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Jul 2018 15:07:42 +0200 Subject: [PATCH 0918/1154] vendor: update trezor-common; reflect rename of common.proto to messages-common.proto --- firmware/Makefile | 2 +- firmware/fsm.c | 2 -- firmware/protect.h | 2 +- firmware/protob/Makefile | 2 +- firmware/protob/common.options | 3 --- firmware/protob/common.proto | 1 - firmware/protob/messages-management.options | 13 ------------- vendor/trezor-common | 2 +- 8 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 firmware/protob/common.options delete mode 120000 firmware/protob/common.proto diff --git a/firmware/Makefile b/firmware/Makefile index 0f823bd23b..39c8e1bb76 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,9 +82,9 @@ OBJS += ../vendor/nanopb/pb_common.o OBJS += ../vendor/nanopb/pb_decode.o OBJS += ../vendor/nanopb/pb_encode.o -OBJS += protob/common.pb.o OBJS += protob/messages.pb.o OBJS += protob/messages-bitcoin.pb.o +OBJS += protob/messages-common.pb.o OBJS += protob/messages-crypto.pb.o OBJS += protob/messages-debug.pb.o OBJS += protob/messages-ethereum.pb.o diff --git a/firmware/fsm.c b/firmware/fsm.c index 5e2dcdf57b..e1cff17b01 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -58,8 +58,6 @@ #include "supervise.h" #include "stellar.h" -#include "messages-management.pb.h" - // message methods static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); diff --git a/firmware/protect.h b/firmware/protect.h index d8c9cde64f..db5edb0222 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -21,7 +21,7 @@ #define __PROTECT_H__ #include -#include "messages-management.pb.h" +#include "messages-common.pb.h" bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only); bool protectPin(bool use_cached); diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index e0b9e10ebb..7873b4c97c 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -2,7 +2,7 @@ ifneq ($(V),1) Q := @ endif -all: messages_map.h common.pb.c messages-bitcoin.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages_nem_pb2.py +all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages_nem_pb2.py PYTHON ?= python diff --git a/firmware/protob/common.options b/firmware/protob/common.options deleted file mode 100644 index 875029177c..0000000000 --- a/firmware/protob/common.options +++ /dev/null @@ -1,3 +0,0 @@ -HDNodeType.chain_code max_size:32 -HDNodeType.private_key max_size:32 -HDNodeType.public_key max_size:33 diff --git a/firmware/protob/common.proto b/firmware/protob/common.proto deleted file mode 120000 index 1bc14a7384..0000000000 --- a/firmware/protob/common.proto +++ /dev/null @@ -1 +0,0 @@ -../../vendor/trezor-common/protob/common.proto \ No newline at end of file diff --git a/firmware/protob/messages-management.options b/firmware/protob/messages-management.options index 039b1b6d54..b3ee14605d 100644 --- a/firmware/protob/messages-management.options +++ b/firmware/protob/messages-management.options @@ -16,19 +16,6 @@ ApplySettings.homescreen max_size:1024 Ping.message max_size:256 -Success.message max_size:256 - -Failure.message max_size:256 - -ButtonRequest.data max_size:256 - -PinMatrixAck.pin max_size:10 - -PassphraseAck.passphrase max_size:51 -PassphraseAck.state max_size:64 - -PassphraseStateRequest.state max_size:64 - LoadDevice.mnemonic max_size:241 LoadDevice.pin max_size:10 LoadDevice.language max_size:17 diff --git a/vendor/trezor-common b/vendor/trezor-common index 32850a6262..e0108d34bf 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 32850a62624ce1a6612ff545beb706560c3716da +Subproject commit e0108d34bf4b741d9ddcf1e7b423e799a3a04b77 From eac5f43b706d23857dfe8bf70228f4a426bf43ce Mon Sep 17 00:00:00 2001 From: Saleem Rashid Date: Mon, 16 Jul 2018 14:08:55 +0100 Subject: [PATCH 0919/1154] fullbuild: Call script/bootstrap before clone (#383) fullbuild would previously fail if the parent repository hadn't initialized submodules yet, due to the use of --reference Fixes #382 --- script/fullbuild | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/fullbuild b/script/fullbuild index 85b8290a99..99c7dd9e71 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -62,6 +62,8 @@ main() { local bootloader_commit="$1" local firmware_commit="$2" + script/bootstrap + worktree_setup "$BOOTLOADER_DIR" "$bootloader_commit" worktree_build "$BOOTLOADER_DIR" From 020a39bf1dd2b062eefd7897ee598643826f64c8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 16 Jul 2018 15:18:56 +0200 Subject: [PATCH 0920/1154] protob: add two missing files --- firmware/protob/messages-common.options | 16 ++++++++++++++++ firmware/protob/messages-common.proto | 1 + 2 files changed, 17 insertions(+) create mode 100644 firmware/protob/messages-common.options create mode 120000 firmware/protob/messages-common.proto diff --git a/firmware/protob/messages-common.options b/firmware/protob/messages-common.options new file mode 100644 index 0000000000..31a54c3fa0 --- /dev/null +++ b/firmware/protob/messages-common.options @@ -0,0 +1,16 @@ +Success.message max_size:256 + +Failure.message max_size:256 + +ButtonRequest.data max_size:256 + +PinMatrixAck.pin max_size:10 + +PassphraseAck.passphrase max_size:51 +PassphraseAck.state max_size:64 + +PassphraseStateRequest.state max_size:64 + +HDNodeType.chain_code max_size:32 +HDNodeType.private_key max_size:32 +HDNodeType.public_key max_size:33 diff --git a/firmware/protob/messages-common.proto b/firmware/protob/messages-common.proto new file mode 120000 index 0000000000..b16f68e613 --- /dev/null +++ b/firmware/protob/messages-common.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-common.proto \ No newline at end of file From 1ef73190b9361a99922b9a950b508933264cf77f Mon Sep 17 00:00:00 2001 From: HackyMiner Date: Fri, 20 Jul 2018 00:56:11 +0900 Subject: [PATCH 0921/1154] fixed rlp_length for chain_id > 255 (#381) --- firmware/ethereum.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 87b7f529da..a5cf7a32a7 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -568,7 +568,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(1, tx_type); } if (chain_id) { - rlp_length += rlp_calculate_length(1, chain_id); + int length = chain_id < 0x100 ? 1: chain_id < 0x10000 ? 2: chain_id < 0x1000000 ? 3 : 4; + rlp_length += rlp_calculate_length(length, chain_id); rlp_length += rlp_calculate_length(0, 0); rlp_length += rlp_calculate_length(0, 0); } From 8b63ffce61ed07f7e4db8fc48ac3ec8ec972891f Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Fri, 27 Jul 2018 06:31:01 -0400 Subject: [PATCH 0922/1154] ethereum: add Akroma chain (#387) --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index a5cf7a32a7..cdf81fcc38 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -263,6 +263,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 820: suffix = " CLO"; break; // Callisto case 1987: suffix = " EGEM"; break; // EtherGem case 31102: suffix = " ESN"; break; // Ethersocial Network + case 200625: suffix = " AKA"; break; // Akroma default : suffix = " UNKN"; break; // unknown chain } } From 925c3a8536f70a5a80131bbf619b0e0db70419eb Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Mon, 30 Jul 2018 06:01:03 -0400 Subject: [PATCH 0923/1154] eth: add Musicoin (#388) --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index cdf81fcc38..638b700af4 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -264,6 +264,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 1987: suffix = " EGEM"; break; // EtherGem case 31102: suffix = " ESN"; break; // Ethersocial Network case 200625: suffix = " AKA"; break; // Akroma + case 7762959: suffix = " MUSI"; break; // Musicoin default : suffix = " UNKN"; break; // unknown chain } } From dca28f1c4457a744859e5ffb7dc8282a857c257b Mon Sep 17 00:00:00 2001 From: heneault Date: Thu, 2 Aug 2018 08:59:46 -0400 Subject: [PATCH 0924/1154] commit emulator flash modification to persistent storage (#390) --- emulator/flash.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/emulator/flash.c b/emulator/flash.c index a275cf641a..02b2a4ec71 100644 --- a/emulator/flash.c +++ b/emulator/flash.c @@ -20,10 +20,14 @@ #include #include #include +#include #include "memory.h" -void flash_lock(void) {} +void flash_lock(void) { + sync(); +} + void flash_unlock(void) {} void flash_clear_status_flags(void) {} @@ -131,5 +135,6 @@ void svc_flash_erase_sector(uint16_t sector) { uint32_t svc_flash_lock(void) { assert (!flash_locked); flash_locked = true; + sync(); return 0; } From 3de28570e44dccb06bcbc7d1bf693dd023806b51 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 6 Aug 2018 16:20:27 +0200 Subject: [PATCH 0925/1154] firmware: don't use hardcoded version_group_id, but use the one from coin definition --- firmware/signing.c | 12 ++++++------ firmware/transaction.c | 9 ++++----- firmware/transaction.h | 3 ++- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 95e038f77b..f2a0ae4edf 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -511,13 +511,13 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; } @@ -1046,7 +1046,7 @@ void signing_txack(TxAck_TransactionType *tx) signing_abort(); return; } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered, coin->version_group_id); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; @@ -1129,7 +1129,7 @@ void signing_txack(TxAck_TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); hasher_Reset(&hasher_check); } // check prevouts and script type @@ -1328,12 +1328,12 @@ void signing_txack(TxAck_TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx1 == 0) { // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); to.is_decred = true; } // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { diff --git a/firmware/transaction.c b/firmware/transaction.c index aa77039b61..ae66a3517c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -467,8 +467,7 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) if (tx->overwintered) { uint32_t ver = tx->version | TX_OVERWINTERED; memcpy(out, &ver, 4); - uint32_t version_group_id = 0x03c48270; - memcpy(out + 4, &version_group_id, 4); + memcpy(out + 4, &(tx->version_group_id), 4); r += 4; } else { memcpy(out, &(tx->version), 4); @@ -486,8 +485,7 @@ uint32_t tx_serialize_header_hash(TxStruct *tx) if (tx->overwintered) { uint32_t ver = tx->version | TX_OVERWINTERED; hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); - uint32_t version_group_id = 0x03c48270; - hasher_Update(&(tx->hasher), (const uint8_t *)&version_group_id, 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version_group_id), 4); r += 4; } else { hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); @@ -713,7 +711,7 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_ return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered) +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id) { tx->inputs_len = inputs_len; tx->outputs_len = outputs_len; @@ -728,6 +726,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v tx->is_segwit = false; tx->is_decred = false; tx->overwintered = overwintered; + tx->version_group_id = version_group_id; hasher_Init(&(tx->hasher), hasher_sign); } diff --git a/firmware/transaction.h b/firmware/transaction.h index 90aa6f9fa3..c247b5c079 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -35,6 +35,7 @@ typedef struct { uint32_t outputs_len; uint32_t version; + uint32_t version_group_id; uint32_t lock_time; uint32_t expiry; bool is_segwit; @@ -71,7 +72,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputTyp uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output, uint8_t *out); uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output); From cf83a97c845b62704b8a6ae4cce75749f54c2165 Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Mon, 6 Aug 2018 10:21:53 -0400 Subject: [PATCH 0926/1154] eth: add Ether-1 (ETHO) --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 638b700af4..b0d9eeb1e2 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -264,6 +264,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 1987: suffix = " EGEM"; break; // EtherGem case 31102: suffix = " ESN"; break; // Ethersocial Network case 200625: suffix = " AKA"; break; // Akroma + case 1313114: suffix = " ETHO"; break; // Ether-1 case 7762959: suffix = " MUSI"; break; // Musicoin default : suffix = " UNKN"; break; // unknown chain } From df5348fb14e1cd6a5c581be2fa0efe20415739bf Mon Sep 17 00:00:00 2001 From: Yannick Heneault Date: Fri, 10 Aug 2018 09:40:08 -0400 Subject: [PATCH 0927/1154] emulator: support /dev/{u,}random configuration at compile time; default is still /dev/urandom (#396) --- Makefile.include | 4 ++++ emulator/setup.c | 26 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Makefile.include b/Makefile.include index cc517be78e..d1911aa92c 100644 --- a/Makefile.include +++ b/Makefile.include @@ -98,6 +98,10 @@ CFLAGS += -I/usr/include/SDL2 -D_REENTRANT LDLIBS += -lSDL2 endif +ifdef RANDOM_DEV_FILE +CFLAGS += -DRANDOM_DEV_FILE=\"$(RANDOM_DEV_FILE)\" +endif + else ifdef APPVER CFLAGS += -DAPPVER=$(APPVER) diff --git a/emulator/setup.c b/emulator/setup.c index 8000aa4ea9..61b4bad149 100644 --- a/emulator/setup.c +++ b/emulator/setup.c @@ -34,11 +34,15 @@ #define EMULATOR_FLASH_FILE "emulator.img" +#ifndef RANDOM_DEV_FILE +#define RANDOM_DEV_FILE "/dev/urandom" +#endif + uint8_t *emulator_flash_base = NULL; uint32_t __stack_chk_guard; -static int urandom = -1; +static int random_fd = -1; static void setup_urandom(void); static void setup_flash(void); @@ -53,17 +57,21 @@ void __attribute__((noreturn)) shutdown(void) { } void emulatorRandom(void *buffer, size_t size) { - ssize_t n = read(urandom, buffer, size); - if (n < 0 || ((size_t) n) != size) { - perror("Failed to read /dev/urandom"); - exit(1); - } + ssize_t n, len = 0; + do { + n = read(random_fd, (char*)buffer + len, size - len); + if (n < 0) { + perror("Failed to read " RANDOM_DEV_FILE); + exit(1); + } + len += n; + } while (len != (ssize_t)size); } static void setup_urandom(void) { - urandom = open("/dev/urandom", O_RDONLY); - if (urandom < 0) { - perror("Failed to open /dev/urandom"); + random_fd = open(RANDOM_DEV_FILE, O_RDONLY); + if (random_fd < 0) { + perror("Failed to open " RANDOM_DEV_FILE); exit(1); } } From 47de7ff63931a55e92e816ee25104b80c39176d8 Mon Sep 17 00:00:00 2001 From: HackyMiner Date: Tue, 14 Aug 2018 18:21:54 +0900 Subject: [PATCH 0928/1154] ethereum: fixed tokenByChainAddress() to use 32bit chain_id (#398) --- firmware/ethereum_tokens.c | 2 +- firmware/ethereum_tokens.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index b7d89ec207..1c9bffe7aa 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -722,7 +722,7 @@ const TokenType tokens[TOKENS_COUNT] = { const TokenType *UnknownToken = (const TokenType *)1; -const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address) +const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address) { if (!address) return 0; for (int i = 0; i < TOKENS_COUNT; i++) { diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index 1b60e594e3..c8383f0a04 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -25,7 +25,7 @@ #define TOKENS_COUNT 716 typedef struct { - uint8_t chain_id; + uint32_t chain_id; const char * const address; const char * const ticker; int decimals; @@ -35,6 +35,6 @@ extern const TokenType tokens[TOKENS_COUNT]; extern const TokenType *UnknownToken; -const TokenType *tokenByChainAddress(uint8_t chain_id, const uint8_t *address); +const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address); #endif From 9a519fb5c0ca1b2c29fde44e1a2565ba19f87d80 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 14 Aug 2018 14:28:11 +0200 Subject: [PATCH 0929/1154] travis: leave the emulator a little time to boot up --- script/test | 1 + 1 file changed, 1 insertion(+) diff --git a/script/test b/script/test index 56fc7d818f..8ef1437fb6 100755 --- a/script/test +++ b/script/test @@ -10,6 +10,7 @@ if [ "$EMULATOR" = 1 ]; then trap "kill %1" EXIT firmware/trezor.elf & + sleep 1 export TREZOR_PATH=udp:127.0.0.1:21324 fi From bdbabf5594e2c5dba9f2b52d59e742c506eacd60 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 14 Aug 2018 14:59:31 +0200 Subject: [PATCH 0930/1154] build: when running test, wait until emulator starts properly --- script/test | 1 + script/wait_for_emulator.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100755 script/wait_for_emulator.py diff --git a/script/test b/script/test index 8ef1437fb6..b6bc428ff3 100755 --- a/script/test +++ b/script/test @@ -12,6 +12,7 @@ if [ "$EMULATOR" = 1 ]; then firmware/trezor.elf & sleep 1 export TREZOR_PATH=udp:127.0.0.1:21324 + "${PYTHON:-python}" script/wait_for_emulator.py fi export TREZOR_TRANSPORT_V1=1 diff --git a/script/wait_for_emulator.py b/script/wait_for_emulator.py new file mode 100755 index 0000000000..035104b151 --- /dev/null +++ b/script/wait_for_emulator.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +import socket +import sys +import time + +DEFAULT_ADDR = "127.0.0.1:21324" + +if len(sys.argv) > 1: + addr = sys.argv[1] +else: + addr = DEFAULT_ADDR + +host, port = addr.split(":") +SOCK_ADDR = (host, int(port)) + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.connect(SOCK_ADDR) +sock.settimeout(0) + +start = time.monotonic() +while True: + try: + sock.sendall(b"PINGPING") + r = sock.recv(8) + if r == b"PONGPONG": + break + except Exception: + time.sleep(0.05) +end = time.monotonic() +print("waited for {:.3f}s".format(end - start)) From 809e313bebcb3fd1e3d6c7a1084a9f10ba07d7ed Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 14 Aug 2018 15:08:03 +0200 Subject: [PATCH 0931/1154] build: drop the sleep that is now superseded by waiting script --- script/test | 1 - 1 file changed, 1 deletion(-) diff --git a/script/test b/script/test index b6bc428ff3..58ef45ffa3 100755 --- a/script/test +++ b/script/test @@ -10,7 +10,6 @@ if [ "$EMULATOR" = 1 ]; then trap "kill %1" EXIT firmware/trezor.elf & - sleep 1 export TREZOR_PATH=udp:127.0.0.1:21324 "${PYTHON:-python}" script/wait_for_emulator.py fi From d114665da77a03c8dffa9eb5dc5a31b9aaa3fdf0 Mon Sep 17 00:00:00 2001 From: HackyMiner Date: Wed, 15 Aug 2018 02:45:44 +0900 Subject: [PATCH 0932/1154] ethereum: support full range 32bit chain_id (#399) --- firmware/ethereum.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index b0d9eeb1e2..851d84e16f 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -202,7 +202,9 @@ static void send_signature(void) msg_tx_request.has_data_length = false; msg_tx_request.has_signature_v = true; - if (chain_id) { + if (chain_id > MAX_CHAIN_ID) { + msg_tx_request.signature_v = v; + } else if (chain_id) { msg_tx_request.signature_v = v + 2 * chain_id + 35; } else { msg_tx_request.signature_v = v + 27; @@ -464,7 +466,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { - if (msg->chain_id < 1 || msg->chain_id > MAX_CHAIN_ID) { + if (msg->chain_id < 1) { fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Chain Id out of bounds")); ethereum_signing_abort(); return; From 0e3bbd61e0ba4123459cc6129908d41ae630f9a8 Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Wed, 15 Aug 2018 05:29:53 -0400 Subject: [PATCH 0933/1154] eth: Add Pirl support (#400) --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 851d84e16f..0ad1324c49 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -268,6 +268,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 200625: suffix = " AKA"; break; // Akroma case 1313114: suffix = " ETHO"; break; // Ether-1 case 7762959: suffix = " MUSI"; break; // Musicoin + case 3125659152: suffix = " PIRL"; break; // Pirl default : suffix = " UNKN"; break; // unknown chain } } From 2214b99d6455401fc9e5ecdab601f44967540dda Mon Sep 17 00:00:00 2001 From: Yannick Heneault Date: Wed, 15 Aug 2018 13:40:50 -0400 Subject: [PATCH 0934/1154] Added fullscreen mode for emulator. Setting the environment variable TREZOR_OLED_FULLSCREEN to non-zero activate that mode. (#402) --- emulator/oled.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/emulator/oled.c b/emulator/oled.c index 1f61981667..cbb853c85c 100644 --- a/emulator/oled.c +++ b/emulator/oled.c @@ -31,9 +31,19 @@ void emulatorPoll(void) {} static SDL_Renderer *renderer = NULL; static SDL_Texture *texture = NULL; +static SDL_Rect dstrect; +#define ENV_OLED_FULLSCREEN "TREZOR_OLED_FULLSCREEN" #define ENV_OLED_SCALE "TREZOR_OLED_SCALE" +static int emulatorFullscreen(void) { + const char *variable = getenv(ENV_OLED_FULLSCREEN); + if (!variable) { + return 0; + } + return atoi(variable); +} + static int emulatorScale(void) { const char *variable = getenv(ENV_OLED_SCALE); if (!variable) { @@ -54,13 +64,14 @@ void oledInit(void) { atexit(SDL_Quit); int scale = emulatorScale(); + int fullscreen = emulatorFullscreen(); SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH * scale, OLED_HEIGHT * scale, - 0); + fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); if (window == NULL) { fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); @@ -72,9 +83,27 @@ void oledInit(void) { fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); exit(1); } + if (fullscreen) { + SDL_DisplayMode current_mode; + if (SDL_GetCurrentDisplayMode(0, ¤t_mode) != 0) + { + fprintf(stderr, "Failed to get current display mode: %s\n", SDL_GetError()); + exit(1); + } - /* Use unscaled coordinate system */ - SDL_RenderSetLogicalSize(renderer, OLED_WIDTH, OLED_HEIGHT); + dstrect.x = (current_mode.w - OLED_WIDTH * scale) / 2; + dstrect.y = (current_mode.h - OLED_HEIGHT * scale) / 2; + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + SDL_ShowCursor(SDL_DISABLE); + } else { + dstrect.x = 0; + dstrect.y = 0; + } + + dstrect.w = OLED_WIDTH * scale; + dstrect.h = OLED_HEIGHT * scale; texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); @@ -101,7 +130,7 @@ void oledRefresh(void) { } SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); - SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderCopy(renderer, texture, NULL, &dstrect); SDL_RenderPresent(renderer); /* Return it back */ From 33dcb4ae8ad3c8e78a034af89ac52e3070d715db Mon Sep 17 00:00:00 2001 From: Yannick Heneault Date: Wed, 15 Aug 2018 13:41:26 -0400 Subject: [PATCH 0935/1154] use pkg-config to find sdl2 installation correctly. (#391) --- Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.include b/Makefile.include index d1911aa92c..01fa7fdb4e 100644 --- a/Makefile.include +++ b/Makefile.include @@ -94,8 +94,8 @@ CFLAGS += -DHEADLESS=1 else CFLAGS += -DHEADLESS=0 -CFLAGS += -I/usr/include/SDL2 -D_REENTRANT -LDLIBS += -lSDL2 +CFLAGS += $(shell pkg-config --cflags sdl2) +LDLIBS += $(shell pkg-config --libs sdl2) endif ifdef RANDOM_DEV_FILE From b7a82060a92479fd305d694c21900484d8eb2b6a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 20 Aug 2018 15:51:17 +0200 Subject: [PATCH 0936/1154] ethereum: fix max_chain_id --- firmware/ethereum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 0ad1324c49..004b8fc094 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -37,7 +37,7 @@ #include "messages.pb.h" /* maximum supported chain id. v must fit in an uint32_t. */ -#define MAX_CHAIN_ID 2147483630 +#define MAX_CHAIN_ID 2147483629 static bool ethereum_signing = false; static uint32_t data_total, data_left; From a265a9cc505307bd0e3b445bdbb03edb48b51f3f Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Fri, 24 Aug 2018 10:23:02 -0400 Subject: [PATCH 0937/1154] ethereum: add AtheiosChain (ATH) chain_id --- firmware/ethereum.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 004b8fc094..54c0d9a0a1 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -263,6 +263,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, case 62: suffix = " tETC"; break; // Ethereum Classic Testnet case 64: suffix = " ELLA"; break; // Ellaism case 820: suffix = " CLO"; break; // Callisto + case 1620: suffix = " ATH"; break; // Atheios case 1987: suffix = " EGEM"; break; // EtherGem case 31102: suffix = " ESN"; break; // Ethersocial Network case 200625: suffix = " AKA"; break; // Akroma From 7c3040d6fce9ad6f5f8e8fd88f1690f4ee66371b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 16:09:31 +0200 Subject: [PATCH 0938/1154] firmware: update ChangeLog, bump to 1.6.3 --- firmware/ChangeLog | 5 +++++ firmware/trezor.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index cfe0edffbb..becb44ec4b 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,8 @@ +Version 1.6.3 [unreleased] +* Stable release, optional update +* implement RSKIP-60 Ethereum checksum encoding +* add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH) + Version 1.6.2 * Stable release, optional update * Add possibility to set custom auto-lock delay diff --git a/firmware/trezor.h b/firmware/trezor.h index f1ae52d06f..228d93769f 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -24,7 +24,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 6 -#define VERSION_PATCH 2 +#define VERSION_PATCH 3 #define STR(X) #X #define VERSTR(X) STR(X) From 0bbb3aef895d87e85354965a51cf95892ab9129a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 16:41:56 +0200 Subject: [PATCH 0939/1154] firmware: add missing include to fsm --- firmware/fsm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/fsm.c b/firmware/fsm.c index e1cff17b01..0cba9b9c9c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -57,6 +57,7 @@ #include "gettext.h" #include "supervise.h" #include "stellar.h" +#include "messages.pb.h" // message methods From 66b85c975797056545abd29c35bfb661a3eb6c58 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:08:02 +0200 Subject: [PATCH 0940/1154] firmware: update Ethereum networks --- firmware/ChangeLog | 2 +- firmware/ethereum.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index becb44ec4b..41e8ba7faa 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,7 +1,7 @@ Version 1.6.3 [unreleased] * Stable release, optional update * implement RSKIP-60 Ethereum checksum encoding -* add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH) +* add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH, GO) Version 1.6.2 * Stable release, optional update diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 54c0d9a0a1..9e1dbfbeb5 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -251,14 +251,15 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, switch (chain_id) { case 1: suffix = " ETH"; break; // Ethereum case 2: suffix = " EXP"; break; // Expanse - case 3: suffix = " tETH"; break; // Ethereum Testnet Ropsten - case 4: suffix = " tETH"; break; // Ethereum Testnet Rinkeby + case 3: suffix = " tROP"; break; // Ethereum Testnet Ropsten + case 4: suffix = " tRIN"; break; // Ethereum Testnet Rinkeby case 8: suffix = " UBQ"; break; // UBIQ case 20: suffix = " EOSC"; break; // EOS Classic case 28: suffix = " ETSC"; break; // Ethereum Social case 30: suffix = " RSK"; break; // RSK case 31: suffix = " tRSK"; break; // RSK Testnet - case 42: suffix = " tETH"; break; // Ethereum Testnet Kovan + case 42: suffix = " tKOV"; break; // Ethereum Testnet Kovan + case 60: suffix = " GO"; break; // GoChain case 61: suffix = " ETC"; break; // Ethereum Classic case 62: suffix = " tETC"; break; // Ethereum Classic Testnet case 64: suffix = " ELLA"; break; // Ellaism From b7535f20a4e1e1a0fab281230eacea44dea48cd1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:16:13 +0200 Subject: [PATCH 0941/1154] firmware: add new ethereum tokens --- firmware/ChangeLog | 1 + firmware/ethereum_tokens.c | 95 ++++++++++++++++++++++++++++++++++---- firmware/ethereum_tokens.h | 2 +- 3 files changed, 89 insertions(+), 9 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 41e8ba7faa..4a9261b19b 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -2,6 +2,7 @@ Version 1.6.3 [unreleased] * Stable release, optional update * implement RSKIP-60 Ethereum checksum encoding * add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH, GO) +* add support for new 80 Ethereum tokens Version 1.6.2 * Stable release, optional update diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c index 1c9bffe7aa..93ed7f232d 100644 --- a/firmware/ethereum_tokens.c +++ b/firmware/ethereum_tokens.c @@ -7,12 +7,14 @@ const TokenType tokens[TOKENS_COUNT] = { {61, "\x5a\xce\x17\xf8\x7c\x73\x91\xe5\x79\x2a\x76\x83\x06\x9a\x80\x25\xb8\x3b\xbd\x85", " PLAY", 0}, // etc / Smart Billions { 1, "\x4e\x84\xe9\xe5\xfb\x0a\x97\x26\x28\xcf\x45\x68\xc4\x03\x16\x7e\xf1\xd4\x04\x31", " $FFC", 18}, // eth / $Fluzcoin { 1, "\xa0\x24\xe8\x05\x7e\xec\x47\x4a\x9b\x23\x56\x83\x37\x07\xdd\x05\x79\xe2\x6e\xf3", " $FXY", 18}, // eth / $FIXY NETWORK + { 1, "\xcd\xb7\xec\xfd\x34\x03\xee\xf3\x88\x2c\x65\xb7\x61\xef\x9b\x50\x54\x89\x0a\x47", " $HUR", 18}, // eth / $Hurify Token { 1, "\x7d\xd7\xf5\x6d\x69\x7c\xc0\xf2\xb5\x2b\xd5\x5c\x05\x7f\x37\x8f\x1f\xe6\xab\x4b", " $TEAK", 18}, // eth / $TEAK { 1, "\xb6\xed\x76\x44\xc6\x94\x16\xd6\x7b\x52\x2e\x20\xbc\x29\x4a\x9a\x9b\x40\x5b\x31", " 0xBTC", 8}, // eth / 0xBitcoin { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, // eth / FirstBlood { 1, "\xfd\xbc\x1a\xdc\x26\xf0\xf8\xf8\x60\x6a\x5d\x63\xb7\xd3\xa3\xcd\x21\xc2\x2b\x23", " 1WO", 8}, // eth / 1WO { 1, "\x9f\xc0\x58\x32\x20\xeb\x44\xfa\xee\x9e\x2d\xc1\xe6\x3f\x39\x20\x4d\xdd\x90\x90", " 2DC", 18}, // eth / DualChain { 1, "\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", " 300", 18}, // eth / 300 Token Sparta + { 1, "\x43\x02\x41\x36\x8c\x1d\x29\x3f\xda\x21\xdb\xa8\xbb\x7a\xf3\x20\x07\xc5\x91\x09", " 3LT", 8}, // eth / TrillionToken { 1, "\xbd\xe8\xf7\x82\x0b\x55\x44\xa4\x9d\x34\xf9\xdd\xea\xca\xbe\xdc\x7c\x0b\x5a\xdc", " A18", 0}, // eth / Apollo18 { 1, "\xb9\x8d\x4c\x97\x42\x5d\x99\x08\xe6\x6e\x53\xa6\xfd\xf6\x73\xac\xca\x0b\xe9\x86", " ABT", 18}, // eth / ArcBlock Token { 1, "\x0e\x8d\x6b\x47\x1e\x33\x2f\x14\x0e\x7d\x9d\xbb\x99\xe5\xe3\x82\x2f\x72\x8d\xa6", " ABYSS", 18}, // eth / ABYSS @@ -28,11 +30,13 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x4c\xed\xa7\x90\x6a\x5e\xd2\x17\x97\x85\xcd\x3a\x40\xa6\x9e\xe8\xbc\x99\xc4\x66", " AION", 8}, // eth / Aion { 1, "\x27\xdc\xe1\xec\x4d\x3f\x72\xc3\xe4\x57\xcc\x50\x35\x4f\x1f\x97\x5d\xde\xf4\x88", " AIR", 8}, // eth / AirToken { 1, "\x10\x63\xce\x52\x42\x65\xd5\xa3\xa6\x24\xf4\x91\x4a\xcd\x57\x3d\xd8\x9c\xe9\x88", " AIX", 18}, // eth / Aigang + { 1, "\x1c\xa4\x3a\x17\x0b\xad\x61\x93\x22\xe6\xf5\x4d\x46\xb5\x7e\x50\x4d\xb6\x63\xaa", " AKC", 18}, // eth / ARTWOOK COIN { 1, "\x18\x1a\x63\x74\x6d\x3a\xdc\xf3\x56\xcb\xc7\x3a\xce\x22\x83\x2f\xfb\xb1\xee\x5a", " ALCO", 8}, // eth / ALCO { 1, "\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab", " ALIS", 18}, // eth / ALIS Token { 1, "\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa", " ALTS", 18}, // eth / ALTS Token { 1, "\x4d\xc3\x64\x3d\xbc\x64\x2b\x72\xc1\x58\xe7\xf3\xd2\xff\x23\x2d\xf6\x1c\xb6\xce", " AMB", 18}, // eth / Amber Token { 1, "\x94\x9b\xed\x88\x6c\x73\x9f\x1a\x32\x73\x62\x9b\x33\x20\xdb\x0c\x50\x24\xc7\x19", " AMIS", 9}, // eth / AMIS + { 1, "\xca\x0e\x72\x69\x60\x0d\x35\x3f\x70\xb1\x4a\xd1\x18\xa4\x95\x75\x45\x5c\x0f\x2f", " AMLT", 18}, // eth / AMLT { 1, "\x73\x7f\x98\xac\x8c\xa5\x9f\x2c\x68\xad\x65\x8e\x3c\x3d\x8c\x89\x63\xe4\x0a\x4c", " AMN", 18}, // eth / Amon { 1, "\x38\xc8\x7a\xa8\x9b\x2b\x8c\xd9\xb9\x5b\x73\x6e\x1f\xa7\xb6\x12\xea\x97\x21\x69", " AMO", 18}, // eth / AMO Coin { 1, "\x84\x93\x6c\xf7\x63\x0a\xa3\xe2\x7d\xd9\xaf\xf9\x68\xb1\x40\xd5\xae\xe4\x9f\x5a", " AMTC", 8}, // eth / AmberTime Coin @@ -40,7 +44,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x4c\x0f\xbe\x1b\xb4\x66\x12\x91\x5e\x79\x67\xd2\xc3\x21\x3c\xd4\xd8\x72\x57\xad", " APIS", 18}, // eth / APIS { 1, "\x1a\x7a\x8b\xd9\x10\x6f\x2b\x8d\x97\x7e\x08\x58\x2d\xc7\xd2\x4c\x72\x3a\xb0\xdb", " APPC", 18}, // eth / AppCoins { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, // eth / AIGang - { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, // eth / ARC + { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, // eth / Arcade Token { 1, "\x12\x45\xef\x80\xf4\xd9\xe0\x2e\xd9\x42\x53\x75\xe8\xf6\x49\xb9\x22\x1b\x31\xd8", " ARCT", 8}, // eth / ArbitrageCT { 1, "\x75\xaa\x7b\x0d\x02\x53\x2f\x38\x33\xb6\x6c\x7f\x0a\xd3\x53\x76\xd3\x73\xdd\xf8", " ARD", 18}, // eth / Accord { 1, "\xba\x5f\x11\xb1\x6b\x15\x57\x92\xcf\x3b\x2e\x68\x80\xe8\x70\x68\x59\xa8\xae\xb6", " ARN", 8}, // eth / Aeron Token @@ -58,6 +62,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x0d\x88\xed\x6e\x74\xbb\xfd\x96\xb8\x31\x23\x16\x38\xb6\x6c\x05\x57\x1e\x82\x4f", " AVT", 18}, // eth / AVT { 1, "\xcd\x4b\x4b\x0f\x32\x84\xa3\x3a\xc4\x9c\x67\x96\x1e\xc6\xe1\x11\x70\x83\x18\xcf", " AX1", 5}, // eth / AX1 Mining Token { 1, "\x9a\xf2\xc6\xb1\xa2\x8d\x3d\x6b\xc0\x84\xbd\x26\x7f\x70\xe9\x0d\x49\x74\x1d\x5b", " AXP", 8}, // eth / AXP + { 1, "\xc3\x9e\x62\x6a\x04\xc5\x97\x1d\x77\x0e\x31\x97\x60\xd7\x92\x65\x02\x97\x5e\x47", " AXPR", 18}, // eth / aXpire { 1, "\xf8\x7f\x0d\x91\x53\xfe\xa5\x49\xc7\x28\xad\x61\xcb\x80\x15\x95\xa6\x8b\x73\xde", " BANX", 18}, // eth / BANX { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, // eth / BAT { 1, "\x4a\x60\x58\x66\x6c\xf1\x05\x7e\xac\x3c\xd3\xa5\xa6\x14\x62\x05\x47\x55\x9f\xc9", " BBK", 18}, // eth / BRICKBLOCK TOKEN @@ -72,6 +77,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BeerCoin", 0}, // eth / BeerCoin { 1, "\x6a\xeb\x95\xf0\x6c\xda\x84\xca\x34\x5c\x2d\xe0\xf3\xb7\xf9\x69\x23\xa4\x4f\x4c", " BERRY", 14}, // eth / Berry { 1, "\x8a\xa3\x3a\x78\x99\xfc\xc8\xea\x5f\xbe\x6a\x60\x8a\x10\x9c\x38\x93\xa1\xb8\xb2", " BET", 18}, // eth / BET + { 1, "\x14\xc9\x26\xf2\x29\x00\x44\xb6\x47\xe1\xbf\x20\x72\xe6\x7b\x49\x5e\xff\x19\x05", " BETHER", 18}, // eth / Bethereum { 1, "\x76\x31\x86\xeb\x8d\x48\x56\xd5\x36\xed\x44\x78\x30\x29\x71\x21\x4f\xeb\xc6\xa9", " BETR", 18}, // eth / BETR { 1, "\xb2\xbf\xeb\x70\xb9\x03\xf1\xba\xac\x7f\x2b\xa2\xc6\x29\x34\xc7\xe5\xb9\x74\xc4", " BKB", 8}, // eth / BetKing Bankroll Token { 1, "\x3c\xf9\xe0\xc3\x85\xa5\xab\xec\x9f\xd2\xa7\x17\x90\xaa\x34\x4c\x4e\x8e\x35\x70", " BKRx", 18}, // eth / BlockRx @@ -93,6 +99,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xcc\x34\x36\x6e\x38\x42\xca\x1b\xd3\x6c\x1f\x32\x4d\x15\x25\x79\x60\xfc\xc8\x01", " BON", 18}, // eth / Bonpay { 1, "\x7f\x1e\x2c\x7d\x6a\x69\xbf\x34\x82\x4d\x72\xc5\x3b\x45\x50\xe8\x95\xc0\xd8\xc2", " BOP", 8}, // eth / BlockOptiopns Token { 1, "\xc2\xc6\x3f\x23\xec\x5e\x97\xef\xbd\x75\x65\xdf\x9e\xc7\x64\xfd\xc7\xd4\xe9\x1d", " BOU", 18}, // eth / Boule Coin + { 1, "\xe1\xa1\x78\xb6\x81\xbd\x05\x96\x4d\x3e\x3e\xd3\x3a\xe7\x31\x57\x7d\x9d\x96\xdd", " BOX", 18}, // eth / BOX Token { 1, "\x32\x76\x82\x77\x9b\xab\x2b\xf4\xd1\x33\x7e\x89\x74\xab\x9d\xe8\x27\x5a\x7c\xa8", " BPT", 18}, // eth / Blockport Token { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, // eth / Bitquence { 1, "\x9e\x77\xd5\xa1\x25\x1b\x6f\x7d\x45\x67\x22\xa6\xea\xc6\xd2\xd5\x98\x0b\xd8\x91", " BRAT", 8}, // eth / BRAT @@ -111,22 +118,25 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x16\xb0\xe6\x2a\xc1\x3a\x2f\xae\xd3\x6d\x18\xbc\xe2\x35\x6d\x25\xab\x3c\xfa\xd3", " BTQ", 18}, // eth / Bitcoin Boutique { 1, "\x08\x0a\xa0\x7e\x2c\x71\x85\x15\x0d\x7e\x4d\xa9\x88\x38\xa8\xd2\xfe\xac\x3d\xfc", " BTT", 0}, // eth / Bitether { 1, "\xfa\x45\x6c\xf5\x52\x50\xa8\x39\x08\x8b\x27\xee\x32\xa4\x24\xd7\xda\xcb\x54\xff", " BTTX", 18}, // eth / Blocktrade.com + { 1, "\xe5\xf8\x67\xde\x1e\xa8\x13\x46\xdf\x51\x81\xb8\xb4\x8d\xd6\xb0\xbb\x33\x57\xb0", " BTZ", 18}, // eth / BTZ by Bunz { 1, "\xca\x3c\x18\xa6\x5b\x80\x2e\xc2\x67\xf8\xf4\x80\x25\x45\xe7\xf5\x3d\x24\xc7\x5e", " BUC", 18}, // eth / BeeUnity Chain { 1, "\x26\xe7\x53\x07\xfc\x0c\x02\x14\x72\xfe\xb8\xf7\x27\x83\x95\x31\xf1\x12\xf3\x17", " C20", 18}, // eth / Crypto20's Token { 1, "\xd4\x2d\xeb\xe4\xed\xc9\x2b\xd5\xa3\xfb\xb4\x24\x3e\x1e\xcc\xf6\xd6\x3a\x4a\x5d", " C8", 18}, // eth / Carboneum { 1, "\x7d\x4b\x8c\xce\x05\x91\xc9\x04\x4a\x22\xee\x54\x35\x33\xb7\x2e\x97\x6e\x36\xc3", " CAG", 18}, // eth / Change Bank { 1, "\x1d\x46\x24\x14\xfe\x14\xcf\x48\x9c\x7a\x21\xca\xc7\x85\x09\xf4\xbf\x8c\xd7\xc0", " CAN", 6}, // eth / CAN { 1, "\x42\x3e\x43\x22\xcd\xda\x29\x15\x6b\x49\xa1\x7d\xfb\xd2\xac\xc4\xb2\x80\x60\x0d", " CAR", 9}, // eth / Car Sharing Community + { 1, "\x4d\x9e\x23\xa3\x84\x2f\xe7\xeb\x76\x82\xb9\x72\x5c\xf6\xc5\x07\xc4\x24\xa4\x1b", " CAR (CarBlock)", 18}, // eth / CarBlock { 1, "\xa5\x17\xa4\x6b\xaa\xd6\xb0\x54\xa7\x6b\xd1\x9c\x46\x84\x4f\x71\x7f\xe6\x9f\xea", " CARB", 8}, // eth / CarbCoin { 1, "\x21\x08\xe6\x2d\x33\x5b\xbd\xc8\x9e\xc3\xe9\xd8\x58\x2f\x18\xdc\xfb\x0c\xdf\xf4", " CARCO", 8}, // eth / CARCO { 1, "\x1e\xd2\xb1\xea\xed\x8e\x96\x8b\xc3\x6e\xb9\x0a\x91\x46\x60\xa7\x18\x27\xa5\xe9", " CARD", 0}, // eth / Cardstack Token + { 1, "\xb0\x7e\xc2\xc2\x88\x34\xb8\x89\xb1\xce\x52\x7c\xa0\xf1\x93\x64\xcd\x38\x93\x5c", " CARD", 0}, // eth / Cardstack Token { 1, "\xbf\x18\xf2\x46\xb9\x30\x1f\x23\x1e\x95\x61\xb3\x5a\x38\x79\x76\x9b\xb4\x63\x75", " CARE", 18}, // eth / Token CARE { 1, "\xe8\x78\x0b\x48\xbd\xb0\x5f\x92\x86\x97\xa5\xe8\x15\x5f\x67\x2e\xd9\x14\x62\xf7", " CAS", 18}, // eth / Cashaa { 1, "\x12\x34\x56\x74\x61\xd3\xf8\xdb\x74\x96\x58\x17\x74\xbd\x86\x9c\x83\xd5\x1c\x93", " CAT (BitClave)", 18}, // eth / CAT (BitClave) { 1, "\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", " CAT (Blockcat)", 18}, // eth / CAT (Blockcat) { 1, "\x68\xe1\x4b\xb5\xa4\x5b\x96\x81\x32\x7e\x16\xe5\x28\x08\x4b\x9d\x96\x2c\x1a\x39", " CATs (BitClave)_Old", 18}, // eth / CATs (BitClave)_Old + { 1, "\x05\xc3\x61\x7c\xbf\x13\x04\xb9\x26\x0a\xa6\x1e\xc9\x60\xf1\x15\xd6\x7b\xec\xea", " CBIX", 18}, // eth / Cubrix { 1, "\xc1\x66\x03\x87\x05\xff\xba\xb3\x79\x41\x85\xb3\xa9\xd9\x25\x63\x2a\x1d\xf3\x7d", " CC3", 18}, // eth / Coal Coin - { 1, "\x28\x57\x7a\x6d\x31\x55\x9b\xd2\x65\xce\x3a\xdb\x62\xd0\x45\x85\x50\xf7\xb8\xa7", " CCC (CryptoCrashCourse)", 18}, // eth / CryptoCrashCourse { 1, "\xbe\x11\xee\xb1\x86\xe6\x24\xb8\xf2\x6a\x50\x45\x57\x5a\x13\x40\xe4\x05\x45\x52", " CCC (ICONOMI)", 18}, // eth / CCC (ICONOMI) { 1, "\xd3\x48\xe0\x7a\x28\x06\x50\x5b\x85\x61\x23\x04\x5d\x27\xae\xed\x90\x92\x4b\x50", " CCLC", 8}, // eth / Christ Coin { 1, "\x31\x5c\xe5\x9f\xaf\xd3\xa8\xd5\x62\xb7\xec\x1c\x85\x42\x38\x2d\x27\x10\xb0\x6c", " CCS", 18}, // eth / CacaoShares @@ -135,6 +145,8 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x6f\xff\x38\x06\xbb\xac\x52\xa2\x0e\x0d\x79\xbc\x53\x8d\x52\x7f\x6a\x22\xc9\x6b", " CDX", 18}, // eth / CDX { 1, "\x2c\xb1\x01\xd7\xda\x0e\xba\xa5\x7d\x3f\x2f\xef\x46\xd7\xff\xb7\xbb\x64\x59\x2b", " CDX", 0}, // eth / Carbon Dollar X { 1, "\xb0\x56\xc3\x8f\x6b\x7d\xc4\x06\x43\x67\x40\x3e\x26\x42\x4c\xd2\xc6\x06\x55\xe1", " CEEK", 18}, // eth / CEEK VR Token + { 1, "\xf6\x60\xca\x1e\x22\x8e\x7b\xe1\xfa\x8b\x4f\x55\x83\x14\x5e\x31\x14\x7f\xb5\x77", " CET", 18}, // eth / DICE Money Dicet + { 1, "\x5d\xff\x89\xa2\xca\xa4\xd7\x6b\xc2\x86\xf7\x4d\x67\xbd\x71\x8e\xb8\x34\xda\x61", " CFC", 18}, // eth / CryptFillCoin { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, // eth / Cofound.it { 1, "\x69\x56\x98\x3f\x8b\x3c\xe1\x73\xb4\xab\x84\x36\x1a\xa0\xad\x52\xf3\x8d\x93\x6f", " CFTY", 8}, // eth / Crafty Token { 1, "\xba\x9d\x41\x99\xfa\xb4\xf2\x6e\xfe\x35\x51\xd4\x90\xe3\x82\x14\x86\xf1\x35\xba", " CHSB", 8}, // eth / CHSB @@ -154,6 +166,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x31\x36\xef\x85\x15\x92\xac\xf4\x9c\xa4\xc8\x25\x13\x1e\x36\x41\x70\xfa\x32\xb3", " COFI", 18}, // eth / CoinFi Token { 1, "\x0c\x91\xb0\x15\xab\xa6\xf7\xb4\x73\x8d\xcd\x36\xe7\x41\x01\x38\xb2\x9a\xdc\x29", " COIL", 8}, // eth / CoinOil { 1, "\x5e\x8f\x85\x59\x66\xd6\x38\x13\x5a\x96\x88\x61\xe8\x0d\xda\x72\x22\x91\xb0\x6d", " COIN", 18}, // eth / Coinvest V2 Token + { 1, "\x72\x5b\x19\x0b\xc0\x77\xff\xde\x17\xcf\x54\x9a\xa8\xba\x25\xe2\x98\x55\x0b\x18", " CORI", 2}, // eth / Corrently Invest Token { 1, "\x65\x29\x2e\xea\xdf\x14\x26\xcd\x2d\xf1\xc4\x79\x3a\x3d\x75\x19\xf2\x53\x91\x3b", " COSS", 18}, // eth / Coss Token { 1, "\x9e\x96\x60\x44\x45\xec\x19\xff\xed\x9a\x5e\x8d\xd7\xb5\x0a\x29\xc8\x99\xa1\x0c", " COSS", 18}, // eth / Coss Token { 1, "\xe2\xfb\x65\x29\xef\x56\x6a\x08\x0e\x6d\x23\xde\x0b\xd3\x51\x31\x10\x87\xd5\x67", " COV", 18}, // eth / Covesting @@ -163,11 +176,14 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, // eth / CRB { 1, "\x67\x2a\x1a\xd4\xf6\x67\xfb\x18\xa3\x33\xaf\x13\x66\x7a\xa0\xaf\x1f\x5b\x5b\xdd", " CRED", 18}, // eth / CRED { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, // eth / Credo / Bitbounce + { 1, "\xf4\x9c\xdd\x50\xad\x40\x8d\x38\x7d\x61\x1f\x88\xa6\x47\x17\x9c\x3d\xe3\x49\x2b", " CRGO", 18}, // eth / CargoCoin + { 1, "\x92\x38\xbf\xb7\x81\xa5\x5e\xac\xc3\xcf\x05\xf7\xdf\x94\x03\x8c\x19\x8c\xd9\xb9", " CRMT", 8}, // eth / Cremit { 1, "\x80\xa7\xe0\x48\xf3\x7a\x50\x50\x03\x51\xc2\x04\xcb\x40\x77\x66\xfa\x3b\xae\x7f", " CRPT", 18}, // eth / CrypteriumToken { 1, "\xf0\xda\x11\x86\xa4\x97\x72\x26\xb9\x13\x5d\x06\x13\xee\x72\xe2\x29\xec\x3f\x4d", " CRT", 18}, // eth / CreamtoeCoin { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CryptoCarbon", 6}, // eth / CryptoCarbon { 1, "\x45\x45\x75\x0f\x39\xaf\x6b\xe4\xf2\x37\xb6\x86\x9d\x4e\xcc\xa9\x28\xfd\x5a\x85", " CTF", 18}, // eth / CryptoTask { 1, "\xc8\x7c\x5d\xd8\x6a\x3d\x56\x7f\xf2\x87\x01\x88\x6f\xb0\x74\x5a\xaa\x89\x8d\xa4", " CTG", 18}, // eth / CT Global Token + { 1, "\x9e\x7d\x29\xbd\x49\x9b\x6c\x7d\xa2\xa5\xb2\xea\xfc\xf4\xa3\x9d\x3b\xd8\x45\xd1", " CTGC", 18}, // eth / Convenient To Go { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, // eth / CTL { 1, "\xe3\xfa\x17\x7a\xce\xcf\xb8\x67\x21\xcf\x6f\x9f\x42\x06\xbd\x3b\xd6\x72\xd7\xd5", " CTT", 18}, // eth / ChainTrade Token { 1, "\x66\x2a\xbc\xad\x0b\x7f\x34\x5a\xb7\xff\xb1\xb1\xfb\xb9\xdf\x78\x94\xf1\x8e\x66", " CTX", 18}, // eth / CarTaxi @@ -175,6 +191,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, // eth / CVC { 1, "\x21\x34\x05\x7c\x0b\x46\x1f\x89\x8d\x37\x5c\xea\xd6\x52\xac\xae\x62\xb5\x95\x41", " CXC", 18}, // eth / CoxxxCoin { 1, "\xb6\xee\x96\x68\x77\x1a\x79\xbe\x79\x67\xee\x29\xa6\x3d\x41\x84\xf8\x09\x71\x43", " CXO", 18}, // eth / CargoX + { 1, "\x3f\x06\xb5\xd7\x84\x06\xcd\x97\xbd\xf1\x0f\x5c\x42\x0b\x24\x1d\x32\x75\x9c\x80", " CYFM", 18}, // eth / CyberFM { 1, "\xda\xb0\xc3\x1b\xf3\x4c\x89\x7f\xb0\xfe\x90\xd1\x2e\xc9\x40\x1c\xaf\x5c\x36\xec", " DAB", 0}, // eth / DAB { 1, "\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba", " DADI", 18}, // eth / DADI { 1, "\x89\xd2\x4a\x6b\x4c\xcb\x1b\x6f\xaa\x26\x25\xfe\x56\x2b\xdd\x9a\x23\x26\x03\x59", " DAI", 18}, // eth / Dai Stablecoin v1.0 @@ -188,6 +205,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x61\x72\x5f\x3d\xb4\x00\x4a\xfe\x01\x47\x45\xb2\x1d\xab\x1e\x16\x77\xcc\x32\x8b", " DAXT", 18}, // eth / Digital Asset Exchange Token { 1, "\xe8\x14\xae\xe9\x60\xa8\x52\x08\xc3\xdb\x54\x2c\x53\xe7\xd4\xa6\xc8\xd5\xf6\x0f", " DAY", 18}, // eth / ChronoLogic DAY { 1, "\x38\x6f\xaa\x47\x03\xa3\x4a\x7f\xdb\x19\xbe\xc2\xe1\x4f\xd4\x27\xc9\x63\x84\x16", " DCA", 18}, // eth / DoBetAcceptBet + { 1, "\xff\xa9\x3a\xac\xf4\x92\x97\xd5\x1e\x21\x18\x17\x45\x28\x39\x05\x2f\xdf\xb9\x61", " DCC", 18}, // eth / Distributed Credit Chain { 1, "\x39\x9a\x0e\x6f\xbe\xb3\xd7\x4c\x85\x35\x74\x39\xf4\xc8\xae\xd9\x67\x8a\x5c\xbf", " DCL", 3}, // eth / DCL { 1, "\x08\xd3\x2b\x0d\xa6\x3e\x2c\x3b\xcf\x80\x19\xc9\xc5\xd8\x49\xd7\xa9\xd7\x91\xe6", " DCN", 0}, // eth / Dentacoin { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, // eth / DDF @@ -195,16 +213,21 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x07\x5c\x60\xee\x2c\xd3\x08\xff\x47\x87\x3b\x38\xbd\x9a\x0f\xa5\x85\x33\x82\xc4", " DEEZ", 18}, // eth / DeezNuts { 1, "\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", " DENT", 8}, // eth / DENT { 1, "\x7c\xf2\x71\x96\x6f\x36\x34\x3b\xf0\x15\x0f\x25\xe5\x36\x4f\x79\x61\xc5\x82\x01", " DEPO", 0}, // eth / CRYPTODEPOZIT + { 1, "\x89\xcb\xea\xc5\xe8\xa1\x3f\x0e\xbb\x4c\x74\xfa\xdf\xc6\x9b\xe8\x1a\x50\x11\x06", " DEPO (Depository Network)", 18}, // eth / DEPO (Depository Network) { 1, "\xdd\x94\xde\x9c\xfe\x06\x35\x77\x05\x1a\x5e\xb7\x46\x5d\x08\x31\x7d\x88\x08\xb6", " Devcon2 Token", 0}, // eth / Devcon2 Token { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, // eth / Digix DAO { 1, "\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1", " DGPT", 18}, // eth / DigiPulse - { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX", 9}, // eth / DGX + { 1, "\x6a\xed\xbf\x8d\xff\x31\x43\x72\x20\xdf\x35\x19\x50\xba\x2a\x33\x62\x16\x8d\x1b", " DGS", 8}, // eth / Dragonglass + { 1, "\x1c\x83\x50\x14\x78\xf1\x32\x09\x77\x04\x70\x08\x49\x6d\xac\xbd\x60\xbb\x15\xef", " DGTX", 18}, // eth / DigitexFutures + { 1, "\x4f\x3a\xfe\xc4\xe5\xa3\xf2\xa6\xa1\xa4\x11\xde\xf7\xd7\xdf\xe5\x0e\xe0\x57\xbf", " DGX", 9}, // eth / Digix Gold Token + { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, // eth / Digix Gold Token 1.0 { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, // eth / Etheroll + { 1, "\xc7\x19\xd0\x10\xb6\x3e\x5b\xbf\x2c\x05\x51\x87\x2c\xd5\x31\x6e\xd2\x6a\xcd\x83", " DIP", 18}, // eth / Decentralized Insurance Protocol { 1, "\x13\xf1\x1c\x99\x05\xa0\x8c\xa7\x6e\x3e\x85\x3b\xe6\x3d\x4f\x09\x44\x32\x6c\x72", " DIVX", 18}, // eth / DIVX { 1, "\xba\x18\x7b\x09\xff\xa8\xdd\xdc\x80\xd2\x57\x1e\xd3\xcb\xc4\xbe\x0a\xf6\x9e\x0c", " DKP", 18}, // eth / Draggin Karma Points { 1, "\x07\xe3\xc7\x06\x53\x54\x8b\x04\xf0\xa7\x59\x70\xc1\xf8\x1b\x4c\xbb\xfb\x60\x6f", " DLT", 18}, // eth / Agrello { 1, "\x2c\xcb\xff\x3a\x04\x2c\x68\x71\x6e\xd2\xa2\xcb\x0c\x54\x4a\x9f\x1d\x19\x35\xe1", " DMT", 8}, // eth / DMarket Token - { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, // eth / DistrictOx + { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, // eth / District0x Network Token { 1, "\xe4\x3e\x20\x41\xdc\x37\x86\xe1\x66\x96\x1e\xd9\x48\x4a\x55\x39\x03\x3d\x10\xfb", " DNX", 18}, // eth / DenCity { 1, "\x76\x97\x4c\x7b\x79\xdc\x8a\x6a\x10\x9f\xd7\x1f\xd7\xce\xb9\xe4\x0e\xff\x53\x82", " DOW", 18}, // eth / DOW { 1, "\xee\xf6\xe9\x00\x34\xee\xa8\x9e\x31\xeb\x4b\x8e\xac\xd3\x23\xf2\x8a\x92\xea\xe4", " DOW", 18}, // eth / DOW @@ -214,6 +237,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x46\x72\xba\xd5\x27\x10\x74\x71\xcb\x50\x67\xa8\x87\xf4\x65\x6d\x58\x5a\x8a\x31", " DROP (dropil)", 18}, // eth / Dropil { 1, "\x27\x99\xd9\x0c\x6d\x44\xcb\x9a\xa5\xfb\xc3\x77\x17\x7f\x16\xc3\x3e\x05\x6b\x82", " DRP", 0}, // eth / Dripcoin { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, // eth / DCorp + { 1, "\x62\xd4\xc0\x46\x44\x31\x4f\x35\x86\x8b\xa4\xc6\x5c\xc2\x7a\x77\x68\x1d\xe7\xa9", " DRVH", 18}, // eth / Driveholic Token { 1, "\x1e\x09\xbd\x8c\xad\xb4\x41\x63\x2e\x44\x1d\xb3\xe1\xd7\x99\x09\xee\x0a\x22\x56", " DSC", 1}, // eth / Digital Safe Coin { 1, "\x5a\xdc\x96\x1d\x6a\xc3\xf7\x06\x2d\x2e\xa4\x5f\xef\xb8\xd8\x16\x7d\x44\xb1\x90", " DTH", 18}, // eth / dether { 1, "\xd2\x34\xbf\x24\x10\xa0\x00\x9d\xf9\xc3\xc6\x3b\x61\x0c\x09\x73\x8f\x18\xcc\xd7", " DTR", 8}, // eth / DTR @@ -227,9 +251,11 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xeb\x7c\x20\x02\x71\x72\xe5\xd1\x43\xfb\x03\x0d\x50\xf9\x1c\xec\xe2\xd1\x48\x5d", " eBTC", 8}, // eth / eBTC { 1, "\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", " ECN", 2}, // eth / ECN { 1, "\x17\xf9\x34\x75\xd2\xa9\x78\xf5\x27\xc3\xf7\xc4\x4a\xbf\x44\xad\xfb\xa6\x0d\x5c", " ECO2", 2}, // eth / EtherCO2 + { 1, "\xae\xa1\xc1\x8a\x99\x29\x84\x83\x10\x02\xd0\xcf\x90\xe2\x91\xfb\x52\xd7\x26\x49", " ECP", 18}, // eth / ECRYPTO COIN { 1, "\xfa\x1d\xe2\xee\x97\xe4\xc1\x0c\x94\xc9\x1c\xb2\xb5\x06\x2b\x89\xfb\x14\x0b\x82", " EDC", 6}, // eth / Education Credits { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, // eth / Edgeless { 1, "\xce\xd4\xe9\x31\x98\x73\x4d\xda\xff\x84\x92\xd5\x25\xbd\x25\x8d\x49\xeb\x38\x8e", " EDO", 18}, // eth / Eidoo + { 1, "\xc5\x28\xc2\x8f\xec\x0a\x90\xc0\x83\x32\x8b\xc4\x5f\x58\x7e\xe2\x15\x76\x0a\x0f", " EDR", 18}, // eth / Endor Protocol Token { 1, "\x5b\x26\xc5\xd0\x77\x2e\x5b\xba\xc8\xb3\x18\x2a\xe9\xa1\x3f\x9b\xb2\xd0\x37\x65", " EDU", 8}, // eth / EDU { 1, "\x2a\x22\xe5\xcc\xa0\x0a\x3d\x63\x30\x8f\xa3\x9f\x29\x20\x2e\xb1\xb3\x9e\xef\x52", " EDU", 6}, // eth / EDU Token { 1, "\xb5\x3a\x96\xbc\xbd\xd9\xcf\x78\xdf\xf2\x0b\xab\x6c\x2b\xe7\xba\xec\x8f\x00\xf8", " eGAS", 8}, // eth / ETH GAS @@ -238,6 +264,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xbf\x21\x79\x85\x9f\xc6\xd5\xbe\xe9\xbf\x91\x58\x63\x2d\xc5\x16\x78\xa4\x10\x0e", " ELF", 18}, // eth / ELF Token { 1, "\xc8\xc6\xa3\x1a\x4a\x80\x6d\x37\x10\xa7\xb3\x8b\x7b\x29\x6d\x2f\xab\xcc\xdb\xa8", " ELIX", 18}, // eth / Elixir Token { 1, "\x44\x19\x7a\x4c\x44\xd6\xa0\x59\x29\x7c\xaf\x6b\xe4\xf7\xe1\x72\xbd\x56\xca\xaf", " ELTCOIN", 8}, // eth / ELTCOIN + { 1, "\xa9\x55\x92\xdc\xff\xa3\xc0\x80\xb4\xb4\x0e\x45\x9c\x5f\x56\x92\xf6\x7d\xb7\xf8", " ELY", 18}, // eth / ELYCOIN { 1, "\xb6\x7b\x88\xa2\x57\x08\xa3\x5a\xe7\xc2\xd7\x36\xd3\x98\xd2\x68\xce\x4f\x7f\x83", " EMON", 8}, // eth / Etheremon { 1, "\x95\xda\xaa\xb9\x80\x46\x84\x6b\xf4\xb2\x85\x3e\x23\xcb\xa2\x36\xfa\x39\x4a\x31", " EMONT", 8}, // eth / Etheremon Token { 1, "\x95\x01\xbf\xc4\x88\x97\xdc\xee\xad\xf7\x31\x13\xef\x63\x5d\x2f\xf7\xee\x4b\x97", " EMT", 18}, // eth / easyMINE Token @@ -260,8 +287,11 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xd7\x80\xae\x2b\xf0\x4c\xd9\x6e\x57\x7d\x3d\x01\x47\x62\xf8\x31\xd9\x71\x29\xd0", " EVN", 18}, // eth / Envion AG { 1, "\xf3\xdb\x5f\xa2\xc6\x6b\x7a\xf3\xeb\x0c\x0b\x78\x25\x10\x81\x6c\xbe\x48\x13\xb8", " EVX", 4}, // eth / EVX Token { 1, "\xc9\x8e\x06\x39\xc6\xd2\xec\x03\x7a\x61\x53\x41\xc3\x69\x66\x6b\x11\x0e\x80\xe5", " EXMR", 8}, // eth / eXMRcoin + { 1, "\x5c\x74\x3a\x35\xe9\x03\xf6\xc5\x84\x51\x4e\xc6\x17\xac\xee\x06\x11\xcf\x44\xf3", " EXY", 18}, // eth / Experty { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, // eth / FAM + { 1, "\x90\x16\x2f\x41\x88\x6c\x09\x46\xd0\x99\x99\x73\x6f\x1c\x15\xc8\xa1\x05\xa4\x21", " FAN", 18}, // eth / Fan Token { 1, "\x7f\x67\x15\xc3\xfc\x47\x40\xa0\x2f\x70\xde\x85\xb9\xfd\x50\xac\x60\x01\xfe\xd9", " FANX", 18}, // eth / FANX Token + { 1, "\x7d\xcb\x3b\x23\x56\xc8\x22\xd3\x57\x7d\x4d\x06\x0d\x0d\x5d\x78\xc8\x60\x48\x8c", " FANX", 18}, // eth / FANX Token { 1, "\x00\x9e\x86\x49\x23\xb4\x92\x63\xc7\xf1\x0d\x19\xb7\xf8\xab\x7a\x9a\x5a\xad\x33", " FKX", 18}, // eth / Knoxstertoken { 1, "\xf0\x4a\x8a\xc5\x53\xfc\xed\xb5\xba\x99\xa6\x47\x99\x15\x58\x26\xc1\x36\xb0\xbe", " FLIXX", 18}, // eth / FLIXX { 1, "\x04\xcc\x78\x3b\x45\x0b\x8d\x11\xf3\xc7\xd0\x0d\xd0\x3f\xdf\x7f\xb5\x1f\xe9\xf2", " FLMC", 18}, // eth / Filmscoin @@ -275,10 +305,12 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe6\xf7\x4d\xcf\xa0\xe2\x08\x83\x00\x8d\x8c\x16\xb6\xd9\xa3\x29\x18\x9d\x0c\x30", " FTC", 2}, // eth / FTC { 1, "\x20\x23\xdc\xf7\xc4\x38\xc8\xc8\xc0\xb0\xf2\x8d\xba\xe1\x55\x20\xb4\xf3\xee\x20", " FTR", 18}, // eth / Futourist Token { 1, "\x2a\xec\x18\xc5\x50\x0f\x21\x35\x9c\xe1\xbe\xa5\xdc\x17\x77\x34\x4d\xf4\xc0\xdc", " FTT", 18}, // eth / FarmaTrust Token + { 1, "\x41\x87\x5c\x23\x32\xb0\x87\x7c\xdf\xaa\x69\x9b\x64\x14\x02\xb7\xd4\x64\x2c\x32", " FTXT", 8}, // eth / FUTURAX { 1, "\x65\xbe\x44\xc7\x47\x98\x8f\xbf\x60\x62\x07\x69\x8c\x94\x4d\xf4\x44\x2e\xfe\x19", " FUCK", 4}, // eth / Finally Usable Crypto Karma { 1, "\xab\x16\xe0\xd2\x5c\x06\xcb\x37\x62\x59\xcc\x18\xc1\xde\x4a\xca\x57\x60\x55\x89", " FUCK", 4}, // eth / FinallyUsableCryptoKarma { 1, "\xea\x38\xea\xa3\xc8\x6c\x8f\x9b\x75\x15\x33\xba\x2e\x56\x2d\xeb\x9a\xcd\xed\x40", " FUEL", 18}, // eth / Etherparty FUEL { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, // eth / Funfair + { 1, "\xc9\x2d\x6e\x3e\x64\x30\x2c\x59\xd7\x34\xf3\x29\x2e\x2a\x13\xa1\x3d\x7e\x18\x17", " FXC", 8}, // eth / FUTURAX { 1, "\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", " FYN", 18}, // eth / Fund Yourself Now { 1, "\xf6\x74\x51\xdc\x84\x21\xf0\xe0\xaf\xeb\x52\xfa\xa8\x10\x10\x34\xed\x08\x1e\xd9", " GAM", 8}, // eth / Gambit { 1, "\x67\x54\xe2\x1b\x9e\xaa\x05\x3c\x62\xd7\x85\x4d\xd6\x56\x1a\xe4\x51\xb0\xcb\xcf", " GANA", 18}, // eth / GANA @@ -299,21 +331,25 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xea\xb4\x31\x93\xcf\x06\x23\x07\x3c\xa8\x9d\xb9\xb7\x12\x79\x63\x56\xfa\x74\x14", " GOLDX", 18}, // eth / GOLDX { 1, "\x12\xb1\x9d\x3e\x2c\xcc\x14\xda\x04\xfa\xe3\x3e\x63\x65\x2c\xe4\x69\xb3\xf2\xfd", " GRID", 12}, // eth / GRID { 1, "\x0a\x9a\x9c\xe6\x00\xd0\x8b\xf9\xb7\x6f\x49\xfa\x4e\x7b\x38\xa6\x7e\xbe\xb1\xe6", " GROW", 8}, // eth / Growchain + { 1, "\xe5\x30\x44\x1f\x4f\x73\xbd\xb6\xdc\x2f\xa5\xaf\x7c\x3f\xc5\xfd\x55\x1e\xc8\x38", " GSE", 4}, // eth / GSENetwork { 1, "\xb7\x08\x35\xd7\x82\x2e\xbb\x94\x26\xb5\x65\x43\xe3\x91\x84\x6c\x10\x7b\xd3\x2c", " GTC", 18}, // eth / GTC Token { 1, "\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", " GTKT", 0}, // eth / GTKT { 1, "\xc5\xbb\xae\x50\x78\x1b\xe1\x66\x93\x06\xb9\xe0\x01\xef\xf5\x7a\x29\x57\xb0\x9d", " GTO", 5}, // eth / Gifto + { 1, "\x98\x47\x34\x5d\xe8\xb6\x14\xc9\x56\x14\x6b\xbe\xa5\x49\x33\x6d\x9c\x8d\x26\xb6", " GULD", 8}, // eth / GULD ERC20 { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, // eth / GUP { 1, "\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0", " GVT", 18}, // eth / Genesis Vision { 1, "\x58\xca\x30\x65\xc0\xf2\x4c\x7c\x96\xae\xe8\xd6\x05\x6b\x5b\x5d\xec\xf9\xc2\xf8", " GXC", 10}, // eth / GXC { 1, "\x22\xf0\xaf\x8d\x78\x85\x1b\x72\xee\x79\x9e\x05\xf5\x4a\x77\x00\x15\x86\xb1\x8a", " GXVC", 10}, // eth / Genevieve VC { 1, "\x8c\x65\xe9\x92\x29\x7d\x5f\x09\x2a\x75\x6d\xef\x24\xf4\x78\x1a\x28\x01\x98\xff", " GZE", 18}, // eth / GazeCoin { 1, "\xe6\x38\xdc\x39\xb6\xad\xbe\xe8\x52\x6b\x5c\x22\x38\x0b\x4b\x45\xda\xf4\x6d\x8e", " GZR", 6}, // eth / Gizer + { 1, "\x5a\x56\x7e\x28\xdb\xfa\x2b\xbd\x3e\xf1\x3c\x0a\x01\xbe\x11\x47\x45\x34\x96\x57", " HAPPY", 2}, // eth / Happiness { 1, "\x90\x02\xd4\x48\x5b\x75\x94\xe3\xe8\x50\xf0\xa2\x06\x71\x3b\x30\x51\x13\xf6\x9e", " HAT", 18}, // eth / Hawala Today { 1, "\xc0\x11\xa7\x24\x00\xe5\x8e\xcd\x99\xee\x49\x7c\xf8\x9e\x37\x75\xd4\xbd\x73\x2f", " HAV", 18}, // eth / Havven { 1, "\xff\xe8\x19\x6b\xc2\x59\xe8\xde\xdc\x54\x4d\x93\x57\x86\xaa\x47\x09\xec\x3e\x64", " HDG", 18}, // eth / Hedge Crypto { 1, "\xe9\xff\x07\x80\x9c\xcf\xf0\x5d\xae\x74\x99\x0e\x25\x83\x1d\x0b\xc5\xcb\xe5\x75", " Hdp", 18}, // eth / HEdpAY { 1, "\xba\x21\x84\x52\x0a\x1c\xc4\x9a\x61\x59\xc5\x7e\x61\xe1\x84\x4e\x08\x56\x15\xb6", " HGT", 8}, // eth / HGT - { 1, "\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44", " HIG", 18}, // eth / ethereumhigh + { 1, "\x9b\xb1\xdb\x14\x45\xb8\x32\x13\xa5\x6d\x90\xd3\x31\x89\x4b\x3f\x26\x21\x8e\x4e", " HIBT", 18}, // eth / HiBTC Token + { 1, "\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44", " HIG", 18}, // eth / ethereumhigh { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, // eth / HKG { 1, "\x88\xac\x94\xd5\xd1\x75\x13\x03\x47\xfc\x95\xe1\x09\xd7\x7a\xc0\x9d\xbf\x5a\xb7", " HKY", 18}, // eth / Hicky { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, // eth / HMQ @@ -346,6 +382,8 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x6f\xb3\xe0\xa2\x17\x40\x7e\xff\xf7\xca\x06\x2d\x46\xc2\x6e\x5d\x60\xa1\x4d\x69", " IOTX", 18}, // eth / IoTeX Network { 1, "\x64\xcd\xf8\x19\xd3\xe7\x5a\xc8\xec\x21\x7b\x34\x96\xd7\xce\x16\x7b\xe4\x2e\x80", " IPL", 18}, // eth / InsurePal token { 1, "\x00\x1f\x0a\xa5\xda\x15\x58\x5e\x5b\x23\x05\xdb\xab\x2b\xac\x42\x5e\xa7\x10\x07", " IPSX", 18}, // eth / IPSX + { 1, "\x0d\xb8\xd8\xb7\x6b\xc3\x61\xba\xcb\xb7\x2e\x2c\x49\x1e\x06\x08\x5a\x97\xab\x31", " IQN", 18}, // eth / IQeon + { 1, "\x0c\xf7\x13\xb1\x1c\x9b\x98\x6e\xc4\x0d\x65\xbd\x4f\x7f\xbd\x50\xf6\xff\x2d\x64", " IST34", 18}, // eth / IST34 Token { 1, "\x5e\x6b\x6d\x9a\xba\xd9\x09\x3f\xdc\x86\x1e\xa1\x60\x0e\xba\x1b\x35\x5c\xd9\x40", " ITC", 18}, // eth / IoT Chain { 1, "\x0a\xef\x06\xdc\xcc\xc5\x31\xe5\x81\xf0\x44\x00\x59\xe6\xff\xcc\x20\x60\x39\xee", " ITT", 8}, // eth / ITT Token { 1, "\xfc\xa4\x79\x62\xd4\x5a\xdf\xdf\xd1\xab\x2d\x97\x23\x15\xdb\x4c\xe7\xcc\xf0\x94", " IXT", 8}, // eth / InsureX @@ -370,6 +408,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xfd\x10\x7b\x47\x3a\xb9\x0e\x8f\xbd\x89\x87\x21\x44\xa3\xdc\x92\xc4\x0f\xa8\xc9", " LALA", 18}, // eth / LALA World Token { 1, "\x51\x02\x79\x1c\xa0\x2f\xc3\x59\x53\x98\x40\x0b\xfe\x0e\x33\xd7\xb6\xc8\x22\x67", " LDC", 18}, // eth / LEADCOIN { 1, "\xd6\xe3\x54\xf0\x73\x19\xe2\x47\x44\x91\xd8\xc7\xc7\x12\x13\x7b\xee\x68\x62\xa2", " LEMO", 0}, // eth / Lemo + { 1, "\x60\xc2\x44\x07\xd0\x17\x82\xc2\x17\x5d\x32\xfe\x7c\x89\x21\xed\x73\x23\x71\xd1", " LEMO", 18}, // eth / Lemo { 1, "\xb5\xae\x84\x8e\xdb\x29\x6c\x21\x25\x9b\x74\x67\x33\x14\x67\xd2\x64\x7e\xec\xdf", " LEMO", 18}, // eth / Lemo { 1, "\x80\xfb\x78\x4b\x7e\xd6\x67\x30\xe8\xb1\xdb\xd9\x82\x0a\xfd\x29\x93\x1a\xab\x03", " LEND", 18}, // eth / EHTLend { 1, "\xc7\x98\xcd\x1c\x49\xdb\x0e\x29\x73\x12\xe4\xc6\x82\x75\x26\x68\xce\x1d\xb2\xad", " LFR", 5}, // eth / LifeRun Coin @@ -381,13 +420,15 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe2\xe6\xd4\xbe\x08\x6c\x69\x38\xb5\x3b\x22\x14\x48\x55\xee\xf6\x74\x28\x16\x39", " LINK Platform", 18}, // eth / Link Platform { 1, "\x24\xa7\x7c\x1f\x17\xc5\x47\x10\x5e\x14\x81\x3e\x51\x7b\xe0\x6b\x00\x40\xaa\x76", " LIVE", 18}, // eth / LIVE Token { 1, "\x63\xe6\x34\x33\x0a\x20\x15\x0d\xbb\x61\xb1\x56\x48\xbc\x73\x85\x5d\x6c\xcf\x07", " LNC", 18}, // eth / Lancer Token - { 1, "\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66", " LNC-Linker Coin", 18}, // eth / Linker Coin + { 1, "\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66", " LNC (Linker Coin)", 18}, // eth / Linker Coin { 1, "\x09\x47\xb0\xe6\xd8\x21\x37\x88\x05\xc9\x59\x82\x91\x38\x5c\xe7\xc7\x91\xa6\xb2", " LND", 18}, // eth / Lendingblock { 1, "\x5e\x33\x46\x44\x40\x10\x13\x53\x22\x26\x8a\x46\x30\xd2\xed\x5f\x8d\x09\x44\x6c", " LOC", 18}, // eth / LockChain { 1, "\x9c\x23\xd6\x7a\xea\x7b\x95\xd8\x09\x42\xe3\x83\x6b\xcd\xf7\xe7\x08\xa7\x47\xc2", " LOCI", 18}, // eth / LOCIcoin { 1, "\xc6\x45\x00\xdd\x7b\x0f\x17\x94\x80\x7e\x67\x80\x2f\x8a\xbb\xf5\xf8\xff\xb0\x54", " LOCUS", 18}, // eth / Locus Chain { 1, "\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", " LOK", 18}, // eth / LOK + { 1, "\x25\x3c\x7d\xd0\x74\xf4\xba\xcb\x30\x53\x87\xf9\x22\x22\x5a\x4f\x73\x7c\x08\xbd", " LOOK", 18}, // eth / LookRev { 1, "\xa4\xe8\xc3\xec\x45\x61\x07\xea\x67\xd3\x07\x5b\xf9\xe3\xdf\x3a\x75\x82\x3d\xb0", " LOOM", 18}, // eth / LOOM + { 1, "\x5a\x27\x6a\xeb\x77\xbc\xfd\xac\x8a\xc6\xf3\x1b\xbc\x74\x16\xae\x1a\x85\xee\xf2", " LOVE", 0}, // eth / Love { 1, "\x58\xb6\xa8\xa3\x30\x23\x69\xda\xec\x38\x33\x34\x67\x24\x04\xee\x73\x3a\xb2\x39", " LPT", 18}, // eth / Livepeer Token { 1, "\xef\x68\xe7\xc6\x94\xf4\x0c\x82\x02\x82\x1e\xdf\x52\x5d\xe3\x78\x24\x58\x63\x9f", " LRC", 18}, // eth / LRC { 1, "\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19", " LUC", 18}, // eth / LUCToken @@ -408,6 +449,8 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x01\xf2\xac\xf2\x91\x48\x60\x33\x1c\x1c\xb1\xa9\xac\xec\xda\x74\x75\xe0\x6a\xf8", " MESH", 18}, // eth / Meshbox { 1, "\x5b\x8d\x43\xff\xde\x4a\x29\x82\xb9\xa5\x38\x7c\xdf\x21\xd5\x4e\xad\x64\xac\x8d", " MEST", 18}, // eth / Monaco Estate { 1, "\x67\x10\xc6\x34\x32\xa2\xde\x02\x95\x4f\xc0\xf8\x51\xdb\x07\x14\x6a\x6c\x03\x12", " MFG", 18}, // eth / SyncFab Smart Manufacturing Blockchain + { 1, "\xdf\x2c\x72\x38\x19\x8a\xd8\xb3\x89\x66\x65\x74\xf2\xd8\xbc\x41\x1a\x4b\x74\x28", " MFT", 18}, // eth / Mainframe Token + { 1, "\x05\xd4\x12\xce\x18\xf2\x40\x40\xbb\x3f\xa4\x5c\xf2\xc6\x9e\x50\x65\x86\xd8\xe8", " MFTU", 18}, // eth / Mainstream For The Underground { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, // eth / MGO { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, // eth / MIT { 1, "\xad\x8d\xd4\xc7\x25\xde\x1d\x31\xb9\xe8\xf8\xd1\x46\x08\x9e\x9d\xc6\x88\x20\x93", " MIT (Mychatcoin)", 6}, // eth / Mychatcoin @@ -423,6 +466,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", " MRV", 18}, // eth / MRV { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, // eth / Mothership { 1, "\x90\x5e\x33\x7c\x6c\x86\x45\x26\x3d\x35\x21\x20\x5a\xa3\x7b\xf4\xd0\x34\xe7\x45", " MTC", 18}, // eth / Medical Token Currency + { 1, "\xdf\xdc\x0d\x82\xd9\x6f\x8f\xd4\x0c\xa0\xcf\xb4\xa2\x88\x95\x5b\xec\xec\x20\x88", " MTC", 18}, // eth / MTC Mesh Network { 1, "\xaf\x4d\xce\x16\xda\x28\x77\xf8\xc9\xe0\x05\x44\xc9\x3b\x62\xac\x40\x63\x1f\x16", " MTH", 5}, // eth / Monetha { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, // eth / MetalPay { 1, "\x41\xdb\xec\xc1\xcd\xc5\x51\x7c\x6f\x76\xf6\xa6\xe8\x36\xad\xbe\xe2\x75\x4d\xe3", " MTN", 18}, // eth / MedToken @@ -451,6 +495,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c", " NOX", 18}, // eth / NOX { 1, "\x4c\xe6\xb3\x62\xbc\x77\xa2\x49\x66\xdd\xa9\x07\x8f\x9c\xef\x81\xb3\xb8\x86\xa7", " NPER", 18}, // eth / NPER { 1, "\xa1\x5c\x7e\xbe\x1f\x07\xca\xf6\xbf\xf0\x97\xd8\xa5\x89\xfb\x8a\xc4\x9a\xe5\xb3", " NPXS", 18}, // eth / Pundi X Token + { 1, "\x24\x5e\xf4\x7d\x4d\x05\x05\xec\xf3\xac\x46\x3f\x4d\x81\xf4\x1a\xde\x8f\x1f\xd1", " NUG", 18}, // eth / Nuggets Token { 1, "\xb9\x13\x18\xf3\x5b\xdb\x26\x2e\x94\x23\xbc\x7c\x7c\x2a\x3a\x93\xdd\x93\xc9\x2c", " NULS", 18}, // eth / NULS { 1, "\x57\xab\x1e\x02\xfe\xe2\x37\x74\x58\x0c\x11\x97\x40\x12\x9e\xac\x70\x81\xe9\xd3", " nUSD", 18}, // eth / Havven-Backed USD Nomins (nUSD) { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, // eth / Nexium @@ -459,21 +504,27 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x5e\x88\x8b\x83\xb7\x28\x7e\xed\x4f\xb7\xda\x7b\x7d\x0a\x0d\x4c\x73\x5d\x94\xb3", " OAK", 18}, // eth / OAK { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, // eth / OAX { 1, "\x02\x35\xfe\x62\x4e\x04\x4a\x05\xee\xd7\xa4\x3e\x16\xe3\x08\x3b\xc8\xa4\x28\x7a", " OCC", 18}, // eth / Original Crypto Coin + { 1, "\xbf\x52\xf2\xab\x39\xe2\x6e\x09\x51\xd2\xa0\x2b\x49\xb7\x70\x2a\xbe\x30\x40\x6a", " ODE", 18}, // eth / ODEM Token { 1, "\x6f\x53\x9a\x94\x56\xa5\xbc\xb6\x33\x4a\x1a\x41\x20\x7c\x37\x88\xf5\x82\x52\x07", " OHNI", 18}, // eth / Ohni { 1, "\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", " OHNI", 0}, // eth / OHNI { 1, "\xbe\xef\x54\x6a\xc8\xa4\xe0\xa8\x0d\xc1\xe2\xd6\x96\x96\x8e\xf5\x41\x38\xf1\xd4", " OJX", 18}, // eth / Ojooo Coin { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " OLD_MKR", 18}, // eth / MakerDAO + { 1, "\x64\xa6\x04\x93\xd8\x88\x72\x8c\xf4\x26\x16\xe0\x34\xa0\xdf\xea\xe3\x8e\xfc\xf0", " OLT", 18}, // eth / OneLedger Token { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, // eth / OMG + { 1, "\x04\x71\x87\xe5\x34\x77\xbe\x70\xdb\xe8\xea\x5b\x79\x93\x18\xf2\xe1\x65\x05\x2f", " OMT", 18}, // eth / OTCMAKER Token { 1, "\xb2\x3b\xe7\x35\x73\xbc\x7e\x03\xdb\x6e\x5d\xfc\x62\x40\x53\x68\x71\x6d\x28\xa8", " ONEK", 18}, // eth / One K Token { 1, "\xd3\x41\xd1\x68\x0e\xee\xe3\x25\x5b\x8c\x4c\x75\xbc\xce\x7e\xb5\x7f\x14\x4d\xae", " onG", 18}, // eth / onG { 1, "\x69\xc4\xbb\x24\x0c\xf0\x5d\x51\xee\xab\x69\x85\xba\xb3\x55\x27\xd0\x4a\x8c\x64", " OPEN", 8}, // eth / OPEN { 1, "\xe9\xde\x1c\x63\x07\x53\xa1\x5d\x70\x21\xcc\x56\x34\x29\xc2\x1d\x48\x87\x50\x6f", " OPEN", 8}, // eth / OPEN { 1, "\x43\x55\xfc\x16\x0f\x74\x32\x8f\x9b\x38\x3d\xf2\xec\x58\x9b\xb3\xdf\xd8\x2b\xa0", " OPT", 18}, // eth / Opus Foundation { 1, "\xff\x56\xcc\x6b\x1e\x6d\xed\x34\x7a\xa0\xb7\x67\x6c\x85\xab\x0b\x3d\x08\xb0\xfa", " ORBS", 18}, // eth / Orbs + { 1, "\x6f\x59\xe0\x46\x1a\xe5\xe2\x79\x9f\x1f\xb3\x84\x7f\x05\xa6\x3b\x16\xd0\xdb\xf8", " ORCA", 18}, // eth / ORCA Token { 1, "\x2c\x4e\x8f\x2d\x74\x61\x13\xd0\x69\x6c\xe8\x9b\x35\xf0\xd8\xbf\x88\xe0\xae\xca", " OST", 18}, // eth / Simple Token 'OST' + { 1, "\x17\x0b\x27\x5c\xed\x08\x9f\xff\xae\xbf\xe9\x27\xf4\x45\xa3\x50\xed\x91\x60\xdc", " OWN", 8}, // eth / OWNDATA { 1, "\x65\xa1\x50\x14\x96\x4f\x21\x02\xff\x58\x64\x7e\x16\xa1\x6a\x6b\x9e\x14\xbc\xf6", " Ox Fina", 3}, // eth / Ox Fina { 1, "\xfe\xda\xe5\x64\x26\x68\xf8\x63\x6a\x11\x98\x7f\xf3\x86\xbf\xd2\x15\xf9\x42\xee", " PAL", 18}, // eth / PolicyPal Network { 1, "\xea\x5f\x88\xe5\x4d\x98\x2c\xbb\x0c\x44\x1c\xde\x4e\x79\xbc\x30\x5e\x5b\x43\xbc", " PARETO", 18}, // eth / PARETO + { 1, "\x77\x76\x1e\x63\xc0\x5a\xee\x66\x48\xfd\xae\xaa\x9b\x94\x24\x83\x51\xaf\x9b\xcd", " PASS", 18}, // eth / PASS Token { 1, "\xbb\x1f\xa4\xfd\xeb\x34\x59\x73\x3b\xf6\x7e\xbc\x6f\x89\x30\x03\xfa\x97\x6a\x82", " PAT", 18}, // eth / Pangea Arbitration Token { 1, "\x69\x44\x04\x59\x5e\x30\x75\xa9\x42\x39\x7f\x46\x6a\xac\xd4\x62\xff\x1a\x7b\xd0", " PATENTS", 18}, // eth / PATENTS { 1, "\xf8\x13\xf3\x90\x2b\xbc\x00\xa6\xdc\xe3\x78\x63\x4d\x3b\x79\xd8\x4f\x98\x03\xd7", " PATH", 18}, // eth / PATH @@ -483,6 +534,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xfc\xac\x7a\x75\x15\xe9\xa9\xd7\x61\x9f\xa7\x7a\x1f\xa7\x38\x11\x1f\x66\x72\x7e", " PCH", 18}, // eth / PITCH { 1, "\x36\x18\x51\x6f\x45\xcd\x3c\x91\x3f\x81\xf9\x98\x7a\xf4\x10\x77\x93\x2b\xc4\x0d", " PCL", 8}, // eth / Peculium { 1, "\x53\x14\x8b\xb4\x55\x17\x07\xed\xf5\x1a\x1e\x8d\x7a\x93\x69\x8d\x18\x93\x12\x25", " PCLOLD", 8}, // eth / PeculiumOLD + { 1, "\x8a\xe5\x6a\x68\x50\xa7\xcb\xea\xc3\xc3\xab\x2c\xb3\x11\xe7\x62\x01\x67\xea\xc8", " PEG", 18}, // eth / PEG Network Token { 1, "\x58\x84\x96\x9e\xc0\x48\x05\x56\xe1\x1d\x11\x99\x80\x13\x6a\x4c\x17\xed\xde\xd1", " PET", 18}, // eth / PETHEREUM { 1, "\xec\x18\xf8\x98\xb4\x07\x6a\x3e\x18\xf1\x08\x9d\x33\x37\x6c\xc3\x80\xbd\xe6\x1d", " PETRO", 18}, // eth / PETRO { 1, "\x55\xc2\xa0\xc1\x71\xd9\x20\x84\x35\x60\x59\x4d\xe3\xd6\xee\xcc\x09\xef\xc0\x98", " PEXT", 4}, // eth / PEX-Token @@ -492,6 +544,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe4\x77\x29\x2f\x1b\x32\x68\x68\x7a\x29\x37\x61\x16\xb0\xed\x27\xa9\xc7\x61\x70", " PLAY", 18}, // eth / HeroCoin { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, // eth / Polybius { 1, "\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", " PLR", 18}, // eth / Pillar Project + { 1, "\xe4\x3a\xc1\x71\x4f\x73\x94\x17\x3b\x15\xe7\xcf\xf3\x1a\x63\xd5\x23\xce\x4f\xb9", " PLS", 18}, // eth / DACPLAY Token { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, // eth / Plutus { 1, "\x0e\x09\x89\xb1\xf9\xb8\xa3\x89\x83\xc2\xba\x80\x53\x26\x9c\xa6\x2e\xc9\xb1\x95", " POE", 8}, // eth / Po.et Tokens { 1, "\x43\xf6\xa1\xbe\x99\x2d\xee\x40\x87\x21\x74\x84\x90\x77\x2b\x15\x14\x3c\xe0\xa7", " POIN", 0}, // eth / Potatoin @@ -515,10 +568,12 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, // eth / PTOY { 1, "\x55\x12\xe1\xd6\xa7\xbe\x42\x4b\x43\x23\x12\x6b\x4f\x9e\x86\xd0\x23\xf9\x57\x64", " PTWO", 18}, // eth / PornTokenV2 { 1, "\xef\x6b\x4c\xe8\xc9\xbc\x83\x74\x4f\xbc\xde\x26\x57\xb3\x2e\xc1\x87\x90\x45\x8a", " PUC", 0}, // eth / Pour Coin + { 1, "\xe2\x5f\xf6\xeb\x95\x9b\xce\x67\x97\x57\x78\xe4\x6a\x47\x75\x0c\x24\x3b\x6b\x99", " PURC", 18}, // eth / PureCarbon { 1, "\xc1\x48\x30\xe5\x3a\xa3\x44\xe8\xc1\x46\x03\xa9\x12\x29\xa0\xb9\x25\xb0\xb2\x62", " PXT", 8}, // eth / Populous XBRL Token (PXT) { 1, "\x61\x8e\x75\xac\x90\xb1\x2c\x60\x49\xba\x3b\x27\xf5\xd5\xf8\x65\x1b\x00\x37\xf6", " QASH", 6}, // eth / QASH { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, // eth / QAU { 1, "\x24\x67\xaa\x6b\x5a\x23\x51\x41\x6f\xd4\xc3\xde\xf8\x46\x2d\x84\x1f\xee\xec\xec", " QBX", 18}, // eth / qiibeeToken + { 1, "\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", " QNT", 18}, // eth / Quant { 1, "\xff\xaa\x5f\xfc\x45\x5d\x91\x31\xf8\xa2\x71\x3a\x74\x1f\xd1\x96\x03\x30\x50\x8b", " QRG", 18}, // eth / QRG { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, // eth / QRL { 1, "\x99\xea\x4d\xb9\xee\x77\xac\xd4\x0b\x11\x9b\xd1\xdc\x4e\x33\xe1\xc0\x70\xb8\x0d", " QSP", 18}, // eth / Quantstamp Token @@ -532,11 +587,14 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05", " REA", 18}, // eth / Realisto { 1, "\x5f\x53\xf7\xa8\x07\x56\x14\xb6\x99\xba\xad\x0b\xc2\xc8\x99\xf4\xba\xd8\xfb\xbf", " REBL", 18}, // eth / Rebellious { 1, "\x76\x96\x0d\xcc\xd5\xa1\xfe\x79\x9f\x7c\x29\xbe\x9f\x19\xce\xb4\x62\x7a\xeb\x2f", " RED", 18}, // eth / Red Community Token + { 1, "\xb5\x63\x30\x0a\x3b\xac\x79\xfc\x09\xb9\x3b\x6f\x84\xce\x0d\x44\x65\xa2\xac\x27", " REDC", 18}, // eth / RedCab { 1, "\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38", " REN", 18}, // eth / Republic Token { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, // eth / Augur + { 1, "\x19\x85\x36\x5e\x9f\x78\x35\x9a\x9b\x6a\xd7\x60\xe3\x24\x12\xf4\xa4\x45\xe8\x62", " REP", 18}, // eth / Augur { 1, "\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a", " REQ", 18}, // eth / Request Network { 1, "\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", " REX", 18}, // eth / REX { 1, "\xd0\x92\x9d\x41\x19\x54\xc4\x74\x38\xdc\x1d\x87\x1d\xd6\x08\x1f\x5c\x5e\x14\x9c", " RFR", 4}, // eth / Refereum + { 1, "\x86\xe5\x6f\x3c\x89\xa1\x45\x28\x85\x8e\x58\xb3\xde\x48\xc0\x74\x53\x8b\xaf\x2c", " RING", 18}, // eth / Evolution Land Global Token { 1, "\xdd\x00\x72\x78\xb6\x67\xf6\xbe\xf5\x2f\xd0\xa4\xc2\x36\x04\xaa\x1f\x96\x03\x9a", " RIPT", 8}, // eth / RiptideCoin { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, // eth / IEx.ec { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, // eth / RLT @@ -573,6 +631,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x6e\x34\xd8\xd8\x47\x64\xd4\x0f\x6d\x7b\x39\xcd\x56\x9f\xd0\x17\xbf\x53\x17\x7d", " SKRP", 18}, // eth / Skraps { 1, "\xfd\xfe\x8b\x7a\xb6\xcf\x1b\xd1\xe3\xd1\x45\x38\xef\x40\x68\x62\x96\xc4\x20\x52", " SKRP", 18}, // eth / Skraps { 1, "\x7a\x5f\xf2\x95\xdc\x82\x39\xd5\xc2\x37\x4e\x4d\x89\x42\x02\xaa\xf0\x29\xca\xb6", " SLT", 3}, // eth / Smartlands + { 1, "\x79\x28\xc8\xab\xf1\xf7\x4e\xf9\xf9\x6d\x4d\x0a\x44\xe3\xb4\x20\x9d\x36\x07\x85", " SLY", 18}, // eth / Selfllery { 1, "\x6f\x6d\xeb\x5d\xb0\xc4\x99\x4a\x82\x83\xa0\x1d\x6c\xfe\xeb\x27\xfc\x3b\xbe\x9c", " SMART", 0}, // eth / Smart Billions { 1, "\x2d\xcf\xaa\xc1\x1c\x9e\xeb\xd8\xc6\xc4\x21\x03\xfe\x9e\x2a\x6a\xd2\x37\xaf\x27", " SMT", 18}, // eth / Smart Node { 1, "\x55\xf9\x39\x85\x43\x1f\xc9\x30\x40\x77\x68\x7a\x35\xa1\xba\x10\x3d\xc1\xe0\x81", " SMT", 18}, // eth / SmartMesh @@ -595,6 +654,7 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xb1\x5f\xe5\xa1\x23\xe6\x47\xba\x59\x4c\xea\x7a\x1e\x64\x86\x46\xf9\x5e\xb4\xaa", " SS", 18}, // eth / Sharder { 1, "\xbb\xff\x86\x2d\x90\x6e\x34\x8e\x99\x46\xbf\xb2\x13\x2e\xcb\x15\x7d\xa3\xd4\xb4", " SS", 18}, // eth / Sharder { 1, "\x6e\x20\x50\xcb\xfb\x3e\xd8\xa4\xd3\x9b\x64\xcc\x9f\x47\xe7\x11\xa0\x3a\x5a\x89", " SSH", 18}, // eth / StreamShares + { 1, "\x4a\x89\xcd\x48\x6f\xa9\x96\xad\x50\xc0\xa6\x3c\x35\xc7\x87\x02\xf5\x42\x2a\x50", " STABIT", 3}, // eth / StabitCoin { 1, "\x9a\x00\x5c\x9a\x89\xbd\x72\xa4\xbd\x27\x72\x1e\x7a\x09\xa3\xc1\x1d\x2b\x03\xc4", " STAC", 18}, // eth / Starter Coin { 1, "\xf7\x0a\x64\x2b\xd3\x87\xf9\x43\x80\xff\xb9\x04\x51\xc2\xc8\x1d\x4e\xb8\x2c\xbc", " STAR", 18}, // eth / Star Token { 1, "\x62\x9a\xee\x55\xed\x49\x58\x1c\x33\xab\x27\xf9\x40\x3f\x79\x92\xa2\x89\xff\xd5", " STC", 18}, // eth / StrikeCoin Token @@ -616,20 +676,24 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xc2\x7a\x2f\x05\xfa\x57\x7a\x83\xba\x0f\xdb\x4c\x38\x44\x3c\x07\x18\x35\x65\x01", " TAU", 18}, // eth / Lamden Tau { 1, "\xfa\xcc\xd5\xfc\x83\xc3\xe4\xc3\xc1\xac\x1e\xf3\x5d\x15\xad\xf0\x6b\xcf\x20\x9c", " TBC2", 8}, // eth / TBC2 { 1, "\xaf\xe6\x05\x11\x34\x1a\x37\x48\x8d\xe2\x5b\xef\x35\x19\x52\x56\x2e\x31\xfc\xc1", " TBT", 8}, // eth / TBitBot + { 1, "\xfa\x0e\xf5\xe0\x34\xca\xe1\xae\x75\x2d\x59\xbd\xb8\xad\xcd\xe3\x7e\xd7\xab\x97", " TCA", 18}, // eth / TangguoTao Token { 1, "\x2a\x1d\xba\xbe\x65\xc5\x95\xb0\x02\x2e\x75\x20\x8c\x34\x01\x41\x39\xd5\xd3\x57", " TDH", 18}, // eth / TrustedHealth { 1, "\x85\xe0\x76\x36\x1c\xc8\x13\xa9\x08\xff\x67\x2f\x9b\xad\x15\x41\x47\x44\x02\xb2", " TEL", 2}, // eth / Telcoin { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, // eth / TrueFlip { 1, "\x38\x83\xf5\xe1\x81\xfc\xca\xf8\x41\x0f\xa6\x1e\x12\xb5\x9b\xad\x96\x3f\xb6\x45", " THETA", 18}, // eth / Theta Token { 1, "\xfe\x7b\x91\x5a\x0b\xaa\x0e\x79\xf8\x5c\x55\x53\x26\x65\x13\xf7\xc1\xc0\x3e\xd0", " THUG", 18}, // eth / THUG + { 1, "\xa5\xdb\x1d\x6f\x7a\x0d\x5b\xcc\xc1\x7d\x0b\xfd\x39\xd7\xaf\x32\xd5\xe5\xed\xc6", " TICO", 5}, // eth / Topinvestmentcoin { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, // eth / Chronobank { 1, "\x80\xbc\x55\x12\x56\x1c\x7f\x85\xa3\xa9\x50\x8c\x7d\xf7\x90\x1b\x37\x0f\xa1\xdf", " TIO", 18}, // eth / TIO { 1, "\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", " TIX", 18}, // eth / Blocktix { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, // eth / TokenCard { 1, "\x08\xf5\xa9\x23\x5b\x08\x17\x3b\x75\x69\xf8\x36\x45\xd2\xc7\xfb\x55\xe8\xcc\xd8", " TNT", 8}, // eth / Tierion Network Token + { 1, "\x8e\xb9\x65\xee\x9c\xcf\xbc\xe7\x6c\x0a\x06\x26\x44\x92\xc0\xaf\xef\xc2\x82\x6d", " TOOR", 18}, // eth / ToorCoin { 1, "\xcb\x3f\x90\x2b\xf9\x76\x26\x39\x1b\xf8\xba\x87\x26\x4b\xbc\x3d\xc1\x34\x69\xbe", " TRC", 18}, // eth / The Real Coin { 1, "\x56\x6f\xd7\x99\x9b\x1f\xc3\x98\x80\x22\xbd\x38\x50\x7a\x48\xf0\xbc\xf2\x2c\x77", " TRCN", 18}, // eth / The Real Coin { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, // eth / TRST { 1, "\xf2\x30\xb7\x90\xe0\x53\x90\xfc\x82\x95\xf4\xd3\xf6\x03\x32\xc9\x3b\xed\x42\xe2", " TRX", 6}, // eth / Tron Lab Token + { 1, "\x6b\x87\x99\x9b\xe8\x73\x58\x06\x5b\xbd\xe4\x1e\x8a\x0f\xe0\xb7\xb1\xcd\x25\x14", " TSW", 18}, // eth / TeslaWatt { 1, "\x2e\xf1\xab\x8a\x26\x18\x7c\x58\xbb\x8a\xae\xb1\x1b\x2f\xc6\xd2\x5c\x5c\x07\x16", " TWN", 18}, // eth / The World News { 1, "\xfb\xd0\xd1\xc7\x7b\x50\x17\x96\xa3\x5d\x86\xcf\x91\xd6\x5d\x97\x78\xee\xe6\x95", " TWNKL", 3}, // eth / Twinkle { 1, "\x24\x69\x27\x91\xbc\x44\x4c\x5c\xd0\xb8\x1e\x3c\xbc\xab\xa4\xb0\x4a\xcd\x1f\x3b", " UKG", 18}, // eth / UnikoinGold @@ -637,23 +701,25 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x8e\x5a\xfc\x69\xf6\x22\x7a\x3a\xd7\x5e\xd3\x46\xc8\x72\x3b\xc6\x2c\xe9\x71\x23", " UMKA", 4}, // eth / UMKA { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " Unicorn", 0}, // eth / Unicorn { 1, "\xd0\x1d\xb7\x3e\x04\x78\x55\xef\xb4\x14\xe6\x20\x20\x98\xc4\xbe\x4c\xd2\x42\x3b", " UQC", 18}, // eth / Uquid Coin + { 1, "\x93\x16\x84\x13\x9f\x75\x6c\x24\xec\x07\x31\xe9\xf7\x4f\xe5\x0e\x55\x48\xdd\xef", " URB", 18}, // eth / Urbit Data { 1, "\xd7\x60\xad\xdf\xb2\x4d\x9c\x01\xfe\x4b\xfe\xa7\x47\x5c\x5e\x36\x36\x68\x40\x58", " USDM", 2}, // eth / Mether (USDM) { 1, "\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", " USDT", 6}, // eth / USD Tether (erc20) { 1, "\x70\xa7\x28\x33\xd6\xbf\x7f\x50\x8c\x82\x24\xce\x59\xea\x1e\xf3\xd0\xea\x3a\x38", " UTK", 18}, // eth / UTK { 1, "\x9e\x33\x19\x63\x6e\x21\x26\xe3\xc0\xbc\x9e\x31\x34\xae\xc5\xe1\x50\x8a\x46\xc7", " UTN-P", 18}, // eth / Universa { 1, "\x35\x43\x63\x8e\xd4\xa9\x00\x6e\x48\x40\xb1\x05\x94\x42\x71\xbc\xea\x15\x60\x5d", " UUU", 18}, // eth / U Networks + { 1, "\x57\xc7\x5e\xcc\xc8\x55\x71\x36\xd3\x26\x19\xa1\x91\xfb\xcd\xc8\x85\x60\xd7\x11", " VDG", 0}, // eth / VeriDocGlobal { 1, "\x82\xbd\x52\x6b\xdb\x71\x8c\x6d\x4d\xd2\x29\x1e\xd0\x13\xa5\x18\x6c\xae\x2d\xca", " VDOC", 18}, // eth / Duty of Care Token { 1, "\x34\x0d\x2b\xde\x5e\xb2\x8c\x1e\xed\x91\xb2\xf7\x90\x72\x3e\x3b\x16\x06\x13\xb7", " VEE", 18}, // eth / BLOCKv + { 1, "\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1", " VEN", 18}, // eth / Vechain { 1, "\xeb\xed\x4f\xf9\xfe\x34\x41\x3d\xb8\xfc\x82\x94\x55\x6b\xbd\x15\x28\xa4\xda\xca", " VENUS", 3}, // eth / VENUS { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, // eth / Veritas - { 1, "\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1", " VET", 18}, // eth / Vechain { 1, "\x2c\x97\x4b\x2d\x0b\xa1\x71\x6e\x64\x4c\x1f\xc5\x99\x82\xa8\x9d\xdd\x2f\xf7\x24", " VIB", 18}, // eth / VIB { 1, "\x88\x24\x48\xf8\x3d\x90\xb2\xbf\x47\x7a\xf2\xea\x79\x32\x7f\xde\xa1\x33\x5d\x93", " VIBEX", 18}, // eth / VIBEX Exchange Token { 1, "\xe8\xff\x5c\x9c\x75\xde\xb3\x46\xac\xac\x49\x3c\x46\x3c\x89\x50\xbe\x03\xdf\xba", " VIBEX", 18}, // eth / VIBEX { 1, "\xf0\x3f\x8d\x65\xba\xfa\x59\x86\x11\xc3\x49\x51\x24\x09\x3c\x56\xe8\xf6\x38\xf0", " VIEW", 18}, // eth / Viewly { 1, "\x23\xb7\x5b\xc7\xaa\xf2\x8e\x2d\x66\x28\xc3\xf4\x24\xb3\x88\x2f\x8f\x07\x2a\x3c", " VIT", 18}, // eth / Vice Industry Token { 1, "\x51\x94\x75\xb3\x16\x53\xe4\x6d\x20\xcd\x09\xf9\xfd\xcf\x3b\x12\xbd\xac\xb4\xf5", " VIU", 18}, // eth / VIU - { 1, "\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c", " VLD", 18}, // eth / VLD + { 1, "\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c", " VLD", 18}, // eth / VETRI { 1, "\xc3\xbc\x9e\xb7\x1f\x75\xec\x43\x9a\x6b\x6c\x8e\x8b\x74\x6f\xcf\x5b\x62\xf7\x03", " VOC", 18}, // eth / VORMACOIN { 1, "\x83\xee\xa0\x0d\x83\x8f\x92\xde\xc4\xd1\x47\x56\x97\xb9\xf4\xd3\x53\x7b\x56\xe3", " VOISE", 8}, // eth / Voise { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, // eth / Veros @@ -671,6 +737,8 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\x62\xcd\x07\xd4\x14\xec\x50\xb6\x8c\x7e\xca\xa8\x63\xa2\x3d\x34\x4f\x2d\x06\x2f", " WIC", 0}, // eth / WickNote { 1, "\xd3\xc0\x07\x72\xb2\x4d\x99\x7a\x81\x22\x49\xca\x63\x7a\x92\x1e\x81\x35\x77\x01", " WILD", 18}, // eth / WILD Token { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, // eth / WINGS + { 1, "\xbf\xbe\x53\x32\xf1\x72\xd7\x78\x11\xbc\x6c\x27\x28\x44\xf3\xe5\x4a\x7b\x23\xbb", " WMK", 18}, // eth / WemarkToken + { 1, "\xd7\x3a\x66\xb8\xfb\x26\xbe\x8b\x0a\xcd\x7c\x52\xbd\x32\x50\x54\xac\x7d\x46\x8b", " WNK", 18}, // eth / Woonk { 1, "\x72\x87\x81\xe7\x57\x35\xdc\x09\x62\xdf\x3a\x51\xd7\xef\x47\xe7\x98\xa7\x10\x7e", " WOLK", 18}, // eth / WOLK { 1, "\xf6\xb5\x5a\xcb\xbc\x49\xf4\x52\x4a\xa4\x8d\x19\x28\x1a\x9a\x77\xc5\x4d\xe1\x0f", " WOLK", 18}, // eth / Wolk Token { 1, "\xd1\x8e\x45\x4d\x84\x4e\xb0\x00\x9d\x32\xe0\x7a\x0c\xde\x89\xe1\x8d\x64\xcf\xb4", " WORK", 18}, // eth / workTOKEN @@ -695,6 +763,8 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, // eth / XRL { 1, "\x0f\x51\x3f\xfb\x49\x26\xff\x82\xd7\xf6\x0a\x05\x06\x90\x47\xac\xa2\x95\xc4\x13", " XSC", 18}, // eth / XSC { 1, "\x6f\x7a\x4b\xac\x33\x15\xb5\x08\x2f\x79\x31\x61\xa2\x2e\x26\x66\x6d\x22\x71\x7f", " YEED", 18}, // eth / YEED + { 1, "\xca\x27\x96\xf9\xf6\x1d\xc7\xb2\x38\xaa\xb0\x43\x97\x1e\x49\xc6\x16\x4d\xf3\x75", " YEED", 18}, // eth / YGGDRASH + { 1, "\xd9\xa1\x2c\xde\x03\xa8\x6e\x80\x04\x96\x46\x98\x58\xde\x85\x81\xd3\xa5\x35\x3d", " YUP", 18}, // eth / YUP { 1, "\x0f\x33\xbb\x20\xa2\x82\xa7\x64\x9c\x7b\x3a\xff\x64\x4f\x08\x4a\x93\x48\xe9\x33", " YUPIE", 18}, // eth / YUPIE { 1, "\x67\x81\xa0\xf8\x4c\x7e\x9e\x84\x6d\xcb\x84\xa9\xa5\xbd\x49\x33\x30\x67\xb1\x04", " ZAP", 18}, // eth / ZAP { 1, "\x7a\x41\xe0\x51\x7a\x5e\xca\x4f\xdb\xc7\xfb\xeb\xa4\xd4\xc4\x7b\x9f\xf6\xdc\x63", " ZCS", 18}, // eth / Zeusshield @@ -703,14 +773,23 @@ const TokenType tokens[TOKENS_COUNT] = { { 1, "\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", " ZRX", 18}, // eth / 0x Project { 1, "\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1", " ZST", 8}, // eth / Zeus Exchange {42, "\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67", " Aeternity", 18}, // kov / Aeternity + {42, "\xc4\x37\x5b\x7d\xe8\xaf\x5a\x38\xa9\x35\x48\xeb\x84\x53\xa4\x98\x22\x2c\x4f\xf2", " DAI", 18}, // kov / RadarRelay test Dai Stablecoin v1.0 + {42, "\xee\xe3\x87\x06\x57\xe4\x71\x66\x70\xf1\x85\xdf\x08\x65\x2d\xd8\x48\xfe\x8f\x7e", " DGD", 18}, // kov / RadarRelay test Digix DAO Token + {42, "\xef\x7f\xff\x64\x38\x9b\x81\x4a\x94\x6f\x3e\x92\x10\x55\x13\x70\x5c\xa6\xb9\x90", " GNT", 18}, // kov / RadarRelay test Golem Network Token {42, "\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83", " GUP", 3}, // kov / GUP + {42, "\x1d\xad\x47\x83\xcf\x3f\xe3\x08\x5c\x14\x26\x15\x7a\xb1\x75\xa6\x11\x9a\x04\xba", " MKR", 18}, // kov / RadarRelay test MakerDAO + {42, "\x32\x3b\x5d\x4c\x32\x34\x5c\xed\x77\x39\x3b\x35\x30\xb1\xee\xd0\xf3\x46\x42\x9d", " MLN", 18}, // kov / RadarRelay test Melon Tokens + {42, "\xb1\x88\x45\xc2\x60\xf6\x80\xd5\xb9\xd8\x46\x49\x63\x88\x13\xe3\x42\xe4\xf8\xc9", " REP", 18}, // kov / RadarRelay test Augur Reputation Token + {42, "\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70", " ZRX", 18}, // kov / RadarRelay test 0x Protocol Token { 4, "\x39\x8a\x7a\x69\xf3\xc5\x91\x81\xa1\xff\xe3\x4b\xed\x11\xdc\xb5\xdf\x86\x3a\x8a", " AETH", 18}, // rin / AKASHA Tokens { 4, "\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f", " BHNT", 0}, // rin / Berlin Hack&Tell winner token { 4, "\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54", " CTGA", 18}, // rin / Convenient To Go { 4, "\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a", " KC", 18}, // rin / Karma Token { 4, "\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91", " NONE", 0}, // rin / None { 4, "\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80", " PPD", 18}, // rin / PP Donation + { 4, "\x36\x15\x75\x70\x11\x11\x25\x60\x52\x15\x36\x25\x8c\x1e\x73\x25\xae\x3b\x48\xae", " RDN", 18}, // rin / Raiden { 4, "\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b", " WALL", 15}, // rin / WALLETH Community-Token + { 3, "\x95\xd7\x32\x1e\xdc\xe5\x19\x41\x9b\xa1\xdb\xc6\x0a\x89\xba\xfb\xf5\x5e\xac\x0d", " PLASMA", 6}, // rop / *PLASMA { 3, "\x6f\x95\xa3\xb6\x82\xf8\xe9\xaa\xcc\x86\xd0\x57\xa6\xdf\x88\xa0\xe6\x81\x45\xa8", " ILSC", 2}, // rop / IsraCoin { 3, "\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31", " NONE", 0}, // rop / None { 8, "\xff\x3b\xf0\x57\xad\xf3\xb0\xe0\x15\xb6\x46\x53\x31\xa6\x23\x6e\x55\x68\x82\x74", " BEER", 0}, // ubq / BEER diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h index c8383f0a04..5415ef7ee5 100644 --- a/firmware/ethereum_tokens.h +++ b/firmware/ethereum_tokens.h @@ -22,7 +22,7 @@ #include -#define TOKENS_COUNT 716 +#define TOKENS_COUNT 795 typedef struct { uint32_t chain_id; From c82ce39ce57e8abefa778f9dcc6efe854b944f94 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:02:49 +0200 Subject: [PATCH 0942/1154] firmware: disable Stellar for now --- firmware/Makefile | 4 ++-- firmware/fsm.c | 4 ++-- firmware/fsm.h | 4 +++- firmware/protob/Makefile | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 39c8e1bb76..035e2d9481 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,7 @@ OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o -OBJS += stellar.o +# OBJS += stellar.o OBJS += debug.o @@ -90,7 +90,7 @@ OBJS += protob/messages-debug.pb.o OBJS += protob/messages-ethereum.pb.o OBJS += protob/messages-management.pb.o OBJS += protob/messages-nem.pb.o -OBJS += protob/messages-stellar.pb.o +# OBJS += protob/messages-stellar.pb.o OPTFLAGS ?= -Os diff --git a/firmware/fsm.c b/firmware/fsm.c index 0cba9b9c9c..f7d4dffd72 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -56,7 +56,7 @@ #include "rfc6979.h" #include "gettext.h" #include "supervise.h" -#include "stellar.h" +// #include "stellar.h" #include "messages.pb.h" // message methods @@ -248,5 +248,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore #include "fsm_msg_ethereum.h" #include "fsm_msg_crypto.h" #include "fsm_msg_nem.h" -#include "fsm_msg_stellar.h" +// #include "fsm_msg_stellar.h" #include "fsm_msg_debug.h" diff --git a/firmware/fsm.h b/firmware/fsm.h index 703be51150..8d6bc5096e 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -26,7 +26,7 @@ #include "messages-ethereum.pb.h" #include "messages-management.pb.h" #include "messages-nem.pb.h" -#include "messages-stellar.pb.h" +// #include "messages-stellar.pb.h" // message functions @@ -87,6 +87,7 @@ void fsm_msgCosiCommit(CosiCommit *msg); void fsm_msgCosiSign(CosiSign *msg); // Stellar +/* void fsm_msgStellarGetAddress(StellarGetAddress *msg); void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg); void fsm_msgStellarSignTx(StellarSignTx *msg); @@ -101,6 +102,7 @@ void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg); void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); +*/ // debug message functions #if DEBUG_LINK diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 7873b4c97c..d915d79354 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -23,7 +23,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From fdd5cbe20271634dc9ba4424ae40f1d11332cdf2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 24 Aug 2018 17:06:05 +0200 Subject: [PATCH 0943/1154] setup: disable SYSCFG registers --- setup.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.c b/setup.c index 0ab33badb6..d0853db691 100644 --- a/setup.c +++ b/setup.c @@ -196,9 +196,13 @@ void mpu_config(void) // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // SYSCFG_* registers are disabled + // (0x40013800 - 0x40013BFF, read-only, execute never) + MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; // Enable MPU - MPU_CTRL = MPU_CTRL_ENABLE; + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; // Enable memory fault handler SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; From 1af6f44e3417d3cb527ed9dcb4c1b958297ec0ce Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 25 Aug 2018 13:08:51 +0200 Subject: [PATCH 0944/1154] bootloader: bump version to 1.5.1 --- bootloader/bootloader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 7e79ae1c01..3c0feefc9f 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 5 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x05" -#define VERSION_PATCH_CHAR "\x00" +#define VERSION_PATCH_CHAR "\x01" #include #include "memory.h" From ef86786ff750351ec454c7bae33b4966cfa862d7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:47:14 +0200 Subject: [PATCH 0945/1154] firmware: add new bootloader 1.5.1 to the whitelist --- firmware/bl_check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 6acc941a3c..04671143e4 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -40,6 +40,7 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 + if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 return 0; } From 89dd09bdb8d546ca63bbd9c57a2dc89ecead399a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 30 Aug 2018 12:53:55 +0200 Subject: [PATCH 0946/1154] firmware: fix typos in ChangeLog --- firmware/ChangeLog | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 4a9261b19b..e89c20ead6 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,8 +1,9 @@ -Version 1.6.3 [unreleased] -* Stable release, optional update -* implement RSKIP-60 Ethereum checksum encoding -* add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH, GO) -* add support for new 80 Ethereum tokens +Version 1.6.3 +* Stable release, required update +* Implement RSKIP-60 Ethereum checksum encoding +* Add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH, GO) +* Add support for new 80 Ethereum tokens +* Improve MPU configuration Version 1.6.2 * Stable release, optional update From 83ae01e7516c70ff79abbaebfc4dfcb508dbaf25 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Sep 2018 12:01:42 +0200 Subject: [PATCH 0947/1154] bootloader: update ChangeLog --- bootloader/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index 50dfb886ce..226b2dbd7b 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,3 +1,6 @@ +Version 1.5.1 +* Improve MPU configuration + Version 1.5.0 * Make unofficial firmwares work again From 988209ab7d98c68d43265c26b68d7b1bdcf70ba1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 3 Sep 2018 17:02:03 +0200 Subject: [PATCH 0948/1154] bootloader: erasing -> preparing --- bootloader/usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index ec69a818bc..d60a622c09 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -363,12 +363,12 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_unlock(); // erase metadata area for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } // erase code area for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } flash_wait_for_last_operation(); @@ -488,12 +488,12 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) flash_unlock(); // erase metadata area for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } // erase code area for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("ERASING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); flash_erase_sector(i, FLASH_CR_PROGRAM_X32); } layoutProgress("INSTALLING ... Please wait", 0); From c2fa3d8fca1b893442866353fae88b24273b9c1c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:20:29 +0200 Subject: [PATCH 0949/1154] firmware: re-enable Stellar This reverts commit "firmware: disable Stellar for now" c82ce39ce57e8abefa778f9dcc6efe854b944f94 --- firmware/Makefile | 4 ++-- firmware/fsm.c | 4 ++-- firmware/fsm.h | 4 +--- firmware/protob/Makefile | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 035e2d9481..39c8e1bb76 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,7 +28,7 @@ OBJS += ethereum.o OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o -# OBJS += stellar.o +OBJS += stellar.o OBJS += debug.o @@ -90,7 +90,7 @@ OBJS += protob/messages-debug.pb.o OBJS += protob/messages-ethereum.pb.o OBJS += protob/messages-management.pb.o OBJS += protob/messages-nem.pb.o -# OBJS += protob/messages-stellar.pb.o +OBJS += protob/messages-stellar.pb.o OPTFLAGS ?= -Os diff --git a/firmware/fsm.c b/firmware/fsm.c index f7d4dffd72..0cba9b9c9c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -56,7 +56,7 @@ #include "rfc6979.h" #include "gettext.h" #include "supervise.h" -// #include "stellar.h" +#include "stellar.h" #include "messages.pb.h" // message methods @@ -248,5 +248,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore #include "fsm_msg_ethereum.h" #include "fsm_msg_crypto.h" #include "fsm_msg_nem.h" -// #include "fsm_msg_stellar.h" +#include "fsm_msg_stellar.h" #include "fsm_msg_debug.h" diff --git a/firmware/fsm.h b/firmware/fsm.h index 8d6bc5096e..703be51150 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -26,7 +26,7 @@ #include "messages-ethereum.pb.h" #include "messages-management.pb.h" #include "messages-nem.pb.h" -// #include "messages-stellar.pb.h" +#include "messages-stellar.pb.h" // message functions @@ -87,7 +87,6 @@ void fsm_msgCosiCommit(CosiCommit *msg); void fsm_msgCosiSign(CosiSign *msg); // Stellar -/* void fsm_msgStellarGetAddress(StellarGetAddress *msg); void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg); void fsm_msgStellarSignTx(StellarSignTx *msg); @@ -102,7 +101,6 @@ void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg); void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); -*/ // debug message functions #if DEBUG_LINK diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index d915d79354..7873b4c97c 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -23,7 +23,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From 4da73df57d7b2419c26588a2a2840f2f270e3b92 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:22:04 +0200 Subject: [PATCH 0950/1154] re-enable WebUSB This reverts commit "Revert WinUSB feature" b20336e82d19d95a0ce65d13d6c7bcf9d11ac668 --- Makefile | 4 + bootloader/usb.c | 124 +++++++++--------------- firmware/usb.c | 245 +++++++++++++++++++---------------------------- usb21_standard.h | 17 +--- webusb.c | 94 ++++++++++++++++++ webusb.h | 31 ++++++ webusb_defs.h | 61 ++++++++++++ winusb.c | 161 +++++++++++++++++++++++++++++++ winusb.h | 30 ++++++ winusb_defs.h | 89 +++++++++++++++++ 10 files changed, 612 insertions(+), 244 deletions(-) create mode 100644 webusb.c create mode 100644 webusb.h create mode 100644 webusb_defs.h create mode 100644 winusb.c create mode 100644 winusb.h create mode 100644 winusb_defs.h diff --git a/Makefile b/Makefile index 32a61bca29..d54c4afc96 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ ifneq ($(EMULATOR),1) OBJS += timer.o endif +OBJS += usb21_standard.o +OBJS += webusb.o +OBJS += winusb.o + OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/bootloader/usb.c b/bootloader/usb.c index d60a622c09..128eefbca0 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -18,7 +18,6 @@ */ #include -#include #include #include @@ -37,8 +36,14 @@ #include "secp256k1.h" #include "memzero.h" +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + #define FIRMWARE_MAGIC "TRZR" +#define USB_INTERFACE_INDEX_MAIN 0 + #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -48,60 +53,21 @@ static bool old_was_unsigned; static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0300, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ +static const struct usb_endpoint_descriptor endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN, @@ -117,24 +83,24 @@ static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor hid_iface[] = {{ +static const struct usb_interface_descriptor iface[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = 0, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, }}; static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = iface, }}; static const struct usb_config_descriptor config = { @@ -155,23 +121,6 @@ static const char *usb_strings[] = { "", // empty serial }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) -{ - (void)complete; - (void)dev; - - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; - - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); - - return 1; -} - enum { STATE_READY, STATE_OPEN, @@ -315,7 +264,7 @@ static void restore_metadata(const uint8_t *backup) flash_lock(); } -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); @@ -665,23 +614,37 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); - - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request - ); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; + +void usbInit(void) +{ + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); +} void checkButtons(void) { @@ -715,8 +678,7 @@ void checkButtons(void) void usbLoop(bool firmware_present) { brand_new_firmware = !firmware_present; - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbInit(); for (;;) { usbd_poll(usbd_dev); if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { diff --git a/firmware/usb.c b/firmware/usb.c index 7a59b6fa02..be7cae7b91 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -29,18 +29,27 @@ #include "util.h" #include "timer.h" +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + + #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK #define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_U2F 2 +#define USB_INTERFACE_COUNT 3 #else #define USB_INTERFACE_INDEX_U2F 1 +#define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_MAIN_IN (0x81) +#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) +#if DEBUG_LINK #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#endif #define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_OUT (0x03) @@ -50,7 +59,7 @@ X(SERIAL_NUMBER, storage_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ - X(INTERFACE_U2F, "U2F Interface") + X(INTERFACE_U2F, "TREZOR U2F Interface") \ #define X(name, value) USB_STRING_##name, enum { @@ -68,60 +77,20 @@ static const char *usb_strings[] = { static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0200, .iManufacturer = USB_STRING_MANUFACTURER, .iProduct = USB_STRING_PRODUCT, .iSerialNumber = USB_STRING_SERIAL_NUMBER, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -#if DEBUG_LINK -static const uint8_t hid_report_descriptor_debug[] = { - 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; -#endif - static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) 0x09, 0x01, // USAGE (U2F HID Authenticator Device) @@ -141,26 +110,6 @@ static const uint8_t hid_report_descriptor_u2f[] = { 0xc0 // END_COLLECTION }; -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - static const struct { struct usb_hid_descriptor hid_descriptor_u2f; struct { @@ -181,52 +130,20 @@ static const struct { } }; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor hid_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), -}}; - static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ @@ -245,7 +162,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ +static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, @@ -261,29 +178,64 @@ static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor hid_iface_debug[] = {{ +static const struct usb_interface_descriptor webusb_iface_debug[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = hid_endpoints_debug, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = webusb_endpoints_debug, + .extra = NULL, + .extralen = 0, }}; + #endif +static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor webusb_iface_main[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = webusb_endpoints_main, + .extra = NULL, + .extralen = 0, +}}; + + +// Windows are strict about interfaces appearing +// in correct order static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = webusb_iface_main, #if DEBUG_LINK }, { .num_altsetting = 1, - .altsetting = hid_iface_debug, + .altsetting = webusb_iface_debug, #endif }, { .num_altsetting = 1, @@ -294,11 +246,7 @@ static const struct usb_config_descriptor config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, -#if DEBUG_LINK - .bNumInterfaces = 3, -#else - .bNumInterfaces = 2, -#endif + .bNumInterfaces = USB_INTERFACE_COUNT, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, @@ -312,40 +260,24 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (void)dev; if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) return 0; - if (req->wIndex == USB_INTERFACE_INDEX_U2F) { - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = sizeof(hid_report_descriptor_u2f); - return 1; - } - -#if DEBUG_LINK - if (req->wIndex == USB_INTERFACE_INDEX_DEBUG) { - debugLog(0, "", "hid_control_request debug"); - *buf = (uint8_t *)hid_report_descriptor_debug; - *len = sizeof(hid_report_descriptor_debug); - return 1; - } -#endif - - debugLog(0, "", "hid_control_request main"); - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); return 1; } static volatile char tiny = 0; -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void main_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_rx_callback"); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; + debugLog(0, "", "main_rx_callback"); if (!tiny) { msg_read(buf, 64); } else { @@ -353,23 +285,23 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } } -static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) +static void u2f_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - debugLog(0, "", "hid_u2f_rx_callback"); + debugLog(0, "", "u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } #if DEBUG_LINK -static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) +static void debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_debug_rx_callback"); + debugLog(0, "", "debug_rx_callback"); if (!tiny) { msg_debug_read(buf, 64); } else { @@ -378,17 +310,17 @@ static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) } #endif -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_u2f_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); #if DEBUG_LINK usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); #endif usbd_register_control_callback( @@ -399,12 +331,29 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + // Debug link interface does not have WinUSB set; + // if you really need debug link on windows, edit the descriptor in winusb.c + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } void usbPoll(void) @@ -415,7 +364,7 @@ void usbPoll(void) // write pending data data = msg_out_data(); if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} } data = u2f_out_data(); if (data) { diff --git a/usb21_standard.h b/usb21_standard.h index e7578a533b..e5358bcd5f 100644 --- a/usb21_standard.h +++ b/usb21_standard.h @@ -22,10 +22,8 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 +#define USB_DT_BOS 15 #define USB_DT_DEVICE_CAPABILITY 16 -#define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 -#define USB_DT_SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49 struct usb_device_capability_descriptor { uint8_t bLength; @@ -45,18 +43,7 @@ struct usb_bos_descriptor { #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_WIRELESS_USB 1 -#define USB_DC_USB_2_0_EXTENSION 2 -#define USB_DC_SUPERSPEED_USB 3 -#define USB_DC_CONTAINER_ID 4 -#define USB_DC_PLATFORM 5 -#define USB_DC_POWER_DELIVERY_CAPABILITY 6 -#define USB_DC_BATTERY_INFO_CAPABILITY 7 -#define USB_DC_PD_CONSUMER_PORT_CAPABILITY 8 -#define USB_DC_PD_PROVIDER_PORT_CAPABILITY 9 -#define USB_DC_SUPERSPEED_PLUS 10 -#define USB_DC_PRECISION_TIME_MEASUREMENT 11 -#define USB_DC_WIRELESS_USB_EXT 12 +#define USB_DC_PLATFORM 5 extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); diff --git a/webusb.c b/webusb.c new file mode 100644 index 0000000000..beb909c089 --- /dev/null +++ b/webusb.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "util.h" +#include "webusb.h" +#include "usb21_standard.h" + +const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 1 +}; + +static const char* webusb_https_url; + +static int webusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WEBUSB_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + switch (req->wIndex) { + case WEBUSB_REQ_GET_URL: { + struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); + uint16_t index = req->wValue; + if (index == 0) { + return USBD_REQ_NOTSUPP; + } + + if (index == 1) { + size_t url_len = strlen(webusb_https_url); + url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; + url->bDescriptorType = WEBUSB_DT_URL; + url->bScheme = WEBUSB_URL_SCHEME_HTTPS; + memcpy(&url->URL, webusb_https_url, url_len); + *len = MIN(*len, url->bLength); + status = USBD_REQ_HANDLED; + } else { + // TODO: stall instead? + status = USBD_REQ_NOTSUPP; + } + break; + } + default: { + status = USBD_REQ_NOTSUPP; + break; + } + } + + return status; +} + +static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + webusb_control_vendor_request); +} + +void webusb_setup(usbd_device* usbd_dev, const char* https_url) { + webusb_https_url = https_url; + + usbd_register_set_config_callback(usbd_dev, webusb_set_config); +} diff --git a/webusb.h b/webusb.h new file mode 100644 index 0000000000..342408f1f7 --- /dev/null +++ b/webusb.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_H_INCLUDED +#define WEBUSB_H_INCLUDED + +#include +#include "webusb_defs.h" + +// Arbitrary +#define WEBUSB_VENDOR_CODE 0x01 + +extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; +extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); + +#endif diff --git a/webusb_defs.h b/webusb_defs.h new file mode 100644 index 0000000000..45b5f2478d --- /dev/null +++ b/webusb_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_DEFS_H_INCLUDED +#define WEBUSB_DEFS_H_INCLUDED + +#include + +#define WEBUSB_REQ_GET_URL 0x02 + +#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 +#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 +#define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2 +#define WEBUSB_DT_URL 3 + +#define WEBUSB_URL_SCHEME_HTTP 0 +#define WEBUSB_URL_SCHEME_HTTPS 1 + +struct webusb_platform_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t platformCapabilityUUID[16]; + uint16_t bcdVersion; + uint8_t bVendorCode; + uint8_t iLandingPage; +} __attribute__((packed)); + +#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) + +// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor +// see also this (for endianness explanation) +// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 +#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} + +struct webusb_url_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char URL[]; +} __attribute__((packed)); + +#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 + +#endif diff --git a/winusb.c b/winusb.c new file mode 100644 index 0000000000..afdaf8b706 --- /dev/null +++ b/winusb.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "util.h" +#include "winusb.h" + +static int usb_descriptor_type(uint16_t wValue) { + return wValue >> 8; +} + +static int usb_descriptor_index(uint16_t wValue) { + return wValue & 0xFF; +} + +static struct winusb_compatible_id_descriptor winusb_wcid = { + .header = { + .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + + 1 * sizeof(struct winusb_compatible_id_function_section), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, + .bNumSections = 1, + .reserved = { 0, 0, 0, 0, 0, 0, 0 }, + }, + .functions = { + { + // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number + .bInterfaceNumber = 0, + .reserved0 = { 1 }, + .compatibleId = "WINUSB", + .subCompatibleId = "", + .reserved1 = { 0, 0, 0, 0, 0, 0} + }, + } +}; + +static const struct usb_string_descriptor winusb_string_descriptor = { + .bLength = 0x12, + .bDescriptorType = USB_DT_STRING, + .wData = WINUSB_EXTRA_STRING +}; + +static const struct winusb_extended_properties_descriptor guid = { + .header = { + .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) + + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, + .wNumFeatures = 1, + }, + .features = { + { + .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), + .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, + .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, + .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, + .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, + .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, + }, + } +}; + +static int winusb_descriptor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return USBD_REQ_NEXT_CALLBACK; + } + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { + if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { + *buf = (uint8_t*)(&winusb_string_descriptor); + *len = MIN(*len, winusb_string_descriptor.bLength); + return USBD_REQ_HANDLED; + } + } + return USBD_REQ_NEXT_CALLBACK; +} + +static int winusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && + (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { + *buf = (uint8_t*)(&winusb_wcid); + *len = MIN(*len, winusb_wcid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && + (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && + (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { + + *buf = (uint8_t*)(&guid); + *len = MIN(*len, guid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else { + status = USBD_REQ_NOTSUPP; + } + + return status; +} + +static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); +} + +void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { + winusb_wcid.functions[0].bInterfaceNumber = interface; + + usbd_register_set_config_callback(usbd_dev, winusb_set_config); + + /* Windows probes the compatible ID before setting the configuration, + so also register the callback now */ + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_RECIPIENT, + winusb_descriptor_request); +} + diff --git a/winusb.h b/winusb.h new file mode 100644 index 0000000000..16a6df1153 --- /dev/null +++ b/winusb.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_H_INCLUDED +#define WINUSB_H_INCLUDED + +#include "winusb_defs.h" + +// Arbitrary, but must be equivalent to the last character in extra string +#define WINUSB_MS_VENDOR_CODE '!' +#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} + +extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); + +#endif diff --git a/winusb_defs.h b/winusb_defs.h new file mode 100644 index 0000000000..830e6b1545 --- /dev/null +++ b/winusb_defs.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_DEFS_H_INCLUDED +#define WINUSB_DEFS_H_INCLUDED + +#include + +/* Microsoft OS 1.0 descriptors */ + +/* Extended Compat ID OS Feature Descriptor Specification */ +#define WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 +#define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 +#define WINUSB_BCD_VERSION 0x0100 + +// Apparently using DeviceInterfaceGUID does not always work on Windows 7. +// DeviceInterfaceGUIDs does seem to work. +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) + +// extra null is intentional - it's an array of GUIDs with 1 item +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 + +#define WINUSB_EXTRA_STRING_INDEX 0xee + +/* Table 2. Function Section */ +struct winusb_compatible_id_function_section { + uint8_t bInterfaceNumber; + uint8_t reserved0[1]; + char compatibleId[8]; + char subCompatibleId[8]; + uint8_t reserved1[6]; +} __attribute__((packed)); + +/* Table 1. Header Section */ +struct winusb_compatible_id_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bNumSections; + uint8_t reserved[7]; +} __attribute__((packed)); + +struct winusb_compatible_id_descriptor { + struct winusb_compatible_id_descriptor_header header; + struct winusb_compatible_id_function_section functions[]; +} __attribute__((packed)); + +struct winusb_extended_properties_feature_descriptor { + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint16_t wNameLength; + uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; + uint32_t dwPropertyDataLength; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wNumFeatures; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor { + struct winusb_extended_properties_descriptor_header header; + struct winusb_extended_properties_feature_descriptor features[]; +} __attribute__((packed)); + +#endif From de96efdb1dc373f2ffa8a35e0f34261d07902bcb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:30:19 +0200 Subject: [PATCH 0951/1154] usb: change vendor/product id to ones we use for WebUSB --- bootloader/usb.c | 6 +++--- demo/demo.c | 4 ++-- firmware/usb.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 128eefbca0..9c6231713d 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -58,9 +58,9 @@ static const struct usb_device_descriptor dev_descr = { .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = 0x534c, - .idProduct = 0x0001, - .bcdDevice = 0x0300, + .idVendor = 0x1209, + .idProduct = 0x53c0, + .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, diff --git a/demo/demo.c b/demo/demo.c index 7a92d15b1d..d77279f0b8 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -47,8 +47,8 @@ static const struct usb_device_descriptor dev_descr = { .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = 0x534c, - .idProduct = 0x0001, + .idVendor = 0x1209, + .idProduct = 0x53c1, .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, diff --git a/firmware/usb.c b/firmware/usb.c index be7cae7b91..228e28a8cb 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -82,9 +82,9 @@ static const struct usb_device_descriptor dev_descr = { .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, - .idVendor = 0x534c, - .idProduct = 0x0001, - .bcdDevice = 0x0200, + .idVendor = 0x1209, + .idProduct = 0x53c1, + .bcdDevice = 0x0100, .iManufacturer = USB_STRING_MANUFACTURER, .iProduct = USB_STRING_PRODUCT, .iSerialNumber = USB_STRING_SERIAL_NUMBER, From 23f03cb6d39d9f7c4e0f0c8fdc607f4c92c0e9a4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 27 Aug 2018 17:37:53 +0200 Subject: [PATCH 0952/1154] firmware: don't use WebUSB landing page for firmware, it's annoying --- firmware/usb.c | 2 +- webusb.c | 11 +++++++++++ webusb.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/firmware/usb.c b/firmware/usb.c index 228e28a8cb..733a55b344 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -334,7 +334,7 @@ static usbd_device *usbd_dev; static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor_no_landing_page, }; static const struct usb_bos_descriptor bos_descriptor = { diff --git a/webusb.c b/webusb.c index beb909c089..7106187810 100644 --- a/webusb.c +++ b/webusb.c @@ -33,6 +33,17 @@ const struct webusb_platform_descriptor webusb_platform_capability_descriptor = .iLandingPage = 1 }; +const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 0 +}; + static const char* webusb_https_url; static int webusb_control_vendor_request(usbd_device *usbd_dev, diff --git a/webusb.h b/webusb.h index 342408f1f7..c7f5dc78fa 100644 --- a/webusb.h +++ b/webusb.h @@ -26,6 +26,8 @@ #define WEBUSB_VENDOR_CODE 0x01 extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; +extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page; + extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); #endif From dbc129d290eb3d038502439160469e49bb09624e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Sep 2018 15:13:30 +0200 Subject: [PATCH 0953/1154] bump versions to 1.7.0 (firmware) and 1.6.0 (bootloader) --- bootloader/ChangeLog | 3 +++ bootloader/bootloader.h | 8 ++++---- firmware/ChangeLog | 9 +++++++++ firmware/trezor.h | 4 ++-- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index 226b2dbd7b..0c386257ef 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,3 +1,6 @@ +Version 1.6.0 [unreleased] +* Switch from HID to WebUSB + Version 1.5.1 * Improve MPU configuration diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 3c0feefc9f..8f9f873516 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,15 +21,15 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 5 -#define VERSION_PATCH 1 +#define VERSION_MINOR 6 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x05" -#define VERSION_PATCH_CHAR "\x01" +#define VERSION_MINOR_CHAR "\x06" +#define VERSION_PATCH_CHAR "\x00" #include #include "memory.h" diff --git a/firmware/ChangeLog b/firmware/ChangeLog index e89c20ead6..d612bd7e0f 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,9 +1,16 @@ +Version 1.7.0 [unreleased] +* Stable release, optional update +* Switch from HID to WebUSB +* Add support for Stellar +* Included bootloader 1.6.0 + Version 1.6.3 * Stable release, required update * Implement RSKIP-60 Ethereum checksum encoding * Add support for new Ethereum networks (ESN, AKA, ETHO, MUSI, PIRL, ATH, GO) * Add support for new 80 Ethereum tokens * Improve MPU configuration +* Included bootloader 1.5.1 Version 1.6.2 * Stable release, optional update @@ -15,12 +22,14 @@ Version 1.6.2 * Support for new Ethereum networks: - EOS Classic, Ethereum Social, Ellaism, Callisto, EtherGem, Wanchain * Support for 500+ new Ethereum tokens +* Included bootloader 1.5.0 Version 1.6.1 * Stable release, required update * Use fixed-width font for addresses * Lots of under-the-hood improvements * Fixed issue with write-protection settings +* Included bootloader 1.4.0 Version 1.6.0 * Stable release, optional update diff --git a/firmware/trezor.h b/firmware/trezor.h index 228d93769f..20fcfc481e 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,8 +23,8 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 6 -#define VERSION_PATCH 3 +#define VERSION_MINOR 7 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 7b2d91b970780e19436407cabe42d4e7d6a9bdb7 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 4 Sep 2018 18:24:41 +0200 Subject: [PATCH 0954/1154] firmware: add bootloader 1.6.0 to whitelist --- firmware/bl_check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 04671143e4..0cb90098a8 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -41,6 +41,7 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 + if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 return 0; } From a3555b9c7cbb616f1cfc6c436726d33075e15034 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Sep 2018 14:37:42 +0200 Subject: [PATCH 0955/1154] layout: fix VerifyMessage dialog (use nonproportional font for addresses) --- firmware/fsm_msg_coin.h | 2 +- firmware/fsm_msg_ethereum.h | 2 +- firmware/layout2.c | 44 +++++++++++++++++++------------------ firmware/layout2.h | 2 +- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 7a002ed606..4f086a5e73 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -254,7 +254,7 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) if (!coin) return; layoutProgressSwipe(_("Verifying"), 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { - layoutVerifyAddress(msg->address); + layoutVerifyAddress(coin, msg->address); if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 15e62b9cd9..ed83a67c98 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -90,7 +90,7 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) char address[43] = { '0', 'x' }; ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); - layoutVerifyAddress(address); + layoutVerifyAddress(NULL, address); if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/firmware/layout2.c b/firmware/layout2.c index a046d1cf0b..5f8a4ab37d 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -244,43 +244,39 @@ void layoutHome(void) system_millis_lock_start = timer_ms(); } -void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out) +static void render_address_dialog(const CoinInfo *coin, const char *address, const char *line1, const char *line2, const char *extra_line) { - char str_out[32 + 3]; - bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); - strlcat(str_out, " to", sizeof(str_out)); - const char *addr = out->address; - if (coin->cashaddr_prefix) { + if (coin && coin->cashaddr_prefix) { /* If this is a cashaddr address, remove the prefix from the * string presented to the user */ int prefix_len = strlen(coin->cashaddr_prefix); - if (strncmp(addr, coin->cashaddr_prefix, prefix_len) == 0 - && addr[prefix_len] == ':') { - addr += prefix_len + 1; + if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 + && address[prefix_len] == ':') { + address += prefix_len + 1; } } - int addrlen = strlen(addr); + int addrlen = strlen(address); int numlines = addrlen <= 42 ? 2 : 3; int linelen = (addrlen - 1) / numlines + 1; if (linelen > 21) { linelen = 21; } - const char **str = split_message((const uint8_t *)addr, addrlen, linelen); + const char **str = split_message((const uint8_t *)address, addrlen, linelen); layoutLast = layoutDialogSwipe; layoutSwipe(); oledClear(); oledDrawBitmap(0, 0, &bmp_icon_question); - oledDrawString(20, 0 * 9, _("Confirm sending"), FONT_STANDARD); - oledDrawString(20, 1 * 9, str_out, FONT_STANDARD); + oledDrawString(20, 0 * 9, line1, FONT_STANDARD); + oledDrawString(20, 1 * 9, line2, FONT_STANDARD); int left = linelen > 18 ? 0 : 20; oledDrawString(left, 2 * 9, str[0], FONT_FIXED); oledDrawString(left, 3 * 9, str[1], FONT_FIXED); oledDrawString(left, 4 * 9, str[2], FONT_FIXED); oledDrawString(left, 5 * 9, str[3], FONT_FIXED); if (!str[3][0]) { - if (out->address_n_count > 0) { - oledDrawString(0, 5*9, address_n_str(out->address_n, out->address_n_count), FONT_STANDARD); + if (extra_line) { + oledDrawString(0, 5 * 9, extra_line, FONT_STANDARD); } else { oledHLine(OLED_HEIGHT - 13); } @@ -290,6 +286,16 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOut oledRefresh(); } +void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out) +{ + char str_out[32 + 3]; + bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); + strlcat(str_out, " to", sizeof(str_out)); + const char *address = out->address; + const char *extra_line = (out->address_n_count > 0) ? address_n_str(out->address_n, out->address_n_count) : 0; + render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); +} + void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) { bool ascii_only = true; @@ -364,13 +370,9 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len) str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutVerifyAddress(const char *address) +void layoutVerifyAddress(const CoinInfo *coin, const char *address) { - const char **str = split_message((const uint8_t *)address, strlen(address), 17); - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), - _("Confirm address?"), - _("Message signed by:"), - str[0], str[1], str[2], NULL, NULL); + render_address_dialog(coin, address, _("Confirm address?"), _("Message signed by:"), 0); } void layoutVerifyMessage(const uint8_t *msg, uint32_t len) diff --git a/firmware/layout2.h b/firmware/layout2.h index f5743859a8..b41a1546bd 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -48,7 +48,7 @@ void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); -void layoutVerifyAddress(const char *address); +void layoutVerifyAddress(const CoinInfo *coin, const char *address); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); From a6de54520d78cbd925c1a1a09ea4e42e5d752fed Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Sep 2018 17:41:48 +0200 Subject: [PATCH 0956/1154] layout2: refactor is_valid_ascii function --- firmware/fsm_msg_coin.h | 2 ++ firmware/layout2.c | 13 ++++++++----- firmware/layout2.h | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 4f086a5e73..2eb8e3a574 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -209,6 +209,8 @@ void fsm_msgGetAddress(GetAddress *msg) void fsm_msgSignMessage(SignMessage *msg) { + // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings")); + RESP_INIT(MessageSignature); CHECK_INITIALIZED diff --git a/firmware/layout2.c b/firmware/layout2.c index 5f8a4ab37d..7ad7e27aac 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -296,17 +296,20 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOut render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); } -void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) +bool is_valid_ascii(const uint8_t *data, uint32_t size) { - bool ascii_only = true; for (uint32_t i = 0; i < size; i++) { if (data[i] < ' ' || data[i] > '~') { - ascii_only = false; - break; + return false; } } + return true; +} + +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) +{ const char **str; - if (!ascii_only) { + if (!is_valid_ascii(data, size)) { char hex[65]; memset(hex, 0, sizeof(hex)); data2hex(data, (size > 32) ? 32 : size, hex); diff --git a/firmware/layout2.h b/firmware/layout2.h index b41a1546bd..5c38ad5c22 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -72,5 +72,6 @@ void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *defini void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); +bool is_valid_ascii(const uint8_t *data, uint32_t size); #endif From 4661db1fd4c4d9247d7599466ce9c1f81f945a2b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Sep 2018 18:28:56 +0200 Subject: [PATCH 0957/1154] add missing license headers --- firmware/fsm_msg_coin.h | 19 +++++++++++++++++++ firmware/fsm_msg_common.h | 19 +++++++++++++++++++ firmware/fsm_msg_crypto.h | 21 ++++++++++++++++++++- firmware/fsm_msg_debug.h | 19 +++++++++++++++++++ firmware/fsm_msg_ethereum.h | 21 ++++++++++++++++++++- firmware/fsm_msg_nem.h | 21 ++++++++++++++++++++- firmware/fsm_msg_stellar.h | 21 ++++++++++++++++++++- firmware/stellar.c | 23 +++++++++++++---------- firmware/stellar.h | 6 ++++-- 9 files changed, 154 insertions(+), 16 deletions(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 2eb8e3a574..7123ce0e19 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgGetPublicKey(GetPublicKey *msg) { RESP_INIT(PublicKey); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index c42b5c3ffe..0c6c5416b0 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgInitialize(Initialize *msg) { recovery_abort(); diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index 1a3a42433b..486dd74e38 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgCipherKeyValue(CipherKeyValue *msg) { CHECK_INITIALIZED @@ -334,4 +353,4 @@ void fsm_msgCosiSign(CosiSign *msg) msg_write(MessageType_MessageType_CosiSignature, resp); layoutHome(); -} \ No newline at end of file +} diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 3a84a87153..ad52e8e373 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + #if DEBUG_LINK void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index ed83a67c98..f39a9659fb 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgEthereumSignTx(EthereumSignTx *msg) { CHECK_INITIALIZED @@ -105,4 +124,4 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) fsm_sendSuccess(_("Message verified")); layoutHome(); -} \ No newline at end of file +} diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h index fb3c964619..83665bcca5 100644 --- a/firmware/fsm_msg_nem.h +++ b/firmware/fsm_msg_nem.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgNEMGetAddress(NEMGetAddress *msg) { if (!msg->has_network) { @@ -284,4 +303,4 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); layoutHome(); -} \ No newline at end of file +} diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index 4e626d183c..e27aadcfd6 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -1,3 +1,22 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 ZuluCrypto + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgStellarGetAddress(StellarGetAddress *msg) { RESP_INIT(StellarAddress); @@ -303,4 +322,4 @@ void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) msg_write(MessageType_MessageType_StellarTxOpRequest, resp); } -} \ No newline at end of file +} diff --git a/firmware/stellar.c b/firmware/stellar.c index 8666e0d5df..e8d66c1e37 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -1,5 +1,7 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 ZuluCrypto * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -13,16 +15,17 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . - * - * Stellar signing workflow: - * 1. Client sends a StellarSignTx method to the device with transaction header information - * 2. Device confirms transaction details with the user and requests first operation - * 3. Client sends protobuf message with details about the operation to sign - * 4. Device confirms operation with user - * 5a. If there are more operations in the transaction, device responds with StellarTxOpRequest. Go to 3 - * 5b. If the operation is the last one, device responds with StellarSignedTx */ +// Stellar signing workflow: +// +// 1. Client sends a StellarSignTx method to the device with transaction header information +// 2. Device confirms transaction details with the user and requests first operation +// 3. Client sends protobuf message with details about the operation to sign +// 4. Device confirms operation with user +// 5a. If there are more operations in the transaction, device responds with StellarTxOpRequest. Go to 3 +// 5b. If the operation is the last one, device responds with StellarSignedTx + #include #include #include "messages.h" @@ -1904,4 +1907,4 @@ void stellar_layoutTransactionDialog(const char *line1, const char *line2, const str_warning, false ); -} \ No newline at end of file +} diff --git a/firmware/stellar.h b/firmware/stellar.h index 404832650c..af1349988a 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -1,5 +1,7 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 ZuluCrypto * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -99,4 +101,4 @@ bool stellar_validateAddress(const char *str_address); bool stellar_getAddressBytes(char* str_address, uint8_t *out_bytes); uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); -#endif \ No newline at end of file +#endif From d36038aa1d07a451ca4f0378d6803964efefd3ec Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 30 Jul 2018 17:40:07 +0200 Subject: [PATCH 0958/1154] firmware: generate coin defs with Mako --- firmware/.gitignore | 2 + firmware/Makefile | 24 +- firmware/coin_info.c.mako | 51 ++ firmware/coin_info.h.mako | 14 + firmware/coin_info.py | 129 ----- firmware/ethereum.c | 28 +- firmware/ethereum_networks.h.mako | 34 ++ firmware/ethereum_tokens.c | 813 ------------------------------ firmware/ethereum_tokens.c.mako | 24 + firmware/ethereum_tokens.h | 40 -- firmware/ethereum_tokens.h.mako | 25 + firmware/nem_mosaics.c.mako | 36 ++ firmware/nem_mosaics.h.mako | 15 + firmware/nem_mosaics.py | 122 ----- vendor/trezor-common | 2 +- 15 files changed, 212 insertions(+), 1147 deletions(-) create mode 100644 firmware/coin_info.c.mako create mode 100644 firmware/coin_info.h.mako delete mode 100755 firmware/coin_info.py create mode 100644 firmware/ethereum_networks.h.mako delete mode 100644 firmware/ethereum_tokens.c create mode 100644 firmware/ethereum_tokens.c.mako delete mode 100644 firmware/ethereum_tokens.h create mode 100644 firmware/ethereum_tokens.h.mako create mode 100644 firmware/nem_mosaics.c.mako create mode 100644 firmware/nem_mosaics.h.mako delete mode 100755 firmware/nem_mosaics.py diff --git a/firmware/.gitignore b/firmware/.gitignore index a35c8127e0..da8ec7c158 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,4 +1,6 @@ coin_info.[ch] nem_mosaics.[ch] +ethereum_networks.h +ethereum_tokens.[ch] bl_data.h diff --git a/firmware/Makefile b/firmware/Makefile index 035e2d9481..a242a30f84 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -115,22 +115,14 @@ CFLAGS += -DUSE_ETHEREUM=1 CFLAGS += -DUSE_NEM=1 CFLAGS += -DUSE_MONERO=0 -define GENERATE_CODE -# $(1) - Basename for script and output header file -# $(2) - Dependencies -# $(3) - Additional output files +%:: %.mako defs + @printf " MAKO $@\n" + $(Q)$(PYTHON) ../vendor/trezor-common/tools/cointool.py render $@.mako -$(1).h $(3): $(1).py $(2) - @printf " PYTHON $(1).py\n" - $(Q)$(PYTHON) $(1).py - -# Serialize build for parallel Make -$(1).h: $(3) +bl_data.h: bl_data.py ../bootloader/bootloader.bin + @printf " PYTHON bl_data.py\n" + $(Q)$(PYTHON) bl_data.py clean:: - rm -f $(1).h $(3) -endef - -$(eval $(call GENERATE_CODE,coin_info,defs,coin_info.c)) -$(eval $(call GENERATE_CODE,nem_mosaics,defs/nem/nem_mosaics.json,nem_mosaics.c)) -$(eval $(call GENERATE_CODE,bl_data,../bootloader/bootloader.bin)) + rm -f bl_data.h + find -maxdepth 1 -name "*.mako" | sed 's/.mako$$//' | xargs rm -f diff --git a/firmware/coin_info.c.mako b/firmware/coin_info.c.mako new file mode 100644 index 0000000000..e504bde2cd --- /dev/null +++ b/firmware/coin_info.c.mako @@ -0,0 +1,51 @@ +<% +def signed_message_header(s): + return r'"\x{:02x}" {}'.format(len(s), c_str(s)) + +def c_bool(b): + return "true" if b else "false" + +def c_int(i): + return int(i or 0) + +def defined(s): + return c_bool(s is not None) + +def hex(x): + return "0x{:08x}".format(c_int(x)) +%>\ +// This file is automatically generated from coin_info.c.mako +// DO NOT EDIT + +#include "coins.h" + +#include "curves.h" +#include "secp256k1.h" + +const CoinInfo coins[COINS_COUNT] = { +% for c in supported_on("trezor1", bitcoin): +{ + .coin_name = ${c_str(c.coin_name)}, + .coin_shortcut = ${c_str(" " + c.coin_shortcut)}, + .maxfee_kb = ${c_int(c.maxfee_kb)}, + .signed_message_header = ${signed_message_header(c.signed_message_header)}, + .has_address_type = ${defined(c.address_type)}, + .has_address_type_p2sh = ${defined(c.address_type_p2sh)}, + .has_segwit = ${c_bool(c.segwit)}, + .has_fork_id = ${defined(c.fork_id)}, + .force_bip143 = ${c_bool(c.force_bip143)}, + .decred = ${c_bool(c.decred)}, + .address_type = ${c.address_type}, + .address_type_p2sh = ${c.address_type_p2sh}, + .xpub_magic = ${hex(c.xpub_magic)}, + .xprv_magic = ${hex(c.xprv_magic)}, + .fork_id = ${c_int(c.fork_id)}, + .version_group_id = ${hex(c.version_group_id)}, + .bech32_prefix = ${c_str(c.bech32_prefix)}, + .cashaddr_prefix = ${c_str(c.cashaddr_prefix)}, + .coin_type = (${c_int(c.slip44)} | 0x80000000), + .curve_name = ${c.curve_name.upper()}_NAME, + .curve = &${c.curve_name}_info, +}, +% endfor +}; diff --git a/firmware/coin_info.h.mako b/firmware/coin_info.h.mako new file mode 100644 index 0000000000..bcd16120bf --- /dev/null +++ b/firmware/coin_info.h.mako @@ -0,0 +1,14 @@ +// This file is automatically generated from coin_info.h.mako +// DO NOT EDIT + +#ifndef __COIN_INFO_H__ +#define __COIN_INFO_H__ + +#include "coins.h" + +<% coins_list = list(supported_on("trezor1", bitcoin)) %>\ +#define COINS_COUNT (${len(coins_list)}) + +extern const CoinInfo coins[COINS_COUNT]; + +#endif diff --git a/firmware/coin_info.py b/firmware/coin_info.py deleted file mode 100755 index d5c7d1b1c5..0000000000 --- a/firmware/coin_info.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python2 -import json -import os - -import collections - -HEADER_TEMPLATE = """ -// This file is automatically generated by coin_info.py -- DO NOT EDIT! - -#ifndef __COIN_INFO_H__ -#define __COIN_INFO_H__ - -#include "coins.h" - -#define COINS_COUNT ({count}) - -extern const CoinInfo coins[COINS_COUNT]; - -#endif -""".lstrip() - -CODE_TEMPLATE = """ -// This file is automatically generated by coin_info.py -- DO NOT EDIT! - -#include "coins.h" - -#include "curves.h" -#include "secp256k1.h" - -const CoinInfo coins[COINS_COUNT] = {{ -{coins} -}}; -""".lstrip() - - -def format_bool(value): - if value: - return "true" - else: - return "false" - - -def format_number(value): - if value is None: - value = 0 - return str(value) - - -def format_string(value): - if value is None: - return "NULL" - else: - return json.dumps(value) - - -def format_hex(value): - if value is None: - value = 0 - return "0x{:08x}".format(value) - - -def prepend_varint(string): - assert len(string) < 253 - - varint = "\"\\x{:02x}\"".format(len(string)) - return "{} {}".format(varint, format_string(string)) - - -def coin_to_struct(coin): - return collections.OrderedDict(( - ("coin_name", format_string(coin["coin_name"])), - ("coin_shortcut", format_string(" " + coin["coin_shortcut"])), - ("maxfee_kb", format_number(coin["maxfee_kb"])), - ("signed_message_header", prepend_varint(coin["signed_message_header"])), # noqa: E501 - ("has_address_type", format_bool(coin["address_type"] is not None)), # noqa: E501 - ("has_address_type_p2sh", format_bool(coin["address_type_p2sh"] is not None)), # noqa: E501 - ("has_segwit", format_bool(coin["segwit"])), - ("has_fork_id", format_bool(coin["fork_id"] is not None)), - ("force_bip143", format_bool(coin["force_bip143"])), - ("decred", format_bool(coin["decred"])), - ("address_type", format_number(coin["address_type"])), - ("address_type_p2sh", format_number(coin["address_type_p2sh"])), - ("xpub_magic", format_hex(coin["xpub_magic"])), - ("xprv_magic", format_hex(coin["xprv_magic"])), - ("fork_id", format_number(coin["fork_id"])), - ("version_group_id", format_hex(coin["version_group_id"])), - ("bech32_prefix", format_string(coin["bech32_prefix"])), - ("cashaddr_prefix", format_string(coin["cashaddr_prefix"])), - ("coin_type", "({} | 0x80000000)".format(format_number(coin["slip44"]))), # noqa: E501 - ("curve_name", "{}_NAME".format(coin["curve_name"].upper())), # noqa: E501 - ("curve", "&{}_info".format(coin["curve_name"])), - )) - - -def format_struct(struct): - return "{\n" + "\n".join( - "\t.{0} = {1},".format(member, value) - for member, value in struct.items() - ) + "\n}" - - -def format_coin(coin): - return format_struct(coin_to_struct(coin)) - - -def format_coins(coins): - return "\n".join("{},".format(format_coin(coin)) for coin in coins) - - -if __name__ == "__main__": - os.chdir(os.path.abspath(os.path.dirname(__file__))) - - coins = [] - - support = json.load(open('defs/support.json', 'r'), object_pairs_hook=collections.OrderedDict) - defs = support['trezor1'].keys() - - for c in defs: - name = c.replace(' ', '_').lower() - if name == 'testnet': - name = 'bitcoin_testnet' - data = json.load(open('defs/coins/%s.json' % name, 'r')) - coins.append(data) - - with open("coin_info.h", "w+") as f: - f.write(HEADER_TEMPLATE.format(count=len(coins))) - - with open("coin_info.c", "w+") as f: - f.write(CODE_TEMPLATE.format(coins=format_coins(coins))) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 9e1dbfbeb5..fffb81021f 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -33,6 +33,7 @@ #include "util.h" #include "gettext.h" #include "ethereum_tokens.h" +#include "ethereum_networks.h" #include "memzero.h" #include "messages.pb.h" @@ -247,32 +248,7 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, if (tx_type == 1 || tx_type == 6) { suffix = " WAN"; } else { - // constants from trezor-common/defs/ethereum/networks.json - switch (chain_id) { - case 1: suffix = " ETH"; break; // Ethereum - case 2: suffix = " EXP"; break; // Expanse - case 3: suffix = " tROP"; break; // Ethereum Testnet Ropsten - case 4: suffix = " tRIN"; break; // Ethereum Testnet Rinkeby - case 8: suffix = " UBQ"; break; // UBIQ - case 20: suffix = " EOSC"; break; // EOS Classic - case 28: suffix = " ETSC"; break; // Ethereum Social - case 30: suffix = " RSK"; break; // RSK - case 31: suffix = " tRSK"; break; // RSK Testnet - case 42: suffix = " tKOV"; break; // Ethereum Testnet Kovan - case 60: suffix = " GO"; break; // GoChain - case 61: suffix = " ETC"; break; // Ethereum Classic - case 62: suffix = " tETC"; break; // Ethereum Classic Testnet - case 64: suffix = " ELLA"; break; // Ellaism - case 820: suffix = " CLO"; break; // Callisto - case 1620: suffix = " ATH"; break; // Atheios - case 1987: suffix = " EGEM"; break; // EtherGem - case 31102: suffix = " ESN"; break; // Ethersocial Network - case 200625: suffix = " AKA"; break; // Akroma - case 1313114: suffix = " ETHO"; break; // Ether-1 - case 7762959: suffix = " MUSI"; break; // Musicoin - case 3125659152: suffix = " PIRL"; break; // Pirl - default : suffix = " UNKN"; break; // unknown chain - } + ASSIGN_ETHEREUM_SUFFIX(suffix, chain_id); } } bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); diff --git a/firmware/ethereum_networks.h.mako b/firmware/ethereum_networks.h.mako new file mode 100644 index 0000000000..6416aba398 --- /dev/null +++ b/firmware/ethereum_networks.h.mako @@ -0,0 +1,34 @@ +<% +BKSL = "\\" + +networks = list(supported_on("trezor1", eth)) +max_chain_id_length = 0 +max_suffix_length = 0 +for n in networks: + max_chain_id_length = max(len(str(n.chain_id)), max_chain_id_length) + max_suffix_length = max(len(n.shortcut), max_suffix_length) + +def align_chain_id(n): + return "{:>{w}}".format(n.chain_id, w=max_chain_id_length) + +def align_suffix(n): + cstr = c_str(" " + n.shortcut) + ";" + # we add two quotes, a space and a semicolon. hence +4 chars + return "{:<{w}}".format(cstr, w=max_suffix_length + 4) + +%>\ +// This file is automatically generated from ethereum_networks.h.mako +// DO NOT EDIT + +#ifndef __ETHEREUM_NETWORKS_H__ +#define __ETHEREUM_NETWORKS_H__ + +#define ASSIGN_ETHEREUM_SUFFIX(suffix, chain_id) ${BKSL} + switch (chain_id) { ${BKSL} +% for n in networks: + case ${align_chain_id(n)}: suffix = ${align_suffix(n)} break; /* ${n.name} */ ${BKSL} +% endfor + default: suffix = " UNKN"; break; /* unknown chain */ ${BKSL} + } + +#endif diff --git a/firmware/ethereum_tokens.c b/firmware/ethereum_tokens.c deleted file mode 100644 index 93ed7f232d..0000000000 --- a/firmware/ethereum_tokens.c +++ /dev/null @@ -1,813 +0,0 @@ -#include -#include "ethereum_tokens.h" - -const TokenType tokens[TOKENS_COUNT] = { - {64, "\x99\x1e\x7f\xe4\xb0\x5f\x2b\x3d\xb1\xd7\x88\xe7\x05\x96\x3f\x5d\x64\x7b\x00\x44", " MINING", 18}, // ella / Ella Mining Tokens - {61, "\x08\x5f\xb4\xf2\x40\x31\xea\xed\xbc\x2b\x61\x1a\xa5\x28\xf2\x23\x43\xeb\x52\xdb", " BEC", 8}, // etc / BEC - {61, "\x5a\xce\x17\xf8\x7c\x73\x91\xe5\x79\x2a\x76\x83\x06\x9a\x80\x25\xb8\x3b\xbd\x85", " PLAY", 0}, // etc / Smart Billions - { 1, "\x4e\x84\xe9\xe5\xfb\x0a\x97\x26\x28\xcf\x45\x68\xc4\x03\x16\x7e\xf1\xd4\x04\x31", " $FFC", 18}, // eth / $Fluzcoin - { 1, "\xa0\x24\xe8\x05\x7e\xec\x47\x4a\x9b\x23\x56\x83\x37\x07\xdd\x05\x79\xe2\x6e\xf3", " $FXY", 18}, // eth / $FIXY NETWORK - { 1, "\xcd\xb7\xec\xfd\x34\x03\xee\xf3\x88\x2c\x65\xb7\x61\xef\x9b\x50\x54\x89\x0a\x47", " $HUR", 18}, // eth / $Hurify Token - { 1, "\x7d\xd7\xf5\x6d\x69\x7c\xc0\xf2\xb5\x2b\xd5\x5c\x05\x7f\x37\x8f\x1f\xe6\xab\x4b", " $TEAK", 18}, // eth / $TEAK - { 1, "\xb6\xed\x76\x44\xc6\x94\x16\xd6\x7b\x52\x2e\x20\xbc\x29\x4a\x9a\x9b\x40\x5b\x31", " 0xBTC", 8}, // eth / 0xBitcoin - { 1, "\xaf\x30\xd2\xa7\xe9\x0d\x7d\xc3\x61\xc8\xc4\x58\x5e\x9b\xb7\xd2\xf6\xf1\x5b\xc7", " 1ST", 18}, // eth / FirstBlood - { 1, "\xfd\xbc\x1a\xdc\x26\xf0\xf8\xf8\x60\x6a\x5d\x63\xb7\xd3\xa3\xcd\x21\xc2\x2b\x23", " 1WO", 8}, // eth / 1WO - { 1, "\x9f\xc0\x58\x32\x20\xeb\x44\xfa\xee\x9e\x2d\xc1\xe6\x3f\x39\x20\x4d\xdd\x90\x90", " 2DC", 18}, // eth / DualChain - { 1, "\xae\xc9\x8a\x70\x88\x10\x41\x48\x78\xc3\xbc\xdf\x46\xaa\xd3\x1d\xed\x4a\x45\x57", " 300", 18}, // eth / 300 Token Sparta - { 1, "\x43\x02\x41\x36\x8c\x1d\x29\x3f\xda\x21\xdb\xa8\xbb\x7a\xf3\x20\x07\xc5\x91\x09", " 3LT", 8}, // eth / TrillionToken - { 1, "\xbd\xe8\xf7\x82\x0b\x55\x44\xa4\x9d\x34\xf9\xdd\xea\xca\xbe\xdc\x7c\x0b\x5a\xdc", " A18", 0}, // eth / Apollo18 - { 1, "\xb9\x8d\x4c\x97\x42\x5d\x99\x08\xe6\x6e\x53\xa6\xfd\xf6\x73\xac\xca\x0b\xe9\x86", " ABT", 18}, // eth / ArcBlock Token - { 1, "\x0e\x8d\x6b\x47\x1e\x33\x2f\x14\x0e\x7d\x9d\xbb\x99\xe5\xe3\x82\x2f\x72\x8d\xa6", " ABYSS", 18}, // eth / ABYSS - { 1, "\x13\xf1\xb7\xfd\xfb\xe1\xfc\x66\x67\x6d\x56\x48\x3e\x21\xb1\xec\xb4\x0b\x58\xe2", " ACC", 18}, // eth / Accelerator Network - { 1, "\xe6\x9a\x35\x3b\x31\x52\xdd\x7b\x70\x6f\xf7\xdd\x40\xfe\x1d\x18\xb7\x80\x2d\x31", " ADH", 18}, // eth / AdHive Token - { 1, "\x88\x10\xc6\x34\x70\xd3\x86\x39\x95\x4c\x6b\x41\xaa\xc5\x45\x84\x8c\x46\x48\x4a", " ADI", 18}, // eth / Aditus - { 1, "\x66\x0e\x71\x48\x37\x85\xf6\x61\x33\x54\x8b\x10\xf6\x92\x6d\xc3\x32\xb0\x6e\x61", " ADL", 18}, // eth / Adelphoi - { 1, "\x42\x28\x66\xa8\xf0\xb0\x32\xc5\xcf\x1d\xfb\xde\xf3\x1a\x20\xf4\x50\x95\x62\xb0", " ADST", 0}, // eth / AdShares - { 1, "\xd0\xd6\xd6\xc5\xfe\x4a\x67\x7d\x34\x3c\xc4\x33\x53\x6b\xb7\x17\xba\xe1\x67\xdd", " ADT", 9}, // eth / AdToken - { 1, "\x44\x70\xbb\x87\xd7\x7b\x96\x3a\x01\x3d\xb9\x39\xbe\x33\x2f\x92\x7f\x2b\x99\x2e", " ADX", 4}, // eth / AdEx Network - { 1, "\x5c\xa9\xa7\x1b\x1d\x01\x84\x9c\x0a\x95\x49\x0c\xc0\x05\x59\x71\x7f\xcf\x0d\x1d", " AE", 18}, // eth / aeternity - { 1, "\x8e\xb2\x43\x19\x39\x37\x16\x66\x8d\x76\x8d\xce\xc2\x93\x56\xae\x9c\xff\xe2\x85", " AGI", 8}, // eth / SingularityNET - { 1, "\x4c\xed\xa7\x90\x6a\x5e\xd2\x17\x97\x85\xcd\x3a\x40\xa6\x9e\xe8\xbc\x99\xc4\x66", " AION", 8}, // eth / Aion - { 1, "\x27\xdc\xe1\xec\x4d\x3f\x72\xc3\xe4\x57\xcc\x50\x35\x4f\x1f\x97\x5d\xde\xf4\x88", " AIR", 8}, // eth / AirToken - { 1, "\x10\x63\xce\x52\x42\x65\xd5\xa3\xa6\x24\xf4\x91\x4a\xcd\x57\x3d\xd8\x9c\xe9\x88", " AIX", 18}, // eth / Aigang - { 1, "\x1c\xa4\x3a\x17\x0b\xad\x61\x93\x22\xe6\xf5\x4d\x46\xb5\x7e\x50\x4d\xb6\x63\xaa", " AKC", 18}, // eth / ARTWOOK COIN - { 1, "\x18\x1a\x63\x74\x6d\x3a\xdc\xf3\x56\xcb\xc7\x3a\xce\x22\x83\x2f\xfb\xb1\xee\x5a", " ALCO", 8}, // eth / ALCO - { 1, "\xea\x61\x0b\x11\x53\x47\x77\x20\x74\x8d\xc1\x3e\xd3\x78\x00\x39\x41\xd8\x4f\xab", " ALIS", 18}, // eth / ALIS Token - { 1, "\x63\x8a\xc1\x49\xea\x8e\xf9\xa1\x28\x6c\x41\xb9\x77\x01\x7a\xa7\x35\x9e\x6c\xfa", " ALTS", 18}, // eth / ALTS Token - { 1, "\x4d\xc3\x64\x3d\xbc\x64\x2b\x72\xc1\x58\xe7\xf3\xd2\xff\x23\x2d\xf6\x1c\xb6\xce", " AMB", 18}, // eth / Amber Token - { 1, "\x94\x9b\xed\x88\x6c\x73\x9f\x1a\x32\x73\x62\x9b\x33\x20\xdb\x0c\x50\x24\xc7\x19", " AMIS", 9}, // eth / AMIS - { 1, "\xca\x0e\x72\x69\x60\x0d\x35\x3f\x70\xb1\x4a\xd1\x18\xa4\x95\x75\x45\x5c\x0f\x2f", " AMLT", 18}, // eth / AMLT - { 1, "\x73\x7f\x98\xac\x8c\xa5\x9f\x2c\x68\xad\x65\x8e\x3c\x3d\x8c\x89\x63\xe4\x0a\x4c", " AMN", 18}, // eth / Amon - { 1, "\x38\xc8\x7a\xa8\x9b\x2b\x8c\xd9\xb9\x5b\x73\x6e\x1f\xa7\xb6\x12\xea\x97\x21\x69", " AMO", 18}, // eth / AMO Coin - { 1, "\x84\x93\x6c\xf7\x63\x0a\xa3\xe2\x7d\xd9\xaf\xf9\x68\xb1\x40\xd5\xae\xe4\x9f\x5a", " AMTC", 8}, // eth / AmberTime Coin - { 1, "\x96\x0b\x23\x6a\x07\xcf\x12\x26\x63\xc4\x30\x33\x50\x60\x9a\x66\xa7\xb2\x88\xc0", " ANT", 18}, // eth / ANT - { 1, "\x4c\x0f\xbe\x1b\xb4\x66\x12\x91\x5e\x79\x67\xd2\xc3\x21\x3c\xd4\xd8\x72\x57\xad", " APIS", 18}, // eth / APIS - { 1, "\x1a\x7a\x8b\xd9\x10\x6f\x2b\x8d\x97\x7e\x08\x58\x2d\xc7\xd2\x4c\x72\x3a\xb0\xdb", " APPC", 18}, // eth / AppCoins - { 1, "\x23\xae\x3c\x5b\x39\xb1\x2f\x06\x93\xe0\x54\x35\xee\xaa\x1e\x51\xd8\xc6\x15\x30", " APT", 18}, // eth / AIGang - { 1, "\xac\x70\x9f\xcb\x44\xa4\x3c\x35\xf0\xda\x4e\x31\x63\xb1\x17\xa1\x7f\x37\x70\xf5", " ARC", 18}, // eth / Arcade Token - { 1, "\x12\x45\xef\x80\xf4\xd9\xe0\x2e\xd9\x42\x53\x75\xe8\xf6\x49\xb9\x22\x1b\x31\xd8", " ARCT", 8}, // eth / ArbitrageCT - { 1, "\x75\xaa\x7b\x0d\x02\x53\x2f\x38\x33\xb6\x6c\x7f\x0a\xd3\x53\x76\xd3\x73\xdd\xf8", " ARD", 18}, // eth / Accord - { 1, "\xba\x5f\x11\xb1\x6b\x15\x57\x92\xcf\x3b\x2e\x68\x80\xe8\x70\x68\x59\xa8\xae\xb6", " ARN", 8}, // eth / Aeron Token - { 1, "\xfe\xc0\xcf\x7f\xe0\x78\xa5\x00\xab\xf1\x5f\x12\x84\x95\x8f\x22\x04\x9c\x2c\x7e", " ART", 18}, // eth / ART - { 1, "\x77\x05\xfa\xa3\x4b\x16\xeb\x6d\x77\xdf\xc7\x81\x2b\xe2\x36\x7b\xa6\xb0\x24\x8e", " ARX", 8}, // eth / ARX - { 1, "\xb0\xd9\x26\xc1\xbc\x3d\x78\x06\x4f\x3e\x10\x75\xd5\xbd\x9a\x24\xf3\x5a\xe6\xc5", " ARXT", 18}, // eth / Assistive Reality ARX - { 1, "\x27\x05\x4b\x13\xb1\xb7\x98\xb3\x45\xb5\x91\xa4\xd2\x2e\x65\x62\xd4\x7e\xa7\x5a", " AST", 4}, // eth / Airswap - { 1, "\x17\x05\x2d\x51\xe9\x54\x59\x2c\x10\x46\x32\x0c\x23\x71\xab\xab\x6c\x73\xef\x10", " ATH", 18}, // eth / Athenian Warrior Token - { 1, "\x15\x43\xd0\xf8\x34\x89\xe8\x2a\x13\x44\xdf\x68\x27\xb2\x3d\x54\x1f\x23\x5a\x50", " ATH (AIgatha Token)", 18}, // eth / AIgatha Token - { 1, "\x78\xb7\xfa\xda\x55\xa6\x4d\xd8\x95\xd8\xc8\xc3\x57\x79\xdd\x8b\x67\xfa\x8a\x05", " ATL", 18}, // eth / ATL - { 1, "\x97\xae\xb5\x06\x6e\x1a\x59\x0e\x86\x8b\x51\x14\x57\xbe\xb6\xfe\x99\xd3\x29\xf5", " ATMI", 18}, // eth / Atonomi - { 1, "\x88\x78\x34\xd3\xb8\xd4\x50\xb6\xba\xb1\x09\xc2\x52\xdf\x3d\xa2\x86\xd7\x3c\xe4", " ATT", 18}, // eth / Atmatrix Token - { 1, "\x63\x39\x78\x4d\x94\x78\xda\x43\x10\x6a\x42\x91\x96\x77\x2a\x02\x9c\x2f\x17\x7d", " ATTN", 18}, // eth / Attention Token - { 1, "\xed\x24\x79\x80\x39\x6b\x10\x16\x9b\xb1\xd3\x6f\x6e\x27\x8e\xd1\x67\x00\xa6\x0f", " AVA", 4}, // eth / AVA - { 1, "\x0d\x88\xed\x6e\x74\xbb\xfd\x96\xb8\x31\x23\x16\x38\xb6\x6c\x05\x57\x1e\x82\x4f", " AVT", 18}, // eth / AVT - { 1, "\xcd\x4b\x4b\x0f\x32\x84\xa3\x3a\xc4\x9c\x67\x96\x1e\xc6\xe1\x11\x70\x83\x18\xcf", " AX1", 5}, // eth / AX1 Mining Token - { 1, "\x9a\xf2\xc6\xb1\xa2\x8d\x3d\x6b\xc0\x84\xbd\x26\x7f\x70\xe9\x0d\x49\x74\x1d\x5b", " AXP", 8}, // eth / AXP - { 1, "\xc3\x9e\x62\x6a\x04\xc5\x97\x1d\x77\x0e\x31\x97\x60\xd7\x92\x65\x02\x97\x5e\x47", " AXPR", 18}, // eth / aXpire - { 1, "\xf8\x7f\x0d\x91\x53\xfe\xa5\x49\xc7\x28\xad\x61\xcb\x80\x15\x95\xa6\x8b\x73\xde", " BANX", 18}, // eth / BANX - { 1, "\x0d\x87\x75\xf6\x48\x43\x06\x79\xa7\x09\xe9\x8d\x2b\x0c\xb6\x25\x0d\x28\x87\xef", " BAT", 18}, // eth / BAT - { 1, "\x4a\x60\x58\x66\x6c\xf1\x05\x7e\xac\x3c\xd3\xa5\xa6\x14\x62\x05\x47\x55\x9f\xc9", " BBK", 18}, // eth / BRICKBLOCK TOKEN - { 1, "\x73\x67\xa6\x80\x39\xd4\x70\x4f\x30\xbf\xbf\x6d\x94\x80\x20\xc3\xb0\x7d\xfc\x59", " BCBC", 18}, // eth / Beercoin - { 1, "\x1e\x79\x7c\xe9\x86\xc3\xcf\xf4\x47\x2f\x7d\x38\xd5\xc4\xab\xa5\x5d\xfe\xfe\x40", " BCDN", 15}, // eth / BCDN - { 1, "\xac\xfa\x20\x9f\xb7\x3b\xf3\xdd\x5b\xbf\xb1\x10\x1b\x9b\xc9\x99\xc4\x90\x62\xa5", " BCDT", 18}, // eth / Blockchain Certified Data Token - { 1, "\xbc\x12\x34\x55\x2e\xbe\xa3\x2b\x51\x21\x19\x03\x56\xbb\xa6\xd3\xbb\x22\x5b\xb5", " BCL", 18}, // eth / BCL - { 1, "\x1c\x44\x81\x75\x0d\xaa\x5f\xf5\x21\xa2\xa7\x49\x0d\x99\x81\xed\x46\x46\x5d\xbd", " BCPT", 18}, // eth / BCPT - { 1, "\x10\x14\x61\x3e\x2b\x3c\xbc\x4d\x57\x50\x54\xd4\x98\x2e\x58\x0d\x9b\x99\xd7\xb1", " BCV", 8}, // eth / BitCapitalVendor Token - { 1, "\x19\x61\xb3\x33\x19\x69\xed\x52\x77\x07\x51\xfc\x71\x8e\xf5\x30\x83\x8b\x6d\xee", " BDG", 18}, // eth / BitDegree Token - { 1, "\x4d\x8f\xc1\x45\x3a\x0f\x35\x9e\x99\xc9\x67\x59\x54\xe6\x56\xd8\x0d\x99\x6f\xbf", " BEE", 18}, // eth / Bee Token - { 1, "\x74\xc1\xe4\xb8\xca\xe5\x92\x69\xec\x1d\x85\xd3\xd4\xf3\x24\x39\x60\x48\xf4\xac", " BeerCoin", 0}, // eth / BeerCoin - { 1, "\x6a\xeb\x95\xf0\x6c\xda\x84\xca\x34\x5c\x2d\xe0\xf3\xb7\xf9\x69\x23\xa4\x4f\x4c", " BERRY", 14}, // eth / Berry - { 1, "\x8a\xa3\x3a\x78\x99\xfc\xc8\xea\x5f\xbe\x6a\x60\x8a\x10\x9c\x38\x93\xa1\xb8\xb2", " BET", 18}, // eth / BET - { 1, "\x14\xc9\x26\xf2\x29\x00\x44\xb6\x47\xe1\xbf\x20\x72\xe6\x7b\x49\x5e\xff\x19\x05", " BETHER", 18}, // eth / Bethereum - { 1, "\x76\x31\x86\xeb\x8d\x48\x56\xd5\x36\xed\x44\x78\x30\x29\x71\x21\x4f\xeb\xc6\xa9", " BETR", 18}, // eth / BETR - { 1, "\xb2\xbf\xeb\x70\xb9\x03\xf1\xba\xac\x7f\x2b\xa2\xc6\x29\x34\xc7\xe5\xb9\x74\xc4", " BKB", 8}, // eth / BetKing Bankroll Token - { 1, "\x3c\xf9\xe0\xc3\x85\xa5\xab\xec\x9f\xd2\xa7\x17\x90\xaa\x34\x4c\x4e\x8e\x35\x70", " BKRx", 18}, // eth / BlockRx - { 1, "\x45\x24\x5b\xc5\x92\x19\xee\xaa\xf6\xcd\x3f\x38\x2e\x07\x8a\x46\x1f\xf9\xde\x7b", " BKX", 18}, // eth / BANKEX - { 1, "\x10\x7c\x45\x04\xcd\x79\xc5\xd2\x69\x6e\xa0\x03\x0a\x8d\xd4\xe9\x26\x01\xb8\x2e", " BLT", 18}, // eth / Bloom - { 1, "\x53\x9e\xfe\x69\xbc\xdd\x21\xa8\x3e\xfd\x91\x22\x57\x1a\x64\xcc\x25\xe0\x28\x2b", " BLUE", 8}, // eth / Ethereum Blue - { 1, "\xce\x59\xd2\x9b\x09\xaa\xe5\x65\xfe\xee\xf8\xe5\x2f\x47\xc3\xcd\x53\x68\xc6\x63", " BLX (Bullion)", 18}, // eth / Bullion Crypto - { 1, "\xe5\xa7\xc1\x29\x72\xf3\xbb\xfe\x70\xed\x29\x52\x1c\x89\x49\xb8\xaf\x6a\x09\x70", " BLX (Iconomi)", 18}, // eth / Iconomi - { 1, "\x57\x32\x04\x6a\x88\x37\x04\x40\x4f\x28\x4c\xe4\x1f\xfa\xdd\x5b\x00\x7f\xd6\x68", " BLZ", 18}, // eth / Bluezelle - { 1, "\xdf\x6e\xf3\x43\x35\x07\x80\xbf\x8c\x34\x10\xbf\x06\x2e\x0c\x01\x5b\x1d\xd6\x71", " BMC", 8}, // eth / Blackmoon Crypto BMC Token - { 1, "\xf0\x28\xad\xee\x51\x53\x3b\x1b\x47\xbe\xaa\x89\x0f\xeb\x54\xa4\x57\xf5\x1e\x89", " BMT", 18}, // eth / BMT - { 1, "\x98\x6e\xe2\xb9\x44\xc4\x2d\x01\x7f\x52\xaf\x21\xc4\xc6\x9b\x84\xdb\xea\x35\xd8", " BMX", 18}, // eth / BitMartToken - { 1, "\xb8\xc7\x74\x82\xe4\x5f\x1f\x44\xde\x17\x45\xf5\x2c\x74\x42\x6c\x63\x1b\xdd\x52", " BNB", 18}, // eth / BNB - { 1, "\xdd\x6b\xf5\x6c\xa2\xad\xa2\x4c\x68\x3f\xac\x50\xe3\x77\x83\xe5\x5b\x57\xaf\x9f", " BNC", 12}, // eth / BNC - { 1, "\xda\x2c\x42\x4f\xc9\x8c\x74\x1c\x2d\x4e\xf2\xf4\x28\x97\xce\xfe\xd8\x97\xca\x75", " BNFT", 9}, // eth / Benefits Coin - { 1, "\x1f\x57\x3d\x6f\xb3\xf1\x3d\x68\x9f\xf8\x44\xb4\xce\x37\x79\x4d\x79\xa7\xff\x1c", " BNT", 18}, // eth / Bancor - { 1, "\xd2\xd6\x15\x86\x83\xae\xe4\xcc\x83\x80\x67\x72\x72\x09\xa0\xaa\xf4\x35\x9d\xe3", " BNTY", 18}, // eth / Bounty0x Token - { 1, "\xdf\x34\x79\x11\x91\x0b\x6c\x9a\x42\x86\xba\x8e\x2e\xe5\xea\x4a\x39\xeb\x21\x34", " BOB", 18}, // eth / Bob's repair - { 1, "\xcc\x34\x36\x6e\x38\x42\xca\x1b\xd3\x6c\x1f\x32\x4d\x15\x25\x79\x60\xfc\xc8\x01", " BON", 18}, // eth / Bonpay - { 1, "\x7f\x1e\x2c\x7d\x6a\x69\xbf\x34\x82\x4d\x72\xc5\x3b\x45\x50\xe8\x95\xc0\xd8\xc2", " BOP", 8}, // eth / BlockOptiopns Token - { 1, "\xc2\xc6\x3f\x23\xec\x5e\x97\xef\xbd\x75\x65\xdf\x9e\xc7\x64\xfd\xc7\xd4\xe9\x1d", " BOU", 18}, // eth / Boule Coin - { 1, "\xe1\xa1\x78\xb6\x81\xbd\x05\x96\x4d\x3e\x3e\xd3\x3a\xe7\x31\x57\x7d\x9d\x96\xdd", " BOX", 18}, // eth / BOX Token - { 1, "\x32\x76\x82\x77\x9b\xab\x2b\xf4\xd1\x33\x7e\x89\x74\xab\x9d\xe8\x27\x5a\x7c\xa8", " BPT", 18}, // eth / Blockport Token - { 1, "\x5a\xf2\xbe\x19\x3a\x6a\xbc\xa9\xc8\x81\x70\x01\xf4\x57\x44\x77\x7d\xb3\x07\x56", " BQX", 8}, // eth / Bitquence - { 1, "\x9e\x77\xd5\xa1\x25\x1b\x6f\x7d\x45\x67\x22\xa6\xea\xc6\xd2\xd5\x98\x0b\xd8\x91", " BRAT", 8}, // eth / BRAT - { 1, "\x55\x8e\xc3\x15\x2e\x2e\xb2\x17\x49\x05\xcd\x19\xae\xa4\xe3\x4a\x23\xde\x9a\xd6", " BRD", 18}, // eth / Bread - { 1, "\xf2\x6e\xf5\xe0\x54\x53\x84\xb7\xdc\xc0\xf2\x97\xf2\x67\x41\x89\x58\x68\x30\xdf", " BSDC", 18}, // eth / BSDC - { 1, "\x50\x9a\x38\xb7\xa1\xcc\x0d\xcd\x83\xaa\x9d\x06\x21\x46\x63\xd9\xec\x7c\x7f\x4a", " BST", 18}, // eth / BlocksquareToken - { 1, "\x08\x86\x94\x9c\x1b\x8c\x41\x28\x60\xc4\x26\x4c\xeb\x80\x83\xd1\x36\x5e\x86\xcf", " BTCE", 8}, // eth / EthereumBitcoin - { 1, "\x5a\xcd\x19\xb9\xc9\x1e\x59\x6b\x1f\x06\x2f\x18\xe3\xd0\x2d\xa7\xed\x8d\x1e\x50", " BTCL", 8}, // eth / BTC Lite - { 1, "\x73\xdd\x06\x9c\x29\x9a\x5d\x69\x1e\x98\x36\x24\x3b\xca\xec\x9c\x8c\x1d\x87\x34", " BTE", 8}, // eth / BTE - { 1, "\xfa\xd5\x72\xdb\x56\x6e\x52\x34\xac\x9f\xc3\xd5\x70\xc4\xed\xc0\x05\x0e\xaa\x92", " BTH", 18}, // eth / Bytether - { 1, "\xa0\x2e\x3b\xb9\xce\xbc\x03\x95\x26\x01\xb3\x72\x4b\x49\x40\xe0\x84\x5b\xeb\xcf", " BTHR", 18}, // eth / Bethereum - { 1, "\xdb\x86\x46\xf5\xb4\x87\xb5\xdd\x97\x9f\xac\x61\x83\x50\xe8\x50\x18\xf5\x57\xd4", " BTK", 18}, // eth / Bitcoin Token - { 1, "\x2a\xcc\xab\x9c\xb7\xa4\x8c\x3e\x82\x28\x6f\x0b\x2f\x87\x98\xd2\x01\xf4\xec\x3f", " BTL (Battle)", 18}, // eth / BTL (Battle) - { 1, "\x92\x68\x5e\x93\x95\x65\x37\xc2\x5b\xb7\x5d\x5d\x47\xfc\xa4\x26\x6d\xd6\x28\xb8", " BTL (Bitlle)", 4}, // eth / Bitlle Token - { 1, "\xcb\x97\xe6\x5f\x07\xda\x24\xd4\x6b\xcd\xd0\x78\xeb\xeb\xd7\xc6\xe6\xe3\xd7\x50", " BTM", 8}, // eth / Bytom - { 1, "\x16\xb0\xe6\x2a\xc1\x3a\x2f\xae\xd3\x6d\x18\xbc\xe2\x35\x6d\x25\xab\x3c\xfa\xd3", " BTQ", 18}, // eth / Bitcoin Boutique - { 1, "\x08\x0a\xa0\x7e\x2c\x71\x85\x15\x0d\x7e\x4d\xa9\x88\x38\xa8\xd2\xfe\xac\x3d\xfc", " BTT", 0}, // eth / Bitether - { 1, "\xfa\x45\x6c\xf5\x52\x50\xa8\x39\x08\x8b\x27\xee\x32\xa4\x24\xd7\xda\xcb\x54\xff", " BTTX", 18}, // eth / Blocktrade.com - { 1, "\xe5\xf8\x67\xde\x1e\xa8\x13\x46\xdf\x51\x81\xb8\xb4\x8d\xd6\xb0\xbb\x33\x57\xb0", " BTZ", 18}, // eth / BTZ by Bunz - { 1, "\xca\x3c\x18\xa6\x5b\x80\x2e\xc2\x67\xf8\xf4\x80\x25\x45\xe7\xf5\x3d\x24\xc7\x5e", " BUC", 18}, // eth / BeeUnity Chain - { 1, "\x26\xe7\x53\x07\xfc\x0c\x02\x14\x72\xfe\xb8\xf7\x27\x83\x95\x31\xf1\x12\xf3\x17", " C20", 18}, // eth / Crypto20's Token - { 1, "\xd4\x2d\xeb\xe4\xed\xc9\x2b\xd5\xa3\xfb\xb4\x24\x3e\x1e\xcc\xf6\xd6\x3a\x4a\x5d", " C8", 18}, // eth / Carboneum - { 1, "\x7d\x4b\x8c\xce\x05\x91\xc9\x04\x4a\x22\xee\x54\x35\x33\xb7\x2e\x97\x6e\x36\xc3", " CAG", 18}, // eth / Change Bank - { 1, "\x1d\x46\x24\x14\xfe\x14\xcf\x48\x9c\x7a\x21\xca\xc7\x85\x09\xf4\xbf\x8c\xd7\xc0", " CAN", 6}, // eth / CAN - { 1, "\x42\x3e\x43\x22\xcd\xda\x29\x15\x6b\x49\xa1\x7d\xfb\xd2\xac\xc4\xb2\x80\x60\x0d", " CAR", 9}, // eth / Car Sharing Community - { 1, "\x4d\x9e\x23\xa3\x84\x2f\xe7\xeb\x76\x82\xb9\x72\x5c\xf6\xc5\x07\xc4\x24\xa4\x1b", " CAR (CarBlock)", 18}, // eth / CarBlock - { 1, "\xa5\x17\xa4\x6b\xaa\xd6\xb0\x54\xa7\x6b\xd1\x9c\x46\x84\x4f\x71\x7f\xe6\x9f\xea", " CARB", 8}, // eth / CarbCoin - { 1, "\x21\x08\xe6\x2d\x33\x5b\xbd\xc8\x9e\xc3\xe9\xd8\x58\x2f\x18\xdc\xfb\x0c\xdf\xf4", " CARCO", 8}, // eth / CARCO - { 1, "\x1e\xd2\xb1\xea\xed\x8e\x96\x8b\xc3\x6e\xb9\x0a\x91\x46\x60\xa7\x18\x27\xa5\xe9", " CARD", 0}, // eth / Cardstack Token - { 1, "\xb0\x7e\xc2\xc2\x88\x34\xb8\x89\xb1\xce\x52\x7c\xa0\xf1\x93\x64\xcd\x38\x93\x5c", " CARD", 0}, // eth / Cardstack Token - { 1, "\xbf\x18\xf2\x46\xb9\x30\x1f\x23\x1e\x95\x61\xb3\x5a\x38\x79\x76\x9b\xb4\x63\x75", " CARE", 18}, // eth / Token CARE - { 1, "\xe8\x78\x0b\x48\xbd\xb0\x5f\x92\x86\x97\xa5\xe8\x15\x5f\x67\x2e\xd9\x14\x62\xf7", " CAS", 18}, // eth / Cashaa - { 1, "\x12\x34\x56\x74\x61\xd3\xf8\xdb\x74\x96\x58\x17\x74\xbd\x86\x9c\x83\xd5\x1c\x93", " CAT (BitClave)", 18}, // eth / CAT (BitClave) - { 1, "\x56\xba\x2e\xe7\x89\x04\x61\xf4\x63\xf7\xbe\x02\xaa\xc3\x09\x9f\x6d\x58\x11\xa8", " CAT (Blockcat)", 18}, // eth / CAT (Blockcat) - { 1, "\x68\xe1\x4b\xb5\xa4\x5b\x96\x81\x32\x7e\x16\xe5\x28\x08\x4b\x9d\x96\x2c\x1a\x39", " CATs (BitClave)_Old", 18}, // eth / CATs (BitClave)_Old - { 1, "\x05\xc3\x61\x7c\xbf\x13\x04\xb9\x26\x0a\xa6\x1e\xc9\x60\xf1\x15\xd6\x7b\xec\xea", " CBIX", 18}, // eth / Cubrix - { 1, "\xc1\x66\x03\x87\x05\xff\xba\xb3\x79\x41\x85\xb3\xa9\xd9\x25\x63\x2a\x1d\xf3\x7d", " CC3", 18}, // eth / Coal Coin - { 1, "\xbe\x11\xee\xb1\x86\xe6\x24\xb8\xf2\x6a\x50\x45\x57\x5a\x13\x40\xe4\x05\x45\x52", " CCC (ICONOMI)", 18}, // eth / CCC (ICONOMI) - { 1, "\xd3\x48\xe0\x7a\x28\x06\x50\x5b\x85\x61\x23\x04\x5d\x27\xae\xed\x90\x92\x4b\x50", " CCLC", 8}, // eth / Christ Coin - { 1, "\x31\x5c\xe5\x9f\xaf\xd3\xa8\xd5\x62\xb7\xec\x1c\x85\x42\x38\x2d\x27\x10\xb0\x6c", " CCS", 18}, // eth / CacaoShares - { 1, "\x8a\x95\xca\x44\x8a\x52\xc0\xad\xf0\x05\x4b\xb3\x40\x2d\xc5\xe0\x9c\xd6\xb2\x32", " CDL", 18}, // eth / Confideal - { 1, "\x17\x7d\x39\xac\x67\x6e\xd1\xc6\x7a\x2b\x26\x8a\xd7\xf1\xe5\x88\x26\xe5\xb0\xaf", " CDT", 18}, // eth / CoinDash - { 1, "\x6f\xff\x38\x06\xbb\xac\x52\xa2\x0e\x0d\x79\xbc\x53\x8d\x52\x7f\x6a\x22\xc9\x6b", " CDX", 18}, // eth / CDX - { 1, "\x2c\xb1\x01\xd7\xda\x0e\xba\xa5\x7d\x3f\x2f\xef\x46\xd7\xff\xb7\xbb\x64\x59\x2b", " CDX", 0}, // eth / Carbon Dollar X - { 1, "\xb0\x56\xc3\x8f\x6b\x7d\xc4\x06\x43\x67\x40\x3e\x26\x42\x4c\xd2\xc6\x06\x55\xe1", " CEEK", 18}, // eth / CEEK VR Token - { 1, "\xf6\x60\xca\x1e\x22\x8e\x7b\xe1\xfa\x8b\x4f\x55\x83\x14\x5e\x31\x14\x7f\xb5\x77", " CET", 18}, // eth / DICE Money Dicet - { 1, "\x5d\xff\x89\xa2\xca\xa4\xd7\x6b\xc2\x86\xf7\x4d\x67\xbd\x71\x8e\xb8\x34\xda\x61", " CFC", 18}, // eth / CryptFillCoin - { 1, "\x12\xfe\xf5\xe5\x7b\xf4\x58\x73\xcd\x9b\x62\xe9\xdb\xd7\xbf\xb9\x9e\x32\xd7\x3e", " CFI", 18}, // eth / Cofound.it - { 1, "\x69\x56\x98\x3f\x8b\x3c\xe1\x73\xb4\xab\x84\x36\x1a\xa0\xad\x52\xf3\x8d\x93\x6f", " CFTY", 8}, // eth / Crafty Token - { 1, "\xba\x9d\x41\x99\xfa\xb4\xf2\x6e\xfe\x35\x51\xd4\x90\xe3\x82\x14\x86\xf1\x35\xba", " CHSB", 8}, // eth / CHSB - { 1, "\x06\x01\x2c\x8c\xf9\x7b\xea\xd5\xde\xae\x23\x70\x70\xf9\x58\x7f\x8e\x7a\x26\x6d", " CK", 0}, // eth / CK - { 1, "\xb1\xc1\xcb\x8c\x7c\x19\x92\xdb\xa2\x4e\x62\x8b\xf7\xd3\x8e\x71\xda\xd4\x6a\xeb", " CLB", 18}, // eth / Cloudbric - { 1, "\x3d\xc9\xa4\x2f\xa7\xaf\xe5\x7b\xe0\x3c\x58\xfd\x7f\x44\x11\xb1\xe4\x66\xc5\x08", " CLL", 18}, // eth / CryptoLiveLeak - { 1, "\x41\x62\x17\x8b\x78\xd6\x98\x54\x80\xa3\x08\xb2\x19\x0e\xe5\x51\x74\x60\x40\x6d", " CLN", 18}, // eth / ColuLocalNetwork - { 1, "\x7f\xce\x28\x56\x89\x9a\x68\x06\xee\xef\x70\x80\x79\x85\xfc\x75\x54\xc6\x63\x40", " CLP", 9}, // eth / CryptoLending - { 1, "\x3e\xdd\x23\x5c\x3e\x84\x0c\x1f\x29\x28\x6b\x2e\x39\x37\x0a\x25\x5c\x7b\x6f\xdb", " CMBT", 8}, // eth / CMBToken - { 1, "\x7e\x66\x75\x25\x52\x1c\xf6\x13\x52\xe2\xe0\x1b\x50\xfa\xaa\xe7\xdf\x39\x74\x9a", " CMC", 18}, // eth / CryptoMart - { 1, "\xf8\x5f\xee\xa2\xfd\xd8\x1d\x51\x17\x7f\x6b\x8f\x35\xf0\xe6\x73\x4c\xe4\x5f\x5f", " CMT", 18}, // eth / CyberMiles Token - { 1, "\xeb\xf2\xf9\xe8\xde\x96\x0f\x64\xec\x0f\xdc\xda\x6c\xb2\x82\x42\x31\x33\x34\x7b", " CNB", 8}, // eth / Canabio - { 1, "\xd4\xc4\x35\xf5\xb0\x9f\x85\x5c\x33\x17\xc8\x52\x4c\xb1\xf5\x86\xe4\x27\x95\xfa", " CND", 18}, // eth / Cindicator - { 1, "\xb4\xb1\xd2\xc2\x17\xec\x07\x76\x58\x4c\xe0\x8d\x3d\xd9\x8f\x90\xed\xed\xa4\x4b", " CO2", 18}, // eth / Climatecoin - { 1, "\x57\x4b\x36\xbc\xed\x44\x33\x38\x87\x5d\x17\x1c\xc3\x77\xe6\x91\xf7\xd4\xf8\x87", " CO2Bit", 18}, // eth / CO2Bit - { 1, "\xb2\xf7\xeb\x1f\x2c\x37\x64\x5b\xe6\x1d\x73\x95\x30\x35\x36\x0e\x76\x8d\x81\xe6", " COB", 18}, // eth / Cobinhood Token - { 1, "\x31\x36\xef\x85\x15\x92\xac\xf4\x9c\xa4\xc8\x25\x13\x1e\x36\x41\x70\xfa\x32\xb3", " COFI", 18}, // eth / CoinFi Token - { 1, "\x0c\x91\xb0\x15\xab\xa6\xf7\xb4\x73\x8d\xcd\x36\xe7\x41\x01\x38\xb2\x9a\xdc\x29", " COIL", 8}, // eth / CoinOil - { 1, "\x5e\x8f\x85\x59\x66\xd6\x38\x13\x5a\x96\x88\x61\xe8\x0d\xda\x72\x22\x91\xb0\x6d", " COIN", 18}, // eth / Coinvest V2 Token - { 1, "\x72\x5b\x19\x0b\xc0\x77\xff\xde\x17\xcf\x54\x9a\xa8\xba\x25\xe2\x98\x55\x0b\x18", " CORI", 2}, // eth / Corrently Invest Token - { 1, "\x65\x29\x2e\xea\xdf\x14\x26\xcd\x2d\xf1\xc4\x79\x3a\x3d\x75\x19\xf2\x53\x91\x3b", " COSS", 18}, // eth / Coss Token - { 1, "\x9e\x96\x60\x44\x45\xec\x19\xff\xed\x9a\x5e\x8d\xd7\xb5\x0a\x29\xc8\x99\xa1\x0c", " COSS", 18}, // eth / Coss Token - { 1, "\xe2\xfb\x65\x29\xef\x56\x6a\x08\x0e\x6d\x23\xde\x0b\xd3\x51\x31\x10\x87\xd5\x67", " COV", 18}, // eth / Covesting - { 1, "\xb7\x87\xd4\xea\xc8\x89\x97\x30\xbb\x8c\x57\xfc\x3c\x99\x8c\x49\xc5\x24\x4e\xc0", " CPEX", 8}, // eth / CoinPulseToken - { 1, "\xf4\x47\x45\xfb\xd4\x1f\x6a\x1b\xa1\x51\xdf\x19\x0d\xb0\x56\x4c\x5f\xcc\x44\x10", " CPY", 18}, // eth / COPYTRACK - { 1, "\x7f\x58\x5b\x91\x30\xc6\x4e\x9e\x9f\x47\x0b\x61\x8a\x7b\xad\xd0\x3d\x79\xca\x7e", " CR7", 18}, // eth / CR7Coin - { 1, "\xae\xf3\x8f\xbf\xbf\x93\x2d\x1a\xef\x3b\x80\x8b\xc8\xfb\xd8\xcd\x8e\x1f\x8b\xc5", " CRB", 8}, // eth / CRB - { 1, "\x67\x2a\x1a\xd4\xf6\x67\xfb\x18\xa3\x33\xaf\x13\x66\x7a\xa0\xaf\x1f\x5b\x5b\xdd", " CRED", 18}, // eth / CRED - { 1, "\x4e\x06\x03\xe2\xa2\x7a\x30\x48\x0e\x5e\x3a\x4f\xe5\x48\xe2\x9e\xf1\x2f\x64\xbe", " CREDO", 18}, // eth / Credo / Bitbounce - { 1, "\xf4\x9c\xdd\x50\xad\x40\x8d\x38\x7d\x61\x1f\x88\xa6\x47\x17\x9c\x3d\xe3\x49\x2b", " CRGO", 18}, // eth / CargoCoin - { 1, "\x92\x38\xbf\xb7\x81\xa5\x5e\xac\xc3\xcf\x05\xf7\xdf\x94\x03\x8c\x19\x8c\xd9\xb9", " CRMT", 8}, // eth / Cremit - { 1, "\x80\xa7\xe0\x48\xf3\x7a\x50\x50\x03\x51\xc2\x04\xcb\x40\x77\x66\xfa\x3b\xae\x7f", " CRPT", 18}, // eth / CrypteriumToken - { 1, "\xf0\xda\x11\x86\xa4\x97\x72\x26\xb9\x13\x5d\x06\x13\xee\x72\xe2\x29\xec\x3f\x4d", " CRT", 18}, // eth / CreamtoeCoin - { 1, "\xe4\xc9\x4d\x45\xf7\xae\xf7\x01\x8a\x5d\x66\xf4\x4a\xf7\x80\xec\x60\x23\x37\x8e", " CryptoCarbon", 6}, // eth / CryptoCarbon - { 1, "\x45\x45\x75\x0f\x39\xaf\x6b\xe4\xf2\x37\xb6\x86\x9d\x4e\xcc\xa9\x28\xfd\x5a\x85", " CTF", 18}, // eth / CryptoTask - { 1, "\xc8\x7c\x5d\xd8\x6a\x3d\x56\x7f\xf2\x87\x01\x88\x6f\xb0\x74\x5a\xaa\x89\x8d\xa4", " CTG", 18}, // eth / CT Global Token - { 1, "\x9e\x7d\x29\xbd\x49\x9b\x6c\x7d\xa2\xa5\xb2\xea\xfc\xf4\xa3\x9d\x3b\xd8\x45\xd1", " CTGC", 18}, // eth / Convenient To Go - { 1, "\xbf\x4c\xfd\x7d\x1e\xde\xee\xa5\xf6\x60\x08\x27\x41\x1b\x41\xa2\x1e\xb0\x8a\xbd", " CTL", 2}, // eth / CTL - { 1, "\xe3\xfa\x17\x7a\xce\xcf\xb8\x67\x21\xcf\x6f\x9f\x42\x06\xbd\x3b\xd6\x72\xd7\xd5", " CTT", 18}, // eth / ChainTrade Token - { 1, "\x66\x2a\xbc\xad\x0b\x7f\x34\x5a\xb7\xff\xb1\xb1\xfb\xb9\xdf\x78\x94\xf1\x8e\x66", " CTX", 18}, // eth / CarTaxi - { 1, "\xda\x6c\xb5\x8a\x0d\x0c\x01\x61\x0a\x29\xc5\xa6\x5c\x30\x3e\x13\xe8\x85\x88\x7c", " cV", 18}, // eth / carVertical - { 1, "\x41\xe5\x56\x00\x54\x82\x4e\xa6\xb0\x73\x2e\x65\x6e\x3a\xd6\x4e\x20\xe9\x4e\x45", " CVC", 8}, // eth / CVC - { 1, "\x21\x34\x05\x7c\x0b\x46\x1f\x89\x8d\x37\x5c\xea\xd6\x52\xac\xae\x62\xb5\x95\x41", " CXC", 18}, // eth / CoxxxCoin - { 1, "\xb6\xee\x96\x68\x77\x1a\x79\xbe\x79\x67\xee\x29\xa6\x3d\x41\x84\xf8\x09\x71\x43", " CXO", 18}, // eth / CargoX - { 1, "\x3f\x06\xb5\xd7\x84\x06\xcd\x97\xbd\xf1\x0f\x5c\x42\x0b\x24\x1d\x32\x75\x9c\x80", " CYFM", 18}, // eth / CyberFM - { 1, "\xda\xb0\xc3\x1b\xf3\x4c\x89\x7f\xb0\xfe\x90\xd1\x2e\xc9\x40\x1c\xaf\x5c\x36\xec", " DAB", 0}, // eth / DAB - { 1, "\xfb\x2f\x26\xf2\x66\xfb\x28\x05\xa3\x87\x23\x0f\x2a\xa0\xa3\x31\xb4\xd9\x6f\xba", " DADI", 18}, // eth / DADI - { 1, "\x89\xd2\x4a\x6b\x4c\xcb\x1b\x6f\xaa\x26\x25\xfe\x56\x2b\xdd\x9a\x23\x26\x03\x59", " DAI", 18}, // eth / Dai Stablecoin v1.0 - { 1, "\x07\xd9\xe4\x9e\xa4\x02\x19\x4b\xf4\x8a\x82\x76\xda\xfb\x16\xe4\xed\x63\x33\x17", " DALC", 8}, // eth / DaleCoin - { 1, "\x9b\x70\x74\x0e\x70\x8a\x08\x3c\x6f\xf3\x8d\xf5\x22\x97\x02\x0f\x5d\xfa\xa5\xee", " DAN", 10}, // eth / DaneelToken - { 1, "\xbb\x9b\xc2\x44\xd7\x98\x12\x3f\xde\x78\x3f\xcc\x1c\x72\xd3\xbb\x8c\x18\x94\x13", " DAO", 16}, // eth / DAO - { 1, "\x81\xc9\x15\x1d\xe0\xc8\xba\xfc\xd3\x25\xa5\x7e\x3d\xb5\xa5\xdf\x1c\xeb\xf7\x9c", " DAT", 18}, // eth / Datum Token - { 1, "\x1b\x5f\x21\xee\x98\xee\xd4\x8d\x29\x2e\x8e\x2d\x3e\xd8\x2b\x40\xa9\x72\x8a\x22", " DATABroker", 18}, // eth / DataBrokerDAO Token - { 1, "\x0c\xf0\xee\x63\x78\x8a\x08\x49\xfe\x52\x97\xf3\x40\x7f\x70\x1e\x12\x2c\xc0\x23", " DATACoin", 18}, // eth / DATACoin - { 1, "\xd8\x2d\xf0\xab\xd3\xf5\x14\x25\xeb\x15\xef\x75\x80\xfd\xa5\x57\x27\x87\x5f\x14", " DAV", 18}, // eth / DAV Token - { 1, "\x61\x72\x5f\x3d\xb4\x00\x4a\xfe\x01\x47\x45\xb2\x1d\xab\x1e\x16\x77\xcc\x32\x8b", " DAXT", 18}, // eth / Digital Asset Exchange Token - { 1, "\xe8\x14\xae\xe9\x60\xa8\x52\x08\xc3\xdb\x54\x2c\x53\xe7\xd4\xa6\xc8\xd5\xf6\x0f", " DAY", 18}, // eth / ChronoLogic DAY - { 1, "\x38\x6f\xaa\x47\x03\xa3\x4a\x7f\xdb\x19\xbe\xc2\xe1\x4f\xd4\x27\xc9\x63\x84\x16", " DCA", 18}, // eth / DoBetAcceptBet - { 1, "\xff\xa9\x3a\xac\xf4\x92\x97\xd5\x1e\x21\x18\x17\x45\x28\x39\x05\x2f\xdf\xb9\x61", " DCC", 18}, // eth / Distributed Credit Chain - { 1, "\x39\x9a\x0e\x6f\xbe\xb3\xd7\x4c\x85\x35\x74\x39\xf4\xc8\xae\xd9\x67\x8a\x5c\xbf", " DCL", 3}, // eth / DCL - { 1, "\x08\xd3\x2b\x0d\xa6\x3e\x2c\x3b\xcf\x80\x19\xc9\xc5\xd8\x49\xd7\xa9\xd7\x91\xe6", " DCN", 0}, // eth / Dentacoin - { 1, "\xcc\x4e\xf9\xee\xaf\x65\x6a\xc1\xa2\xab\x88\x67\x43\xe9\x8e\x97\xe0\x90\xed\x38", " DDF", 18}, // eth / DDF - { 1, "\x15\x12\x02\xc9\xc1\x8e\x49\x56\x56\xf3\x72\x28\x1f\x49\x3e\xb7\x69\x89\x61\xd5", " DEB", 18}, // eth / DEBITUM - { 1, "\x07\x5c\x60\xee\x2c\xd3\x08\xff\x47\x87\x3b\x38\xbd\x9a\x0f\xa5\x85\x33\x82\xc4", " DEEZ", 18}, // eth / DeezNuts - { 1, "\x35\x97\xbf\xd5\x33\xa9\x9c\x9a\xa0\x83\x58\x7b\x07\x44\x34\xe6\x1e\xb0\xa2\x58", " DENT", 8}, // eth / DENT - { 1, "\x7c\xf2\x71\x96\x6f\x36\x34\x3b\xf0\x15\x0f\x25\xe5\x36\x4f\x79\x61\xc5\x82\x01", " DEPO", 0}, // eth / CRYPTODEPOZIT - { 1, "\x89\xcb\xea\xc5\xe8\xa1\x3f\x0e\xbb\x4c\x74\xfa\xdf\xc6\x9b\xe8\x1a\x50\x11\x06", " DEPO (Depository Network)", 18}, // eth / DEPO (Depository Network) - { 1, "\xdd\x94\xde\x9c\xfe\x06\x35\x77\x05\x1a\x5e\xb7\x46\x5d\x08\x31\x7d\x88\x08\xb6", " Devcon2 Token", 0}, // eth / Devcon2 Token - { 1, "\xe0\xb7\x92\x7c\x4a\xf2\x37\x65\xcb\x51\x31\x4a\x0e\x05\x21\xa9\x64\x5f\x0e\x2a", " DGD", 9}, // eth / Digix DAO - { 1, "\xf6\xcf\xe5\x3d\x6f\xeb\xae\xea\x05\x1f\x40\x0f\xf5\xfc\x14\xf0\xcb\xbd\xac\xa1", " DGPT", 18}, // eth / DigiPulse - { 1, "\x6a\xed\xbf\x8d\xff\x31\x43\x72\x20\xdf\x35\x19\x50\xba\x2a\x33\x62\x16\x8d\x1b", " DGS", 8}, // eth / Dragonglass - { 1, "\x1c\x83\x50\x14\x78\xf1\x32\x09\x77\x04\x70\x08\x49\x6d\xac\xbd\x60\xbb\x15\xef", " DGTX", 18}, // eth / DigitexFutures - { 1, "\x4f\x3a\xfe\xc4\xe5\xa3\xf2\xa6\xa1\xa4\x11\xde\xf7\xd7\xdf\xe5\x0e\xe0\x57\xbf", " DGX", 9}, // eth / Digix Gold Token - { 1, "\x55\xb9\xa1\x1c\x2e\x83\x51\xb4\xff\xc7\xb1\x15\x61\x14\x8b\xfa\xc9\x97\x78\x55", " DGX1", 9}, // eth / Digix Gold Token 1.0 - { 1, "\x2e\x07\x1d\x29\x66\xaa\x7d\x8d\xec\xb1\x00\x58\x85\xba\x19\x77\xd6\x03\x8a\x65", " DICE", 16}, // eth / Etheroll - { 1, "\xc7\x19\xd0\x10\xb6\x3e\x5b\xbf\x2c\x05\x51\x87\x2c\xd5\x31\x6e\xd2\x6a\xcd\x83", " DIP", 18}, // eth / Decentralized Insurance Protocol - { 1, "\x13\xf1\x1c\x99\x05\xa0\x8c\xa7\x6e\x3e\x85\x3b\xe6\x3d\x4f\x09\x44\x32\x6c\x72", " DIVX", 18}, // eth / DIVX - { 1, "\xba\x18\x7b\x09\xff\xa8\xdd\xdc\x80\xd2\x57\x1e\xd3\xcb\xc4\xbe\x0a\xf6\x9e\x0c", " DKP", 18}, // eth / Draggin Karma Points - { 1, "\x07\xe3\xc7\x06\x53\x54\x8b\x04\xf0\xa7\x59\x70\xc1\xf8\x1b\x4c\xbb\xfb\x60\x6f", " DLT", 18}, // eth / Agrello - { 1, "\x2c\xcb\xff\x3a\x04\x2c\x68\x71\x6e\xd2\xa2\xcb\x0c\x54\x4a\x9f\x1d\x19\x35\xe1", " DMT", 8}, // eth / DMarket Token - { 1, "\x0a\xbd\xac\xe7\x0d\x37\x90\x23\x5a\xf4\x48\xc8\x85\x47\x60\x3b\x94\x56\x04\xea", " DNT", 18}, // eth / District0x Network Token - { 1, "\xe4\x3e\x20\x41\xdc\x37\x86\xe1\x66\x96\x1e\xd9\x48\x4a\x55\x39\x03\x3d\x10\xfb", " DNX", 18}, // eth / DenCity - { 1, "\x76\x97\x4c\x7b\x79\xdc\x8a\x6a\x10\x9f\xd7\x1f\xd7\xce\xb9\xe4\x0e\xff\x53\x82", " DOW", 18}, // eth / DOW - { 1, "\xee\xf6\xe9\x00\x34\xee\xa8\x9e\x31\xeb\x4b\x8e\xac\xd3\x23\xf2\x8a\x92\xea\xe4", " DOW", 18}, // eth / DOW - { 1, "\x01\xb3\xec\x4a\xae\x1b\x87\x29\x52\x9b\xeb\x49\x65\xf2\x7d\x00\x87\x88\xb0\xeb", " DPP", 18}, // eth / Digital Assets Power Play - { 1, "\x41\x9c\x4d\xb4\xb9\xe2\x5d\x6d\xb2\xad\x96\x91\xcc\xb8\x32\xc8\xd9\xfd\xa0\x5e", " DRGN", 18}, // eth / Dragon - { 1, "\x3c\x75\x22\x65\x55\xfc\x49\x61\x68\xd4\x8b\x88\xdf\x83\xb9\x5f\x16\x77\x1f\x37", " DROP", 0}, // eth / Droplex - { 1, "\x46\x72\xba\xd5\x27\x10\x74\x71\xcb\x50\x67\xa8\x87\xf4\x65\x6d\x58\x5a\x8a\x31", " DROP (dropil)", 18}, // eth / Dropil - { 1, "\x27\x99\xd9\x0c\x6d\x44\xcb\x9a\xa5\xfb\xc3\x77\x17\x7f\x16\xc3\x3e\x05\x6b\x82", " DRP", 0}, // eth / Dripcoin - { 1, "\x62\x1d\x78\xf2\xef\x2f\xd9\x37\xbf\xca\x69\x6c\xab\xaf\x9a\x77\x9f\x59\xb3\xed", " DRP", 2}, // eth / DCorp - { 1, "\x62\xd4\xc0\x46\x44\x31\x4f\x35\x86\x8b\xa4\xc6\x5c\xc2\x7a\x77\x68\x1d\xe7\xa9", " DRVH", 18}, // eth / Driveholic Token - { 1, "\x1e\x09\xbd\x8c\xad\xb4\x41\x63\x2e\x44\x1d\xb3\xe1\xd7\x99\x09\xee\x0a\x22\x56", " DSC", 1}, // eth / Digital Safe Coin - { 1, "\x5a\xdc\x96\x1d\x6a\xc3\xf7\x06\x2d\x2e\xa4\x5f\xef\xb8\xd8\x16\x7d\x44\xb1\x90", " DTH", 18}, // eth / dether - { 1, "\xd2\x34\xbf\x24\x10\xa0\x00\x9d\xf9\xc3\xc6\x3b\x61\x0c\x09\x73\x8f\x18\xcc\xd7", " DTR", 8}, // eth / DTR - { 1, "\xf9\xf7\xc2\x9c\xfd\xf1\x9f\xcf\x1f\x2a\xa6\xb8\x4a\xa3\x67\xbc\xf1\xbd\x16\x76", " DTT", 18}, // eth / Delphi Tech Token - { 1, "\x76\x5f\x0c\x16\xd1\xdd\xc2\x79\x29\x5c\x1a\x7c\x24\xb0\x88\x3f\x62\xd3\x3f\x75", " DTX", 18}, // eth / DaTa eXchange Token - { 1, "\x82\xfd\xed\xfb\x76\x35\x44\x1a\xa5\xa9\x27\x91\xd0\x01\xfa\x73\x88\xda\x80\x25", " DTx", 18}, // eth / DigitalTicks - { 1, "\x9c\x6f\xa4\x22\x09\x16\x9b\xce\xa0\x32\xe4\x01\x18\x8a\x6f\xc3\xe9\xc9\xf5\x9c", " DUBI", 18}, // eth / Decentralized Universal Basic Income - { 1, "\xd4\xcf\xfe\xef\x10\xf6\x0e\xca\x58\x1b\x5e\x11\x46\xb5\xac\xa4\x19\x4a\x4c\x3b", " DUBI", 18}, // eth / Decentralized Universal Basic Income - { 1, "\x99\x4f\x0d\xff\xdb\xae\x0b\xbf\x09\xb6\x52\xd6\xf1\x1a\x49\x3f\xd3\x3f\x42\xb9", " EAGLE", 18}, // eth / EagleCoin - { 1, "\xaf\xc3\x97\x88\xc5\x1f\x0c\x1f\xf7\xb5\x53\x17\xf3\xe7\x02\x99\xe5\x21\xff\xf6", " eBCH", 8}, // eth / eBCH - { 1, "\xeb\x7c\x20\x02\x71\x72\xe5\xd1\x43\xfb\x03\x0d\x50\xf9\x1c\xec\xe2\xd1\x48\x5d", " eBTC", 8}, // eth / eBTC - { 1, "\xa5\x78\xac\xc0\xcb\x78\x75\x78\x1b\x78\x80\x90\x3f\x45\x94\xd1\x3c\xfa\x8b\x98", " ECN", 2}, // eth / ECN - { 1, "\x17\xf9\x34\x75\xd2\xa9\x78\xf5\x27\xc3\xf7\xc4\x4a\xbf\x44\xad\xfb\xa6\x0d\x5c", " ECO2", 2}, // eth / EtherCO2 - { 1, "\xae\xa1\xc1\x8a\x99\x29\x84\x83\x10\x02\xd0\xcf\x90\xe2\x91\xfb\x52\xd7\x26\x49", " ECP", 18}, // eth / ECRYPTO COIN - { 1, "\xfa\x1d\xe2\xee\x97\xe4\xc1\x0c\x94\xc9\x1c\xb2\xb5\x06\x2b\x89\xfb\x14\x0b\x82", " EDC", 6}, // eth / Education Credits - { 1, "\x08\x71\x1d\x3b\x02\xc8\x75\x8f\x2f\xb3\xab\x4e\x80\x22\x84\x18\xa7\xf8\xe3\x9c", " EDG", 0}, // eth / Edgeless - { 1, "\xce\xd4\xe9\x31\x98\x73\x4d\xda\xff\x84\x92\xd5\x25\xbd\x25\x8d\x49\xeb\x38\x8e", " EDO", 18}, // eth / Eidoo - { 1, "\xc5\x28\xc2\x8f\xec\x0a\x90\xc0\x83\x32\x8b\xc4\x5f\x58\x7e\xe2\x15\x76\x0a\x0f", " EDR", 18}, // eth / Endor Protocol Token - { 1, "\x5b\x26\xc5\xd0\x77\x2e\x5b\xba\xc8\xb3\x18\x2a\xe9\xa1\x3f\x9b\xb2\xd0\x37\x65", " EDU", 8}, // eth / EDU - { 1, "\x2a\x22\xe5\xcc\xa0\x0a\x3d\x63\x30\x8f\xa3\x9f\x29\x20\x2e\xb1\xb3\x9e\xef\x52", " EDU", 6}, // eth / EDU Token - { 1, "\xb5\x3a\x96\xbc\xbd\xd9\xcf\x78\xdf\xf2\x0b\xab\x6c\x2b\xe7\xba\xec\x8f\x00\xf8", " eGAS", 8}, // eth / ETH GAS - { 1, "\x8e\x1b\x44\x8e\xc7\xad\xfc\x7f\xa3\x5f\xc2\xe8\x85\x67\x8b\xd3\x23\x17\x6e\x34", " EGT", 18}, // eth / Egretia Token - { 1, "\xf9\xf0\xfc\x71\x67\xc3\x11\xdd\x2f\x1e\x21\xe9\x20\x4f\x87\xeb\xa9\x01\x2f\xb2", " EHT", 8}, // eth / EasyHomes - { 1, "\xbf\x21\x79\x85\x9f\xc6\xd5\xbe\xe9\xbf\x91\x58\x63\x2d\xc5\x16\x78\xa4\x10\x0e", " ELF", 18}, // eth / ELF Token - { 1, "\xc8\xc6\xa3\x1a\x4a\x80\x6d\x37\x10\xa7\xb3\x8b\x7b\x29\x6d\x2f\xab\xcc\xdb\xa8", " ELIX", 18}, // eth / Elixir Token - { 1, "\x44\x19\x7a\x4c\x44\xd6\xa0\x59\x29\x7c\xaf\x6b\xe4\xf7\xe1\x72\xbd\x56\xca\xaf", " ELTCOIN", 8}, // eth / ELTCOIN - { 1, "\xa9\x55\x92\xdc\xff\xa3\xc0\x80\xb4\xb4\x0e\x45\x9c\x5f\x56\x92\xf6\x7d\xb7\xf8", " ELY", 18}, // eth / ELYCOIN - { 1, "\xb6\x7b\x88\xa2\x57\x08\xa3\x5a\xe7\xc2\xd7\x36\xd3\x98\xd2\x68\xce\x4f\x7f\x83", " EMON", 8}, // eth / Etheremon - { 1, "\x95\xda\xaa\xb9\x80\x46\x84\x6b\xf4\xb2\x85\x3e\x23\xcb\xa2\x36\xfa\x39\x4a\x31", " EMONT", 8}, // eth / Etheremon Token - { 1, "\x95\x01\xbf\xc4\x88\x97\xdc\xee\xad\xf7\x31\x13\xef\x63\x5d\x2f\xf7\xee\x4b\x97", " EMT", 18}, // eth / easyMINE Token - { 1, "\xb8\x02\xb2\x4e\x06\x37\xc2\xb8\x7d\x2e\x8b\x77\x84\xc0\x55\xbb\xe9\x21\x01\x1a", " EMV", 2}, // eth / EMovieVenture - { 1, "\x03\x9f\x50\x50\xde\x49\x08\xf9\xb5\xdd\xf4\x0a\x4f\x3a\xa3\xf3\x29\x08\x63\x87", " ENC", 18}, // eth / Ethernet.Cash - { 1, "\xf0\xee\x6b\x27\xb7\x59\xc9\x89\x3c\xe4\xf0\x94\xb4\x9a\xd2\x8f\xd1\x5a\x23\xe4", " ENG", 8}, // eth / Enigma - { 1, "\xf6\x29\xcb\xd9\x4d\x37\x91\xc9\x25\x01\x52\xbd\x8d\xfb\xdf\x38\x0e\x2a\x3b\x9c", " ENJ", 18}, // eth / ENJIN - { 1, "\x5b\xc7\xe5\xf0\xab\x8b\x2e\x10\xd2\xd0\xa3\xf2\x17\x39\xfc\xe6\x24\x59\xae\xf3", " ENTRP", 18}, // eth / Hut34 Entropy Token - { 1, "\x86\xfa\x04\x98\x57\xe0\x20\x9a\xa7\xd9\xe6\x16\xf7\xeb\x3b\x3b\x78\xec\xfd\xb0", " EOS", 18}, // eth / EOS - { 1, "\x7e\x9e\x43\x1a\x0b\x8c\x4d\x53\x2c\x74\x5b\x10\x43\xc7\xfa\x29\xa4\x8d\x4f\xba", " eosDAC", 18}, // eth / eosDAC - { 1, "\x35\xba\xa7\x20\x38\xf1\x27\xf9\xf8\xc8\xf9\xb4\x91\x04\x9f\x64\xf3\x77\x91\x4d", " EPX", 4}, // eth / ethPoker.io EPX - { 1, "\xe8\xa1\xdf\x95\x8b\xe3\x79\x04\x5e\x2b\x46\xa3\x1a\x98\xb9\x3a\x2e\xcd\xfd\xed", " ESZ", 18}, // eth / ESZCoin - { 1, "\x1b\x97\x43\xf5\x56\xd6\x5e\x75\x7c\x4c\x65\x0b\x45\x55\xba\xf3\x54\xcb\x8b\xd3", " ETBS", 12}, // eth / Ethbits - { 1, "\xdd\x74\xa7\xa3\x76\x9f\xa7\x25\x61\xb3\xa6\x9e\x65\x96\x8f\x49\x74\x8c\x69\x0c", " ETCH", 18}, // eth / ETCH - { 1, "\x3a\x26\x74\x6d\xdb\x79\xb1\xb8\xe4\x45\x0e\x3f\x4f\xfe\x32\x85\xa3\x07\x38\x7e", " ETHB", 8}, // eth / EtherBTC - { 1, "\x69\x27\xc6\x9f\xb4\xda\xf2\x04\x3f\xbb\x1c\xb7\xb8\x6c\x56\x61\x41\x6b\xea\x29", " ETR", 18}, // eth / Etheruem Risen - { 1, "\xab\xdf\x14\x78\x70\x23\x5f\xcf\xc3\x41\x53\x82\x8c\x76\x9a\x70\xb3\xfa\xe0\x1f", " EURT", 6}, // eth / EUR Tether (erc20) - { 1, "\x52\x36\x30\x97\x6e\xb6\x14\x76\x21\xb5\xc3\x1c\x78\x1e\xbe\x2e\xc2\xa8\x06\xe0", " eUSD", 18}, // eth / Ether-Backed USD Nomins (erc20) - { 1, "\x92\x31\x08\xa4\x39\xc4\xe8\xc2\x31\x5c\x4f\x65\x21\xe5\xce\x95\xb4\x4e\x9b\x4c", " EVE", 18}, // eth / EVE - { 1, "\xd7\x80\xae\x2b\xf0\x4c\xd9\x6e\x57\x7d\x3d\x01\x47\x62\xf8\x31\xd9\x71\x29\xd0", " EVN", 18}, // eth / Envion AG - { 1, "\xf3\xdb\x5f\xa2\xc6\x6b\x7a\xf3\xeb\x0c\x0b\x78\x25\x10\x81\x6c\xbe\x48\x13\xb8", " EVX", 4}, // eth / EVX Token - { 1, "\xc9\x8e\x06\x39\xc6\xd2\xec\x03\x7a\x61\x53\x41\xc3\x69\x66\x6b\x11\x0e\x80\xe5", " EXMR", 8}, // eth / eXMRcoin - { 1, "\x5c\x74\x3a\x35\xe9\x03\xf6\xc5\x84\x51\x4e\xc6\x17\xac\xee\x06\x11\xcf\x44\xf3", " EXY", 18}, // eth / Experty - { 1, "\x19\x0e\x56\x9b\xe0\x71\xf4\x0c\x70\x4e\x15\x82\x5f\x28\x54\x81\xcb\x74\xb6\xcc", " FAM", 12}, // eth / FAM - { 1, "\x90\x16\x2f\x41\x88\x6c\x09\x46\xd0\x99\x99\x73\x6f\x1c\x15\xc8\xa1\x05\xa4\x21", " FAN", 18}, // eth / Fan Token - { 1, "\x7f\x67\x15\xc3\xfc\x47\x40\xa0\x2f\x70\xde\x85\xb9\xfd\x50\xac\x60\x01\xfe\xd9", " FANX", 18}, // eth / FANX Token - { 1, "\x7d\xcb\x3b\x23\x56\xc8\x22\xd3\x57\x7d\x4d\x06\x0d\x0d\x5d\x78\xc8\x60\x48\x8c", " FANX", 18}, // eth / FANX Token - { 1, "\x00\x9e\x86\x49\x23\xb4\x92\x63\xc7\xf1\x0d\x19\xb7\xf8\xab\x7a\x9a\x5a\xad\x33", " FKX", 18}, // eth / Knoxstertoken - { 1, "\xf0\x4a\x8a\xc5\x53\xfc\xed\xb5\xba\x99\xa6\x47\x99\x15\x58\x26\xc1\x36\xb0\xbe", " FLIXX", 18}, // eth / FLIXX - { 1, "\x04\xcc\x78\x3b\x45\x0b\x8d\x11\xf3\xc7\xd0\x0d\xd0\x3f\xdf\x7f\xb5\x1f\xe9\xf2", " FLMC", 18}, // eth / Filmscoin - { 1, "\x59\x76\xf7\xda\xc1\x52\x5e\xf3\x27\x78\x36\x04\x3b\xa4\x74\xa3\x5e\x6b\x42\x72", " FLMC", 0}, // eth / Filmscoin - { 1, "\x3a\x1b\xda\x28\xad\xb5\xb0\xa8\x12\xa7\xcf\x10\xa1\x95\x0c\x92\x0f\x79\xbc\xd3", " FLP", 18}, // eth / FLIP Token - { 1, "\x9a\xef\xbe\x0b\x3c\x3b\xa9\xea\xb2\x62\xcb\x98\x56\xe8\x15\x7a\xb7\x64\x8e\x09", " FLR", 18}, // eth / Flair Coin - { 1, "\x95\x4b\x5d\xe0\x9a\x55\xe5\x97\x55\xac\xbd\xa2\x9e\x1e\xb7\x4a\x45\xd3\x01\x75", " FLUZ", 18}, // eth / Fluz Fluz Global - { 1, "\x70\xb1\x47\xe0\x1e\x92\x85\xe7\xce\x68\xb9\xba\x43\x7f\xe3\xa9\x19\x0e\x75\x6a", " FLX", 18}, // eth / BitFlux - { 1, "\x4d\xf4\x7b\x49\x69\xb2\x91\x1c\x96\x65\x06\xe3\x59\x2c\x41\x38\x94\x93\x95\x3b", " FND", 18}, // eth / FundRequest - { 1, "\x0a\xbe\xfb\x76\x11\xcb\x3a\x01\xea\x3f\xad\x85\xf3\x3c\x3c\x93\x4f\x8e\x2c\xf4", " FRD", 18}, // eth / FARAD Cryptoken - { 1, "\xe6\xf7\x4d\xcf\xa0\xe2\x08\x83\x00\x8d\x8c\x16\xb6\xd9\xa3\x29\x18\x9d\x0c\x30", " FTC", 2}, // eth / FTC - { 1, "\x20\x23\xdc\xf7\xc4\x38\xc8\xc8\xc0\xb0\xf2\x8d\xba\xe1\x55\x20\xb4\xf3\xee\x20", " FTR", 18}, // eth / Futourist Token - { 1, "\x2a\xec\x18\xc5\x50\x0f\x21\x35\x9c\xe1\xbe\xa5\xdc\x17\x77\x34\x4d\xf4\xc0\xdc", " FTT", 18}, // eth / FarmaTrust Token - { 1, "\x41\x87\x5c\x23\x32\xb0\x87\x7c\xdf\xaa\x69\x9b\x64\x14\x02\xb7\xd4\x64\x2c\x32", " FTXT", 8}, // eth / FUTURAX - { 1, "\x65\xbe\x44\xc7\x47\x98\x8f\xbf\x60\x62\x07\x69\x8c\x94\x4d\xf4\x44\x2e\xfe\x19", " FUCK", 4}, // eth / Finally Usable Crypto Karma - { 1, "\xab\x16\xe0\xd2\x5c\x06\xcb\x37\x62\x59\xcc\x18\xc1\xde\x4a\xca\x57\x60\x55\x89", " FUCK", 4}, // eth / FinallyUsableCryptoKarma - { 1, "\xea\x38\xea\xa3\xc8\x6c\x8f\x9b\x75\x15\x33\xba\x2e\x56\x2d\xeb\x9a\xcd\xed\x40", " FUEL", 18}, // eth / Etherparty FUEL - { 1, "\x41\x9d\x0d\x8b\xdd\x9a\xf5\xe6\x06\xae\x22\x32\xed\x28\x5a\xff\x19\x0e\x71\x1b", " FUN", 8}, // eth / Funfair - { 1, "\xc9\x2d\x6e\x3e\x64\x30\x2c\x59\xd7\x34\xf3\x29\x2e\x2a\x13\xa1\x3d\x7e\x18\x17", " FXC", 8}, // eth / FUTURAX - { 1, "\x88\xfc\xfb\xc2\x2c\x6d\x3d\xba\xa2\x5a\xf4\x78\xc5\x78\x97\x83\x39\xbd\xe7\x7a", " FYN", 18}, // eth / Fund Yourself Now - { 1, "\xf6\x74\x51\xdc\x84\x21\xf0\xe0\xaf\xeb\x52\xfa\xa8\x10\x10\x34\xed\x08\x1e\xd9", " GAM", 8}, // eth / Gambit - { 1, "\x67\x54\xe2\x1b\x9e\xaa\x05\x3c\x62\xd7\x85\x4d\xd6\x56\x1a\xe4\x51\xb0\xcb\xcf", " GANA", 18}, // eth / GANA - { 1, "\xc0\xea\x63\x06\xf6\x36\x0f\xe7\xdc\xab\x65\xd1\x6b\xf1\xa3\xaf\x92\xc7\x9a\xa2", " GANA", 18}, // eth / GANA - { 1, "\x70\x88\x76\xf4\x86\xe4\x48\xee\x89\xeb\x33\x2b\xfb\xc8\xe5\x93\x55\x30\x58\xb9", " GAVEL", 18}, // eth / GAVEL - { 1, "\x75\x85\xf8\x35\xae\x2d\x52\x27\x22\xd2\x68\x43\x23\xa0\xba\x83\x40\x1f\x32\xf5", " GBT", 18}, // eth / GBT - { 1, "\x12\xfc\xd6\x46\x3e\x66\x97\x4c\xf7\xbb\xc2\x4f\xfc\x4d\x40\xd6\xbe\x45\x82\x83", " GBX", 18}, // eth / Globitex - { 1, "\xdb\x0f\x69\x30\x6f\xf8\xf9\x49\xf2\x58\xe8\x3f\x6b\x87\xee\x5d\x05\x2d\x0b\x23", " GCP", 18}, // eth / Globcoin Crypto Platform - { 1, "\x4f\x4f\x0d\xb4\xde\x90\x3b\x88\xf2\xb1\xa2\x84\x79\x71\xe2\x31\xd5\x4f\x8f\xd3", " GEE", 8}, // eth / Geens NPO - { 1, "\x24\x08\x3b\xb3\x00\x72\x64\x3c\x3b\xb9\x0b\x44\xb7\x28\x58\x60\xa7\x55\xe6\x87", " GELD", 18}, // eth / GELD - { 1, "\x54\x3f\xf2\x27\xf6\x4a\xa1\x7e\xa1\x32\xbf\x98\x86\xca\xb5\xdb\x55\xdc\xad\xdf", " GEN", 18}, // eth / DAOstack - { 1, "\x8a\x85\x42\x88\xa5\x97\x60\x36\xa7\x25\x87\x91\x64\xca\x3e\x91\xd3\x0c\x6a\x1b", " GET", 18}, // eth / GET - { 1, "\xfc\xd8\x62\x98\x56\x28\xb2\x54\x06\x1f\x7a\x91\x80\x35\xb8\x03\x40\xd0\x45\xd3", " GIF", 18}, // eth / GIFcoin Token - { 1, "\xae\x4f\x56\xf0\x72\xc3\x4c\x0a\x65\xb3\xae\x3e\x4d\xb7\x97\xd8\x31\x43\x9d\x93", " GIM", 8}, // eth / Gimli - { 1, "\xb3\xbd\x49\xe2\x8f\x8f\x83\x2b\x8d\x1e\x24\x61\x06\x99\x1e\x54\x6c\x32\x35\x02", " GMT", 18}, // eth / GMT - { 1, "\x68\x10\xe7\x76\x88\x0c\x02\x93\x3d\x47\xdb\x1b\x9f\xc0\x59\x08\xe5\x38\x6b\x96", " GNO", 18}, // eth / Gnosis - { 1, "\xa7\x44\x76\x44\x31\x19\xa9\x42\xde\x49\x85\x90\xfe\x1f\x24\x54\xd7\xd4\xac\x0d", " GNT", 18}, // eth / Golem - { 1, "\xea\xb4\x31\x93\xcf\x06\x23\x07\x3c\xa8\x9d\xb9\xb7\x12\x79\x63\x56\xfa\x74\x14", " GOLDX", 18}, // eth / GOLDX - { 1, "\x12\xb1\x9d\x3e\x2c\xcc\x14\xda\x04\xfa\xe3\x3e\x63\x65\x2c\xe4\x69\xb3\xf2\xfd", " GRID", 12}, // eth / GRID - { 1, "\x0a\x9a\x9c\xe6\x00\xd0\x8b\xf9\xb7\x6f\x49\xfa\x4e\x7b\x38\xa6\x7e\xbe\xb1\xe6", " GROW", 8}, // eth / Growchain - { 1, "\xe5\x30\x44\x1f\x4f\x73\xbd\xb6\xdc\x2f\xa5\xaf\x7c\x3f\xc5\xfd\x55\x1e\xc8\x38", " GSE", 4}, // eth / GSENetwork - { 1, "\xb7\x08\x35\xd7\x82\x2e\xbb\x94\x26\xb5\x65\x43\xe3\x91\x84\x6c\x10\x7b\xd3\x2c", " GTC", 18}, // eth / GTC Token - { 1, "\x02\x5a\xba\xd9\xe5\x18\x51\x6f\xda\xaf\xbd\xcd\xb9\x70\x1b\x37\xfb\x7e\xf0\xfa", " GTKT", 0}, // eth / GTKT - { 1, "\xc5\xbb\xae\x50\x78\x1b\xe1\x66\x93\x06\xb9\xe0\x01\xef\xf5\x7a\x29\x57\xb0\x9d", " GTO", 5}, // eth / Gifto - { 1, "\x98\x47\x34\x5d\xe8\xb6\x14\xc9\x56\x14\x6b\xbe\xa5\x49\x33\x6d\x9c\x8d\x26\xb6", " GULD", 8}, // eth / GULD ERC20 - { 1, "\xf7\xb0\x98\x29\x8f\x7c\x69\xfc\x14\x61\x0b\xf7\x1d\x5e\x02\xc6\x07\x92\x89\x4c", " GUP", 3}, // eth / GUP - { 1, "\x10\x3c\x3a\x20\x9d\xa5\x9d\x3e\x7c\x4a\x89\x30\x7e\x66\x52\x1e\x08\x1c\xfd\xf0", " GVT", 18}, // eth / Genesis Vision - { 1, "\x58\xca\x30\x65\xc0\xf2\x4c\x7c\x96\xae\xe8\xd6\x05\x6b\x5b\x5d\xec\xf9\xc2\xf8", " GXC", 10}, // eth / GXC - { 1, "\x22\xf0\xaf\x8d\x78\x85\x1b\x72\xee\x79\x9e\x05\xf5\x4a\x77\x00\x15\x86\xb1\x8a", " GXVC", 10}, // eth / Genevieve VC - { 1, "\x8c\x65\xe9\x92\x29\x7d\x5f\x09\x2a\x75\x6d\xef\x24\xf4\x78\x1a\x28\x01\x98\xff", " GZE", 18}, // eth / GazeCoin - { 1, "\xe6\x38\xdc\x39\xb6\xad\xbe\xe8\x52\x6b\x5c\x22\x38\x0b\x4b\x45\xda\xf4\x6d\x8e", " GZR", 6}, // eth / Gizer - { 1, "\x5a\x56\x7e\x28\xdb\xfa\x2b\xbd\x3e\xf1\x3c\x0a\x01\xbe\x11\x47\x45\x34\x96\x57", " HAPPY", 2}, // eth / Happiness - { 1, "\x90\x02\xd4\x48\x5b\x75\x94\xe3\xe8\x50\xf0\xa2\x06\x71\x3b\x30\x51\x13\xf6\x9e", " HAT", 18}, // eth / Hawala Today - { 1, "\xc0\x11\xa7\x24\x00\xe5\x8e\xcd\x99\xee\x49\x7c\xf8\x9e\x37\x75\xd4\xbd\x73\x2f", " HAV", 18}, // eth / Havven - { 1, "\xff\xe8\x19\x6b\xc2\x59\xe8\xde\xdc\x54\x4d\x93\x57\x86\xaa\x47\x09\xec\x3e\x64", " HDG", 18}, // eth / Hedge Crypto - { 1, "\xe9\xff\x07\x80\x9c\xcf\xf0\x5d\xae\x74\x99\x0e\x25\x83\x1d\x0b\xc5\xcb\xe5\x75", " Hdp", 18}, // eth / HEdpAY - { 1, "\xba\x21\x84\x52\x0a\x1c\xc4\x9a\x61\x59\xc5\x7e\x61\xe1\x84\x4e\x08\x56\x15\xb6", " HGT", 8}, // eth / HGT - { 1, "\x9b\xb1\xdb\x14\x45\xb8\x32\x13\xa5\x6d\x90\xd3\x31\x89\x4b\x3f\x26\x21\x8e\x4e", " HIBT", 18}, // eth / HiBTC Token - { 1, "\xa9\x24\x0f\xbc\xac\x1f\x0b\x9a\x6a\xdf\xb0\x4a\x53\xc8\xe3\xb0\xcc\x1d\x14\x44", " HIG", 18}, // eth / ethereumhigh - { 1, "\x14\xf3\x7b\x57\x42\x42\xd3\x66\x55\x8d\xb6\x1f\x33\x35\x28\x9a\x50\x35\xc5\x06", " HKG", 3}, // eth / HKG - { 1, "\x88\xac\x94\xd5\xd1\x75\x13\x03\x47\xfc\x95\xe1\x09\xd7\x7a\xc0\x9d\xbf\x5a\xb7", " HKY", 18}, // eth / Hicky - { 1, "\xcb\xcc\x0f\x03\x6e\xd4\x78\x8f\x63\xfc\x0f\xee\x32\x87\x3d\x6a\x74\x87\xb9\x08", " HMQ", 8}, // eth / HMQ - { 1, "\xb4\x5d\x7b\xc4\xce\xbc\xab\x98\xad\x09\xba\xbd\xf8\xc8\x18\xb2\x29\x2b\x67\x2c", " HODL", 18}, // eth / HODLCoin - { 1, "\x5b\x07\x51\x71\x3b\x25\x27\xd7\xf0\x02\xc0\xc4\xe2\xa3\x7e\x12\x19\x61\x0a\x6b", " HORSE", 18}, // eth / HORSE - { 1, "\x6c\x6e\xe5\xe3\x1d\x82\x8d\xe2\x41\x28\x2b\x96\x06\xc8\xe9\x8e\xa4\x85\x26\xe2", " HOT", 18}, // eth / HoloToken - { 1, "\x9a\xf8\x39\x68\x7f\x6c\x94\x54\x2a\xc5\xec\xe2\xe3\x17\xda\xae\x35\x54\x93\xa1", " HOT", 18}, // eth / Hydro Protocol - { 1, "\x55\x4c\x20\xb7\xc4\x86\xbe\xee\x43\x92\x77\xb4\x54\x0a\x43\x45\x66\xdc\x4c\x02", " HST", 18}, // eth / HST - { 1, "\xc0\xeb\x85\x28\x5d\x83\x21\x7c\xd7\xc8\x91\x70\x2b\xcb\xc0\xfc\x40\x1e\x2d\x9d", " HVN", 8}, // eth / Hive Project - { 1, "\xeb\xbd\xf3\x02\xc9\x40\xc6\xbf\xd4\x9c\x6b\x16\x5f\x45\x7f\xdb\x32\x46\x49\xbc", " HYDRO", 18}, // eth / Hydro - { 1, "\xc1\xe2\x09\x7d\x78\x8d\x33\x70\x1b\xa3\xcc\x27\x73\xbf\x67\x15\x5e\xc9\x3f\xc4", " IAD", 18}, // eth / IADOWR Coin - { 1, "\x5a\x84\x96\x9b\xb6\x63\xfb\x64\xf6\xd0\x15\xdc\xf9\xf6\x22\xae\xdc\x79\x67\x50", " ICE", 18}, // eth / ICE - { 1, "\x88\x86\x66\xca\x69\xe0\xf1\x78\xde\xd6\xd7\x5b\x57\x26\xce\xe9\x9a\x87\xd6\x98", " ICN", 18}, // eth / ICN - { 1, "\xa3\x3e\x72\x9b\xf4\xfd\xeb\x86\x8b\x53\x4e\x1f\x20\x52\x34\x63\xd9\xc4\x6b\xee", " ICO", 10}, // eth / ICO - { 1, "\x01\x4b\x50\x46\x65\x90\x34\x0d\x41\x30\x7c\xc5\x4d\xce\xe9\x90\xc8\xd5\x8a\xa8", " ICOS", 6}, // eth / ICOS - { 1, "\xb5\xa5\xf2\x26\x94\x35\x2c\x15\xb0\x03\x23\x84\x4a\xd5\x45\xab\xb2\xb1\x10\x28", " ICX", 18}, // eth / ICON - { 1, "\x81\x4c\xaf\xd4\x78\x2d\x2e\x72\x81\x70\xfd\xa6\x82\x57\x98\x3f\x03\x32\x1c\x58", " IDEA", 0}, // eth / IDEA Token - { 1, "\x76\x54\x91\x5a\x1b\x82\xd6\xd2\xd0\xaf\xc3\x7c\x52\xaf\x55\x6e\xa8\x98\x3c\x7e", " IFT", 18}, // eth / InvestFeed - { 1, "\x16\x66\x2f\x73\xdf\x3e\x79\xe5\x4c\x6c\x59\x38\xb4\x31\x3f\x92\xc5\x24\xc1\x20", " IIC", 18}, // eth / IIC - { 1, "\x88\xae\x96\x84\x5e\x15\x75\x58\xef\x59\xe9\xff\x90\xe7\x66\xe2\x2e\x48\x03\x90", " IKB", 0}, // eth / IKB - { 1, "\xe3\x83\x1c\x5a\x98\x2b\x27\x9a\x19\x84\x56\xd5\x77\xcf\xb9\x04\x24\xcb\x63\x40", " IMC", 6}, // eth / Immune Coin - { 1, "\x22\xe5\xf6\x2d\x0f\xa1\x99\x74\x74\x9f\xaa\x19\x4e\x3d\x3e\xf6\xd8\x9c\x08\xd7", " IMT", 0}, // eth / IMT - { 1, "\xf8\xe3\x86\xed\xa8\x57\x48\x4f\x5a\x12\xe4\xb5\xda\xa9\x98\x4e\x06\xe7\x37\x05", " IND", 18}, // eth / Indorse - { 1, "\x48\xe5\x41\x3b\x73\xad\xd2\x43\x4e\x47\x50\x4e\x2a\x22\xd1\x49\x40\xdb\xfe\x78", " INRM", 3}, // eth / Integrated Money - { 1, "\x5b\x2e\x4a\x70\x0d\xfb\xc5\x60\x06\x1e\x95\x7e\xde\xc8\xf6\xee\xeb\x74\xa3\x20", " INS", 10}, // eth / INS - { 1, "\xc7\x2f\xe8\xe3\xdd\x5b\xef\x0f\x9f\x31\xf2\x59\x39\x9f\x30\x12\x72\xef\x2a\x2d", " INSTAR", 18}, // eth / Insights Network - { 1, "\xa8\x00\x6c\x4c\xa5\x6f\x24\xd6\x83\x67\x27\xd1\x06\x34\x93\x20\xdb\x7f\xef\x82", " INXT", 8}, // eth / Internxt - { 1, "\xfa\x1a\x85\x6c\xfa\x34\x09\xcf\xa1\x45\xfa\x4e\x20\xeb\x27\x0d\xf3\xeb\x21\xab", " IOST", 18}, // eth / IOSToken - { 1, "\xc3\x4b\x21\xf6\xf8\xe5\x1c\xc9\x65\xc2\x39\x3b\x3c\xcf\xa3\xb8\x2b\xeb\x24\x03", " IoT", 6}, // eth / IoTコイン - { 1, "\x6f\xb3\xe0\xa2\x17\x40\x7e\xff\xf7\xca\x06\x2d\x46\xc2\x6e\x5d\x60\xa1\x4d\x69", " IOTX", 18}, // eth / IoTeX Network - { 1, "\x64\xcd\xf8\x19\xd3\xe7\x5a\xc8\xec\x21\x7b\x34\x96\xd7\xce\x16\x7b\xe4\x2e\x80", " IPL", 18}, // eth / InsurePal token - { 1, "\x00\x1f\x0a\xa5\xda\x15\x58\x5e\x5b\x23\x05\xdb\xab\x2b\xac\x42\x5e\xa7\x10\x07", " IPSX", 18}, // eth / IPSX - { 1, "\x0d\xb8\xd8\xb7\x6b\xc3\x61\xba\xcb\xb7\x2e\x2c\x49\x1e\x06\x08\x5a\x97\xab\x31", " IQN", 18}, // eth / IQeon - { 1, "\x0c\xf7\x13\xb1\x1c\x9b\x98\x6e\xc4\x0d\x65\xbd\x4f\x7f\xbd\x50\xf6\xff\x2d\x64", " IST34", 18}, // eth / IST34 Token - { 1, "\x5e\x6b\x6d\x9a\xba\xd9\x09\x3f\xdc\x86\x1e\xa1\x60\x0e\xba\x1b\x35\x5c\xd9\x40", " ITC", 18}, // eth / IoT Chain - { 1, "\x0a\xef\x06\xdc\xcc\xc5\x31\xe5\x81\xf0\x44\x00\x59\xe6\xff\xcc\x20\x60\x39\xee", " ITT", 8}, // eth / ITT Token - { 1, "\xfc\xa4\x79\x62\xd4\x5a\xdf\xdf\xd1\xab\x2d\x97\x23\x15\xdb\x4c\xe7\xcc\xf0\x94", " IXT", 8}, // eth / InsureX - { 1, "\x0d\x26\x2e\x5d\xc4\xa0\x6a\x0f\x1c\x90\xce\x79\xc7\xa6\x0c\x09\xdf\xc8\x84\xe4", " J8T", 8}, // eth / J8T Token - { 1, "\x0a\xaf\x56\x1e\xff\x5b\xd9\xc8\xf9\x11\x61\x69\x33\xf8\x41\x66\xa1\x7c\xfe\x0c", " JBX", 0}, // eth / JBX - { 1, "\x88\x4e\x39\x02\xc4\xd5\xcf\xa8\x6d\xe4\xac\xe7\xa9\x6a\xa9\x1e\xbc\x25\xc0\xff", " JBX", 18}, // eth / JBOX - { 1, "\x87\x27\xc1\x12\xc7\x12\xc4\xa0\x33\x71\xac\x87\xa7\x4d\xd6\xab\x10\x4a\xf7\x68", " JET", 18}, // eth / JET - { 1, "\x77\x34\x50\x33\x5e\xd4\xec\x3d\xb4\x5a\xf7\x4f\x34\xf2\xc8\x53\x48\x64\x5d\x39", " JetCoins", 18}, // eth / JetCoins - { 1, "\xa5\xfd\x1a\x79\x1c\x4d\xfc\xaa\xcc\x96\x3d\x4f\x73\xc6\xae\x58\x24\x14\x9e\xa7", " JNT", 18}, // eth / JNT - { 1, "\xdd\xe1\x2a\x12\xa6\xf6\x71\x56\xe0\xda\x67\x2b\xe0\x5c\x37\x4e\x1b\x0a\x3e\x57", " JOY", 6}, // eth / JOYSO - { 1, "\x0d\x6d\xd9\xf6\x8d\x24\xec\x1d\x5f\xe2\x17\x4f\x3e\xc8\xda\xb5\x2b\x52\xba\xf5", " KC", 18}, // eth / KMCC - { 1, "\x72\xd3\x2a\xc1\xc5\xe6\x6b\xfc\x5b\x08\x80\x62\x71\xf8\xee\xf9\x15\x54\x51\x64", " KEE", 0}, // eth / CryptoKEE - { 1, "\x4c\xc1\x93\x56\xf2\xd3\x73\x38\xb9\x80\x2a\xa8\xe8\xfc\x58\xb0\x37\x32\x96\xe7", " KEY", 18}, // eth / SelfKey - { 1, "\x4c\xd9\x88\xaf\xba\xd3\x72\x89\xba\xaf\x53\xc1\x3e\x98\xe2\xbd\x46\xaa\xea\x8c", " KEY", 18}, // eth / BihuKey - { 1, "\x27\x69\x5e\x09\x14\x9a\xdc\x73\x8a\x97\x8e\x9a\x67\x8f\x99\xe4\xc3\x9e\x9e\xb9", " KICK", 8}, // eth / KICK - { 1, "\x81\x8f\xc6\xc2\xec\x59\x86\xbc\x6e\x2c\xbf\x00\x93\x9d\x90\x55\x6a\xb1\x2c\xe5", " KIN", 18}, // eth / Kin Foundation - { 1, "\xdd\x97\x4d\x5c\x2e\x29\x28\xde\xa5\xf7\x1b\x98\x25\xb8\xb6\x46\x68\x6b\xd2\x00", " KNC", 18}, // eth / Kyber Network - { 1, "\xb5\xc3\x3f\x96\x5c\x88\x99\xd2\x55\xc3\x4c\xdd\x2a\x3e\xfa\x8a\xbc\xbb\x3d\xea", " KPR", 18}, // eth / KPRCoin - { 1, "\x46\x4e\xbe\x77\xc2\x93\xe4\x73\xb4\x8c\xfe\x96\xdd\xcf\x88\xfc\xf7\xbf\xda\xc0", " KRL", 18}, // eth / Kryll - { 1, "\x95\x41\xfd\x8b\x9b\x5f\xa9\x73\x81\x78\x37\x83\xce\xbf\x2f\x5f\xa7\x93\xc2\x62", " KZN", 8}, // eth / KaizenCoin - { 1, "\xe5\x03\x65\xf5\xd6\x79\xcb\x98\xa1\xdd\x62\xd6\xf6\xe5\x8e\x59\x32\x1b\xcd\xdf", " LA", 18}, // eth / LATOKEN - { 1, "\xfd\x10\x7b\x47\x3a\xb9\x0e\x8f\xbd\x89\x87\x21\x44\xa3\xdc\x92\xc4\x0f\xa8\xc9", " LALA", 18}, // eth / LALA World Token - { 1, "\x51\x02\x79\x1c\xa0\x2f\xc3\x59\x53\x98\x40\x0b\xfe\x0e\x33\xd7\xb6\xc8\x22\x67", " LDC", 18}, // eth / LEADCOIN - { 1, "\xd6\xe3\x54\xf0\x73\x19\xe2\x47\x44\x91\xd8\xc7\xc7\x12\x13\x7b\xee\x68\x62\xa2", " LEMO", 0}, // eth / Lemo - { 1, "\x60\xc2\x44\x07\xd0\x17\x82\xc2\x17\x5d\x32\xfe\x7c\x89\x21\xed\x73\x23\x71\xd1", " LEMO", 18}, // eth / Lemo - { 1, "\xb5\xae\x84\x8e\xdb\x29\x6c\x21\x25\x9b\x74\x67\x33\x14\x67\xd2\x64\x7e\xec\xdf", " LEMO", 18}, // eth / Lemo - { 1, "\x80\xfb\x78\x4b\x7e\xd6\x67\x30\xe8\xb1\xdb\xd9\x82\x0a\xfd\x29\x93\x1a\xab\x03", " LEND", 18}, // eth / EHTLend - { 1, "\xc7\x98\xcd\x1c\x49\xdb\x0e\x29\x73\x12\xe4\xc6\x82\x75\x26\x68\xce\x1d\xb2\xad", " LFR", 5}, // eth / LifeRun Coin - { 1, "\x12\x3a\xb1\x95\xdd\x38\xb1\xb4\x05\x10\xd4\x67\xa6\xa3\x59\xb2\x01\xaf\x05\x6f", " LGO", 8}, // eth / LGO - { 1, "\x2e\xb8\x6e\x8f\xc5\x20\xe0\xf6\xbb\x5d\x9a\xf0\x8f\x92\x4f\xe7\x05\x58\xab\x89", " LGR", 8}, // eth / Logarithm - { 1, "\xeb\x99\x51\x02\x16\x98\xb4\x2e\x43\x99\xf9\xcb\xb6\x26\x7a\xa3\x5f\x82\xd5\x9d", " LIF", 18}, // eth / LIF - { 1, "\xff\x18\xdb\xc4\x87\xb4\xc2\xe3\x22\x2d\x11\x59\x52\xba\xbf\xda\x8b\xa5\x2f\x5f", " LIFE", 18}, // eth / LIFE - { 1, "\x51\x49\x10\x77\x1a\xf9\xca\x65\x6a\xf8\x40\xdf\xf8\x3e\x82\x64\xec\xf9\x86\xca", " LINK (Chainlink)", 18}, // eth / LINK Chainlink - { 1, "\xe2\xe6\xd4\xbe\x08\x6c\x69\x38\xb5\x3b\x22\x14\x48\x55\xee\xf6\x74\x28\x16\x39", " LINK Platform", 18}, // eth / Link Platform - { 1, "\x24\xa7\x7c\x1f\x17\xc5\x47\x10\x5e\x14\x81\x3e\x51\x7b\xe0\x6b\x00\x40\xaa\x76", " LIVE", 18}, // eth / LIVE Token - { 1, "\x63\xe6\x34\x33\x0a\x20\x15\x0d\xbb\x61\xb1\x56\x48\xbc\x73\x85\x5d\x6c\xcf\x07", " LNC", 18}, // eth / Lancer Token - { 1, "\x6b\xeb\x41\x8f\xc6\xe1\x95\x82\x04\xac\x8b\xad\xdc\xf1\x09\xb8\xe9\x69\x49\x66", " LNC (Linker Coin)", 18}, // eth / Linker Coin - { 1, "\x09\x47\xb0\xe6\xd8\x21\x37\x88\x05\xc9\x59\x82\x91\x38\x5c\xe7\xc7\x91\xa6\xb2", " LND", 18}, // eth / Lendingblock - { 1, "\x5e\x33\x46\x44\x40\x10\x13\x53\x22\x26\x8a\x46\x30\xd2\xed\x5f\x8d\x09\x44\x6c", " LOC", 18}, // eth / LockChain - { 1, "\x9c\x23\xd6\x7a\xea\x7b\x95\xd8\x09\x42\xe3\x83\x6b\xcd\xf7\xe7\x08\xa7\x47\xc2", " LOCI", 18}, // eth / LOCIcoin - { 1, "\xc6\x45\x00\xdd\x7b\x0f\x17\x94\x80\x7e\x67\x80\x2f\x8a\xbb\xf5\xf8\xff\xb0\x54", " LOCUS", 18}, // eth / Locus Chain - { 1, "\x21\xae\x23\xb8\x82\xa3\x40\xa2\x22\x82\x16\x20\x86\xbc\x98\xd3\xe2\xb7\x30\x18", " LOK", 18}, // eth / LOK - { 1, "\x25\x3c\x7d\xd0\x74\xf4\xba\xcb\x30\x53\x87\xf9\x22\x22\x5a\x4f\x73\x7c\x08\xbd", " LOOK", 18}, // eth / LookRev - { 1, "\xa4\xe8\xc3\xec\x45\x61\x07\xea\x67\xd3\x07\x5b\xf9\xe3\xdf\x3a\x75\x82\x3d\xb0", " LOOM", 18}, // eth / LOOM - { 1, "\x5a\x27\x6a\xeb\x77\xbc\xfd\xac\x8a\xc6\xf3\x1b\xbc\x74\x16\xae\x1a\x85\xee\xf2", " LOVE", 0}, // eth / Love - { 1, "\x58\xb6\xa8\xa3\x30\x23\x69\xda\xec\x38\x33\x34\x67\x24\x04\xee\x73\x3a\xb2\x39", " LPT", 18}, // eth / Livepeer Token - { 1, "\xef\x68\xe7\xc6\x94\xf4\x0c\x82\x02\x82\x1e\xdf\x52\x5d\xe3\x78\x24\x58\x63\x9f", " LRC", 18}, // eth / LRC - { 1, "\x5d\xbe\x29\x6f\x97\xb2\x3c\x4a\x6a\xa6\x18\x3d\x73\xe5\x74\xd0\x2b\xa5\xc7\x19", " LUC", 18}, // eth / LUCToken - { 1, "\xfb\x12\xe3\xcc\xa9\x83\xb9\xf5\x9d\x90\x91\x2f\xd1\x7f\x8d\x74\x5a\x8b\x29\x53", " LUCK", 0}, // eth / LUCK - { 1, "\xa8\x9b\x59\x34\x86\x34\x47\xf6\xe4\xfc\x53\xb3\x15\xa9\x3e\x87\x3b\xda\x69\xa3", " LUM", 18}, // eth / Lumino Coin - { 1, "\xfa\x05\xa7\x3f\xfe\x78\xef\x8f\x1a\x73\x94\x73\xe4\x62\xc5\x4b\xae\x65\x67\xd9", " LUN", 18}, // eth / LUN - { 1, "\xdd\x41\xfb\xd1\xae\x95\xc5\xd9\xb1\x98\x17\x4a\x28\xe0\x4b\xe6\xb3\xd1\xaa\x27", " LYS", 8}, // eth / Lightyears - { 1, "\x3f\x4b\x72\x66\x68\xda\x46\xf5\xe0\xe7\x5a\xa5\xd4\x78\xac\xec\x9f\x38\x21\x0f", " M-ETH", 18}, // eth / M-ETH - { 1, "\x5b\x09\xa0\x37\x1c\x1d\xa4\x4a\x8e\x24\xd3\x6b\xf5\xde\xb1\x14\x1a\x84\xd8\x75", " MAD", 18}, // eth / MAD - { 1, "\xe2\x5b\xce\xc5\xd3\x80\x1c\xe3\xa7\x94\x07\x9b\xf9\x4a\xdf\x1b\x8c\xcd\x80\x2d", " MAN", 18}, // eth / MAN - { 1, "\x0f\x5d\x2f\xb2\x9f\xb7\xd3\xcf\xee\x44\x4a\x20\x02\x98\xf4\x68\x90\x8c\xc9\x42", " MANA", 18}, // eth / Decentraland MANA - { 1, "\xfd\xcc\x07\xab\x60\x66\x0d\xe5\x33\xb5\xad\x26\xe1\x45\x7b\x56\x5a\x9d\x59\xbd", " MART", 18}, // eth / Martcoin - { 1, "\x38\x64\x67\xf1\xf3\xdd\xbe\x83\x24\x48\x65\x04\x18\x31\x1a\x47\x9e\xec\xfc\x57", " MBRS", 0}, // eth / Embers - { 1, "\x93\xe6\x82\x10\x7d\x1e\x9d\xef\xb0\xb5\xee\x70\x1c\x71\x70\x7a\x4b\x2e\x46\xbc", " MCAP", 8}, // eth / MCAP - { 1, "\x13\x8a\x87\x52\x09\x3f\x4f\x9a\x79\xaa\xed\xf4\x8d\x4b\x92\x48\xfa\xb9\x3c\x9c", " MCI", 18}, // eth / Musiconomi - { 1, "\xb6\x3b\x60\x6a\xc8\x10\xa5\x2c\xca\x15\xe4\x4b\xb6\x30\xfd\x42\xd8\xd1\xd8\x3d", " MCO", 8}, // eth / MCO - { 1, "\x51\xdb\x5a\xd3\x5c\x67\x1a\x87\x20\x7d\x88\xfc\x11\xd5\x93\xac\x0c\x84\x15\xbd", " MDA", 18}, // eth / MDA - { 1, "\x01\xf2\xac\xf2\x91\x48\x60\x33\x1c\x1c\xb1\xa9\xac\xec\xda\x74\x75\xe0\x6a\xf8", " MESH", 18}, // eth / Meshbox - { 1, "\x5b\x8d\x43\xff\xde\x4a\x29\x82\xb9\xa5\x38\x7c\xdf\x21\xd5\x4e\xad\x64\xac\x8d", " MEST", 18}, // eth / Monaco Estate - { 1, "\x67\x10\xc6\x34\x32\xa2\xde\x02\x95\x4f\xc0\xf8\x51\xdb\x07\x14\x6a\x6c\x03\x12", " MFG", 18}, // eth / SyncFab Smart Manufacturing Blockchain - { 1, "\xdf\x2c\x72\x38\x19\x8a\xd8\xb3\x89\x66\x65\x74\xf2\xd8\xbc\x41\x1a\x4b\x74\x28", " MFT", 18}, // eth / Mainframe Token - { 1, "\x05\xd4\x12\xce\x18\xf2\x40\x40\xbb\x3f\xa4\x5c\xf2\xc6\x9e\x50\x65\x86\xd8\xe8", " MFTU", 18}, // eth / Mainstream For The Underground - { 1, "\x40\x39\x50\x44\xac\x3c\x0c\x57\x05\x19\x06\xda\x93\x8b\x54\xbd\x65\x57\xf2\x12", " MGO", 8}, // eth / MGO - { 1, "\xe2\x3c\xd1\x60\x76\x1f\x63\xfc\x3a\x1c\xf7\x8a\xa0\x34\xb6\xcd\xf9\x7d\x3e\x0c", " MIT", 18}, // eth / MIT - { 1, "\xad\x8d\xd4\xc7\x25\xde\x1d\x31\xb9\xe8\xf8\xd1\x46\x08\x9e\x9d\xc6\x88\x20\x93", " MIT (Mychatcoin)", 6}, // eth / Mychatcoin - { 1, "\x9f\x8f\x72\xaa\x93\x04\xc8\xb5\x93\xd5\x55\xf1\x2e\xf6\x58\x9c\xc3\xa5\x79\xa2", " MKR", 18}, // eth / MakerDAO - { 1, "\x79\x39\x88\x2b\x54\xfc\xf0\xbc\xae\x6b\x53\xde\xc3\x9a\xd6\xe8\x06\x17\x64\x42", " MKT", 8}, // eth / Mikado - { 1, "\xbe\xb9\xef\x51\x4a\x37\x9b\x99\x7e\x07\x98\xfd\xcc\x90\x1e\xe4\x74\xb6\xd9\xa1", " MLN", 18}, // eth / Melonport - { 1, "\x1a\x95\xb2\x71\xb0\x53\x5d\x15\xfa\x49\x93\x2d\xab\xa3\x1b\xa6\x12\xb5\x29\x46", " MNE", 8}, // eth / MNE - { 1, "\xa9\x87\x7b\x1e\x05\xd0\x35\x89\x91\x31\xdb\xd1\xe4\x03\x82\x51\x66\xd0\x9f\x92", " MNT", 18}, // eth / Media Network Token - { 1, "\x83\xce\xe9\xe0\x86\xa7\x7e\x49\x2e\xe0\xbb\x93\xc2\xb0\x43\x7a\xd6\xfd\xec\xcc", " MNTP", 18}, // eth / Goldmint MNT Prelaunch Token - { 1, "\x95\x7c\x30\xab\x04\x26\xe0\xc9\x3c\xd8\x24\x1e\x2c\x60\x39\x2d\x08\xc6\xac\x8e", " MOD", 0}, // eth / Modum - { 1, "\x82\x12\x5a\xfe\x01\x81\x9d\xff\x15\x35\xd0\xd6\x27\x6d\x57\x04\x52\x91\xb6\xc0", " MRL", 18}, // eth / Marcelo - { 1, "\x21\xf0\xf0\xfd\x31\x41\xee\x9e\x11\xb3\xd7\xf1\x3a\x10\x28\xcd\x51\x5f\x45\x9c", " MRP", 18}, // eth / MoneyRebel Token - { 1, "\xab\x6c\xf8\x7a\x50\xf1\x7d\x7f\x5e\x1f\xea\xf8\x1b\x6f\xe9\xff\xbe\x8e\xbf\x84", " MRV", 18}, // eth / MRV - { 1, "\x68\xaa\x3f\x23\x2d\xa9\xbd\xc2\x34\x34\x65\x54\x57\x94\xef\x3e\xea\x52\x09\xbd", " MSP", 18}, // eth / Mothership - { 1, "\x90\x5e\x33\x7c\x6c\x86\x45\x26\x3d\x35\x21\x20\x5a\xa3\x7b\xf4\xd0\x34\xe7\x45", " MTC", 18}, // eth / Medical Token Currency - { 1, "\xdf\xdc\x0d\x82\xd9\x6f\x8f\xd4\x0c\xa0\xcf\xb4\xa2\x88\x95\x5b\xec\xec\x20\x88", " MTC", 18}, // eth / MTC Mesh Network - { 1, "\xaf\x4d\xce\x16\xda\x28\x77\xf8\xc9\xe0\x05\x44\xc9\x3b\x62\xac\x40\x63\x1f\x16", " MTH", 5}, // eth / Monetha - { 1, "\xf4\x33\x08\x93\x66\x89\x9d\x83\xa9\xf2\x6a\x77\x3d\x59\xec\x7e\xcf\x30\x35\x5e", " MTL", 8}, // eth / MetalPay - { 1, "\x41\xdb\xec\xc1\xcd\xc5\x51\x7c\x6f\x76\xf6\xa6\xe8\x36\xad\xbe\xe2\x75\x4d\xe3", " MTN", 18}, // eth / MedToken - { 1, "\x7f\xc4\x08\x01\x11\x65\x76\x0e\xe3\x1b\xe2\xbf\x20\xda\xf4\x50\x35\x66\x92\xaf", " MTR", 8}, // eth / Mitrav - { 1, "\x1e\x49\xff\x77\xc3\x55\xa3\xe3\x8d\x66\x51\xce\x84\x04\xaf\x0e\x48\xc5\x39\x5f", " MTRc", 18}, // eth / MTRCToken - { 1, "\x0a\xf4\x4e\x27\x84\x63\x72\x18\xdd\x1d\x32\xa3\x22\xd4\x4e\x60\x3a\x8f\x0c\x6a", " MTX", 18}, // eth / MTX - { 1, "\x51\x56\x69\xd3\x08\xf8\x87\xfd\x83\xa4\x71\xc7\x76\x4f\x5d\x08\x48\x86\xd3\x4d", " MUXE", 18}, // eth / MUXE - { 1, "\x8a\x77\xe4\x09\x36\xbb\xc2\x7e\x80\xe9\xa3\xf5\x26\x36\x8c\x96\x78\x69\xc8\x6d", " MVP", 18}, // eth / Merculet - { 1, "\x64\x25\xc6\xbe\x90\x2d\x69\x2a\xe2\xdb\x75\x2b\x3c\x26\x8a\xfa\xdb\x09\x9d\x3b", " MWAT", 18}, // eth / RED MWAT - { 1, "\xf7\xe9\x83\x78\x16\x09\x01\x23\x07\xf2\x51\x4f\x63\xd5\x26\xd8\x3d\x24\xf4\x66", " MYD", 16}, // eth / MYD - { 1, "\xa6\x45\x26\x4c\x56\x03\xe9\x6c\x3b\x0b\x07\x8c\xda\xb6\x87\x33\x79\x4b\x0a\x71", " MYST", 8}, // eth / Mysterium - { 1, "\x8d\x80\xde\x8a\x78\x19\x83\x96\x32\x9d\xfa\x76\x9a\xd5\x4d\x24\xbf\x90\xe7\xaa", " NAC", 18}, // eth / Nami ICO - { 1, "\xff\xe0\x2e\xe4\xc6\x9e\xdf\x1b\x34\x0f\xca\xd6\x4f\xbd\x6b\x37\xa7\xb9\xe2\x65", " NANJ", 8}, // eth / NANJCOIN - { 1, "\x58\x80\x47\x36\x5d\xf5\xba\x58\x9f\x92\x36\x04\xaa\xc2\x3d\x67\x35\x55\xc6\x23", " NAVI", 18}, // eth / NaviToken - { 1, "\x17\xf8\xaf\xb6\x3d\xfc\xdc\xc9\x0e\xbe\x6e\x84\xf0\x60\xcc\x30\x6a\x98\x25\x7d", " NBAI", 18}, // eth / NebulaAiToken - { 1, "\x80\x98\x26\xcc\xea\xb6\x8c\x38\x77\x26\xaf\x96\x27\x13\xb6\x4c\xb5\xcb\x3c\xca", " nCash", 18}, // eth / NucleusVision - { 1, "\x9e\x46\xa3\x8f\x5d\xaa\xbe\x86\x83\xe1\x07\x93\xb0\x67\x49\xee\xf7\xd7\x33\xd1", " NCT", 18}, // eth / Nectar - { 1, "\xa5\x4d\xdc\x7b\x3c\xce\x7f\xc8\xb1\xe3\xfa\x02\x56\xd0\xdb\x80\xd2\xc1\x09\x70", " NDC", 18}, // eth / Neverdie - { 1, "\xcc\x80\xc0\x51\x05\x7b\x77\x4c\xd7\x50\x67\xdc\x48\xf8\x98\x7c\x4e\xb9\x7a\x5e", " NEC", 18}, // eth / Ethfinex Nectar Token - { 1, "\xcf\xb9\x86\x37\xbc\xae\x43\xc1\x33\x23\xea\xa1\x73\x1c\xed\x2b\x71\x69\x62\xfd", " NET", 18}, // eth / NIMIQ - { 1, "\xa8\x23\xe6\x72\x20\x06\xaf\xe9\x9e\x91\xc3\x0f\xf5\x29\x50\x52\xfe\x6b\x8e\x32", " NEU", 18}, // eth / NEU Fund - { 1, "\x72\xdd\x4b\x6b\xd8\x52\xa3\xaa\x17\x2b\xe4\xd6\xc5\xa6\xdb\xec\x58\x8c\xf1\x31", " NGC", 18}, // eth / NAGA Coin - { 1, "\xe2\x65\x17\xa9\x96\x72\x99\x45\x3d\x3f\x1b\x48\xaa\x00\x5e\x61\x27\xe6\x72\x10", " NIMFA", 18}, // eth / Ninfa Money - { 1, "\x17\x76\xe1\xf2\x6f\x98\xb1\xa5\xdf\x9c\xd3\x47\x95\x3a\x26\xdd\x3c\xb4\x66\x71", " NMR", 18}, // eth / NMR - { 1, "\x64\x3b\x68\x70\xbe\xab\xee\x94\x1b\x92\x60\xa0\xa8\x78\xbc\xf4\xa6\x1f\xb0\xf1", " NONE", 0}, // eth / None - { 1, "\xec\x46\xf8\x20\x7d\x76\x60\x12\x45\x4c\x40\x8d\xe2\x10\xbc\xbc\x22\x43\xe7\x1c", " NOX", 18}, // eth / NOX - { 1, "\x4c\xe6\xb3\x62\xbc\x77\xa2\x49\x66\xdd\xa9\x07\x8f\x9c\xef\x81\xb3\xb8\x86\xa7", " NPER", 18}, // eth / NPER - { 1, "\xa1\x5c\x7e\xbe\x1f\x07\xca\xf6\xbf\xf0\x97\xd8\xa5\x89\xfb\x8a\xc4\x9a\xe5\xb3", " NPXS", 18}, // eth / Pundi X Token - { 1, "\x24\x5e\xf4\x7d\x4d\x05\x05\xec\xf3\xac\x46\x3f\x4d\x81\xf4\x1a\xde\x8f\x1f\xd1", " NUG", 18}, // eth / Nuggets Token - { 1, "\xb9\x13\x18\xf3\x5b\xdb\x26\x2e\x94\x23\xbc\x7c\x7c\x2a\x3a\x93\xdd\x93\xc9\x2c", " NULS", 18}, // eth / NULS - { 1, "\x57\xab\x1e\x02\xfe\xe2\x37\x74\x58\x0c\x11\x97\x40\x12\x9e\xac\x70\x81\xe9\xd3", " nUSD", 18}, // eth / Havven-Backed USD Nomins (nUSD) - { 1, "\x45\xe4\x2d\x65\x9d\x9f\x94\x66\xcd\x5d\xf6\x22\x50\x60\x33\x14\x5a\x9b\x89\xbc", " NxC", 3}, // eth / Nexium - { 1, "\x76\x27\xde\x4b\x93\x26\x3a\x6a\x75\x70\xb8\xda\xfa\x64\xba\xe8\x12\xe5\xc3\x94", " NXX", 8}, // eth / NXX - { 1, "\x5c\x61\x83\xd1\x0a\x00\xcd\x74\x7a\x6d\xbb\x5f\x65\x8a\xd5\x14\x38\x3e\x94\x19", " NXX OLD", 8}, // eth / NXX OLD - { 1, "\x5e\x88\x8b\x83\xb7\x28\x7e\xed\x4f\xb7\xda\x7b\x7d\x0a\x0d\x4c\x73\x5d\x94\xb3", " OAK", 18}, // eth / OAK - { 1, "\x70\x1c\x24\x4b\x98\x8a\x51\x3c\x94\x59\x73\xde\xfa\x05\xde\x93\x3b\x23\xfe\x1d", " OAX", 18}, // eth / OAX - { 1, "\x02\x35\xfe\x62\x4e\x04\x4a\x05\xee\xd7\xa4\x3e\x16\xe3\x08\x3b\xc8\xa4\x28\x7a", " OCC", 18}, // eth / Original Crypto Coin - { 1, "\xbf\x52\xf2\xab\x39\xe2\x6e\x09\x51\xd2\xa0\x2b\x49\xb7\x70\x2a\xbe\x30\x40\x6a", " ODE", 18}, // eth / ODEM Token - { 1, "\x6f\x53\x9a\x94\x56\xa5\xbc\xb6\x33\x4a\x1a\x41\x20\x7c\x37\x88\xf5\x82\x52\x07", " OHNI", 18}, // eth / Ohni - { 1, "\x7f\x21\x76\xce\xb1\x6d\xcb\x64\x8d\xc9\x24\xef\xf6\x17\xc3\xdc\x2b\xef\xd3\x0d", " OHNI", 0}, // eth / OHNI - { 1, "\xbe\xef\x54\x6a\xc8\xa4\xe0\xa8\x0d\xc1\xe2\xd6\x96\x96\x8e\xf5\x41\x38\xf1\xd4", " OJX", 18}, // eth / Ojooo Coin - { 1, "\xc6\x6e\xa8\x02\x71\x7b\xfb\x98\x33\x40\x02\x64\xdd\x12\xc2\xbc\xea\xa3\x4a\x6d", " OLD_MKR", 18}, // eth / MakerDAO - { 1, "\x64\xa6\x04\x93\xd8\x88\x72\x8c\xf4\x26\x16\xe0\x34\xa0\xdf\xea\xe3\x8e\xfc\xf0", " OLT", 18}, // eth / OneLedger Token - { 1, "\xd2\x61\x14\xcd\x6e\xe2\x89\xac\xcf\x82\x35\x0c\x8d\x84\x87\xfe\xdb\x8a\x0c\x07", " OMG", 18}, // eth / OMG - { 1, "\x04\x71\x87\xe5\x34\x77\xbe\x70\xdb\xe8\xea\x5b\x79\x93\x18\xf2\xe1\x65\x05\x2f", " OMT", 18}, // eth / OTCMAKER Token - { 1, "\xb2\x3b\xe7\x35\x73\xbc\x7e\x03\xdb\x6e\x5d\xfc\x62\x40\x53\x68\x71\x6d\x28\xa8", " ONEK", 18}, // eth / One K Token - { 1, "\xd3\x41\xd1\x68\x0e\xee\xe3\x25\x5b\x8c\x4c\x75\xbc\xce\x7e\xb5\x7f\x14\x4d\xae", " onG", 18}, // eth / onG - { 1, "\x69\xc4\xbb\x24\x0c\xf0\x5d\x51\xee\xab\x69\x85\xba\xb3\x55\x27\xd0\x4a\x8c\x64", " OPEN", 8}, // eth / OPEN - { 1, "\xe9\xde\x1c\x63\x07\x53\xa1\x5d\x70\x21\xcc\x56\x34\x29\xc2\x1d\x48\x87\x50\x6f", " OPEN", 8}, // eth / OPEN - { 1, "\x43\x55\xfc\x16\x0f\x74\x32\x8f\x9b\x38\x3d\xf2\xec\x58\x9b\xb3\xdf\xd8\x2b\xa0", " OPT", 18}, // eth / Opus Foundation - { 1, "\xff\x56\xcc\x6b\x1e\x6d\xed\x34\x7a\xa0\xb7\x67\x6c\x85\xab\x0b\x3d\x08\xb0\xfa", " ORBS", 18}, // eth / Orbs - { 1, "\x6f\x59\xe0\x46\x1a\xe5\xe2\x79\x9f\x1f\xb3\x84\x7f\x05\xa6\x3b\x16\xd0\xdb\xf8", " ORCA", 18}, // eth / ORCA Token - { 1, "\x2c\x4e\x8f\x2d\x74\x61\x13\xd0\x69\x6c\xe8\x9b\x35\xf0\xd8\xbf\x88\xe0\xae\xca", " OST", 18}, // eth / Simple Token 'OST' - { 1, "\x17\x0b\x27\x5c\xed\x08\x9f\xff\xae\xbf\xe9\x27\xf4\x45\xa3\x50\xed\x91\x60\xdc", " OWN", 8}, // eth / OWNDATA - { 1, "\x65\xa1\x50\x14\x96\x4f\x21\x02\xff\x58\x64\x7e\x16\xa1\x6a\x6b\x9e\x14\xbc\xf6", " Ox Fina", 3}, // eth / Ox Fina - { 1, "\xfe\xda\xe5\x64\x26\x68\xf8\x63\x6a\x11\x98\x7f\xf3\x86\xbf\xd2\x15\xf9\x42\xee", " PAL", 18}, // eth / PolicyPal Network - { 1, "\xea\x5f\x88\xe5\x4d\x98\x2c\xbb\x0c\x44\x1c\xde\x4e\x79\xbc\x30\x5e\x5b\x43\xbc", " PARETO", 18}, // eth / PARETO - { 1, "\x77\x76\x1e\x63\xc0\x5a\xee\x66\x48\xfd\xae\xaa\x9b\x94\x24\x83\x51\xaf\x9b\xcd", " PASS", 18}, // eth / PASS Token - { 1, "\xbb\x1f\xa4\xfd\xeb\x34\x59\x73\x3b\xf6\x7e\xbc\x6f\x89\x30\x03\xfa\x97\x6a\x82", " PAT", 18}, // eth / Pangea Arbitration Token - { 1, "\x69\x44\x04\x59\x5e\x30\x75\xa9\x42\x39\x7f\x46\x6a\xac\xd4\x62\xff\x1a\x7b\xd0", " PATENTS", 18}, // eth / PATENTS - { 1, "\xf8\x13\xf3\x90\x2b\xbc\x00\xa6\xdc\xe3\x78\x63\x4d\x3b\x79\xd8\x4f\x98\x03\xd7", " PATH", 18}, // eth / PATH - { 1, "\xb9\x70\x48\x62\x8d\xb6\xb6\x61\xd4\xc2\xaa\x83\x3e\x95\xdb\xe1\xa9\x05\xb2\x80", " PAY", 18}, // eth / TenX - { 1, "\x55\x64\x8d\xe1\x98\x36\x33\x85\x49\x13\x0b\x1a\xf5\x87\xf1\x6b\xea\x46\xf6\x6b", " PBL", 18}, // eth / PBL - { 1, "\xf4\xc0\x7b\x18\x65\xbc\x32\x6a\x3c\x01\x33\x94\x92\xca\x75\x38\xfd\x03\x8c\xc0", " PBT", 4}, // eth / Primalbase Token (PBT) - { 1, "\xfc\xac\x7a\x75\x15\xe9\xa9\xd7\x61\x9f\xa7\x7a\x1f\xa7\x38\x11\x1f\x66\x72\x7e", " PCH", 18}, // eth / PITCH - { 1, "\x36\x18\x51\x6f\x45\xcd\x3c\x91\x3f\x81\xf9\x98\x7a\xf4\x10\x77\x93\x2b\xc4\x0d", " PCL", 8}, // eth / Peculium - { 1, "\x53\x14\x8b\xb4\x55\x17\x07\xed\xf5\x1a\x1e\x8d\x7a\x93\x69\x8d\x18\x93\x12\x25", " PCLOLD", 8}, // eth / PeculiumOLD - { 1, "\x8a\xe5\x6a\x68\x50\xa7\xcb\xea\xc3\xc3\xab\x2c\xb3\x11\xe7\x62\x01\x67\xea\xc8", " PEG", 18}, // eth / PEG Network Token - { 1, "\x58\x84\x96\x9e\xc0\x48\x05\x56\xe1\x1d\x11\x99\x80\x13\x6a\x4c\x17\xed\xde\xd1", " PET", 18}, // eth / PETHEREUM - { 1, "\xec\x18\xf8\x98\xb4\x07\x6a\x3e\x18\xf1\x08\x9d\x33\x37\x6c\xc3\x80\xbd\xe6\x1d", " PETRO", 18}, // eth / PETRO - { 1, "\x55\xc2\xa0\xc1\x71\xd9\x20\x84\x35\x60\x59\x4d\xe3\xd6\xee\xcc\x09\xef\xc0\x98", " PEXT", 4}, // eth / PEX-Token - { 1, "\xe6\x45\x09\xf0\xbf\x07\xce\x2d\x29\xa7\xef\x19\xa8\xa9\xbc\x06\x54\x77\xc1\xb4", " PIPL", 8}, // eth / PIPL Coin - { 1, "\x8e\xff\xd4\x94\xeb\x69\x8c\xc3\x99\xaf\x62\x31\xfc\xcd\x39\xe0\x8f\xd2\x0b\x15", " PIX", 0}, // eth / PIX - { 1, "\x59\x41\x6a\x25\x62\x8a\x76\xb4\x73\x0e\xc5\x14\x86\x11\x4c\x32\xe0\xb5\x82\xa1", " PLASMA", 6}, // eth / PLASMA - { 1, "\xe4\x77\x29\x2f\x1b\x32\x68\x68\x7a\x29\x37\x61\x16\xb0\xed\x27\xa9\xc7\x61\x70", " PLAY", 18}, // eth / HeroCoin - { 1, "\x0a\xff\xa0\x6e\x7f\xbe\x5b\xc9\xa7\x64\xc9\x79\xaa\x66\xe8\x25\x6a\x63\x1f\x02", " PLBT", 6}, // eth / Polybius - { 1, "\xe3\x81\x85\x04\xc1\xb3\x2b\xf1\x55\x7b\x16\xc2\x38\xb2\xe0\x1f\xd3\x14\x9c\x17", " PLR", 18}, // eth / Pillar Project - { 1, "\xe4\x3a\xc1\x71\x4f\x73\x94\x17\x3b\x15\xe7\xcf\xf3\x1a\x63\xd5\x23\xce\x4f\xb9", " PLS", 18}, // eth / DACPLAY Token - { 1, "\xd8\x91\x2c\x10\x68\x1d\x8b\x21\xfd\x37\x42\x24\x4f\x44\x65\x8d\xba\x12\x26\x4e", " PLU", 18}, // eth / Plutus - { 1, "\x0e\x09\x89\xb1\xf9\xb8\xa3\x89\x83\xc2\xba\x80\x53\x26\x9c\xa6\x2e\xc9\xb1\x95", " POE", 8}, // eth / Po.et Tokens - { 1, "\x43\xf6\xa1\xbe\x99\x2d\xee\x40\x87\x21\x74\x84\x90\x77\x2b\x15\x14\x3c\xe0\xa7", " POIN", 0}, // eth / Potatoin - { 1, "\x99\x92\xec\x3c\xf6\xa5\x5b\x00\x97\x8c\xdd\xf2\xb2\x7b\xc6\x88\x2d\x88\xd1\xec", " POLY", 18}, // eth / Polymath Network - { 1, "\x77\x9b\x7b\x71\x3c\x86\xe3\xe6\x77\x4f\x50\x40\xd9\xcc\xc2\xd4\x3a\xd3\x75\xf8", " POOL", 8}, // eth / Stake Pool - { 1, "\xee\x60\x9f\xe2\x92\x12\x8c\xad\x03\xb7\x86\xdb\xb9\xbc\x26\x34\xcc\xdb\xe7\xfc", " POS", 18}, // eth / PoSToken - { 1, "\x59\x58\x32\xf8\xfc\x6b\xf5\x9c\x85\xc5\x27\xfe\xc3\x74\x0a\x1b\x7a\x36\x12\x69", " POWR", 6}, // eth / PowerLedger - { 1, "\xc4\x22\x09\xac\xcc\x14\x02\x9c\x10\x12\xfb\x56\x80\xd9\x5f\xbd\x60\x36\xe2\xa0", " PPP", 18}, // eth / PayPie - { 1, "\xd4\xfa\x14\x60\xf5\x37\xbb\x90\x85\xd2\x2c\x7b\xcc\xb5\xdd\x45\x0e\xf2\x8e\x3a", " PPT", 8}, // eth / Populous - { 1, "\x88\xa3\xe4\xf3\x5d\x64\xaa\xd4\x1a\x6d\x40\x30\xac\x9a\xfe\x43\x56\xcb\x84\xfa", " PRE", 18}, // eth / Presearch - { 1, "\x77\x28\xdf\xef\x5a\xbd\x46\x86\x69\xeb\x7f\x9b\x48\xa7\xf7\x0a\x50\x1e\xd2\x9d", " PRG", 6}, // eth / PRG - { 1, "\x18\x44\xb2\x15\x93\x26\x26\x68\xb7\x24\x8d\x0f\x57\xa2\x20\xca\xab\xa4\x6a\xb9", " PRL", 18}, // eth / Oyster Pearl - { 1, "\x22\x6b\xb5\x99\xa1\x2c\x82\x64\x76\xe3\xa7\x71\x45\x46\x97\xea\x52\xe9\xe2\x20", " PRO", 8}, // eth / Propy - { 1, "\xa3\x14\x9e\x0f\xa0\x06\x1a\x90\x07\xfa\xf3\x07\x07\x4c\xdc\xd2\x90\xf0\xe2\xfd", " PRON", 8}, // eth / PronCoin - { 1, "\x76\x41\xb2\xca\x9d\xdd\x58\xad\xdf\x6e\x33\x81\xc1\xf9\x94\xaa\xc5\xf1\xa3\x2f", " PRPS", 18}, // eth / Purpose - { 1, "\xd9\x4f\x27\x78\xe2\xb3\x91\x3c\x53\x63\x7a\xe6\x06\x47\x59\x8b\xe5\x88\xc5\x70", " PRPS", 18}, // eth / Purpose - { 1, "\x16\x37\x33\xbc\xc2\x8d\xbf\x26\xb4\x1a\x8c\xfa\x83\xe3\x69\xb5\xb3\xaf\x74\x1b", " PRS", 18}, // eth / Persians - { 1, "\x0c\x04\xd4\xf3\x31\xda\x8d\xf7\x5f\x9e\x2e\x27\x1e\x3f\x3f\x14\x94\xc6\x6c\x36", " PRSP", 9}, // eth / PRSP - { 1, "\x66\x49\x7a\x28\x3e\x0a\x00\x7b\xa3\x97\x4e\x83\x77\x84\xc6\xae\x32\x34\x47\xde", " PT", 18}, // eth / PornToken - { 1, "\x2a\x8e\x98\xe2\x56\xf3\x22\x59\xb5\xe5\xcb\x55\xdd\x63\xc8\xe8\x91\x95\x06\x66", " PTC", 18}, // eth / ParrotCoin - { 1, "\x8a\xe4\xbf\x2c\x33\xa8\xe6\x67\xde\x34\xb5\x49\x38\xb0\xcc\xd0\x3e\xb8\xcc\x06", " PTOY", 8}, // eth / PTOY - { 1, "\x55\x12\xe1\xd6\xa7\xbe\x42\x4b\x43\x23\x12\x6b\x4f\x9e\x86\xd0\x23\xf9\x57\x64", " PTWO", 18}, // eth / PornTokenV2 - { 1, "\xef\x6b\x4c\xe8\xc9\xbc\x83\x74\x4f\xbc\xde\x26\x57\xb3\x2e\xc1\x87\x90\x45\x8a", " PUC", 0}, // eth / Pour Coin - { 1, "\xe2\x5f\xf6\xeb\x95\x9b\xce\x67\x97\x57\x78\xe4\x6a\x47\x75\x0c\x24\x3b\x6b\x99", " PURC", 18}, // eth / PureCarbon - { 1, "\xc1\x48\x30\xe5\x3a\xa3\x44\xe8\xc1\x46\x03\xa9\x12\x29\xa0\xb9\x25\xb0\xb2\x62", " PXT", 8}, // eth / Populous XBRL Token (PXT) - { 1, "\x61\x8e\x75\xac\x90\xb1\x2c\x60\x49\xba\x3b\x27\xf5\xd5\xf8\x65\x1b\x00\x37\xf6", " QASH", 6}, // eth / QASH - { 1, "\x67\x1a\xbb\xe5\xce\x65\x24\x91\x98\x53\x42\xe8\x54\x28\xeb\x1b\x07\xbc\x6c\x64", " QAU", 8}, // eth / QAU - { 1, "\x24\x67\xaa\x6b\x5a\x23\x51\x41\x6f\xd4\xc3\xde\xf8\x46\x2d\x84\x1f\xee\xec\xec", " QBX", 18}, // eth / qiibeeToken - { 1, "\x4a\x22\x0e\x60\x96\xb2\x5e\xad\xb8\x83\x58\xcb\x44\x06\x8a\x32\x48\x25\x46\x75", " QNT", 18}, // eth / Quant - { 1, "\xff\xaa\x5f\xfc\x45\x5d\x91\x31\xf8\xa2\x71\x3a\x74\x1f\xd1\x96\x03\x30\x50\x8b", " QRG", 18}, // eth / QRG - { 1, "\x69\x7b\xea\xc2\x8b\x09\xe1\x22\xc4\x33\x2d\x16\x39\x85\xe8\xa7\x31\x21\xb9\x7f", " QRL", 8}, // eth / QRL - { 1, "\x99\xea\x4d\xb9\xee\x77\xac\xd4\x0b\x11\x9b\xd1\xdc\x4e\x33\xe1\xc0\x70\xb8\x0d", " QSP", 18}, // eth / Quantstamp Token - { 1, "\x2c\x3c\x1f\x05\x18\x7d\xba\x7a\x5f\x2d\xd4\x7d\xca\x57\x28\x1c\x4d\x4f\x18\x3f", " QTQ", 18}, // eth / TiiQu's Q Token - { 1, "\x9a\x64\x2d\x6b\x33\x68\xdd\xc6\x62\xca\x24\x4b\xad\xf3\x2c\xda\x71\x60\x05\xbc", " QTUM", 18}, // eth / Qtum - { 1, "\x45\xed\xb5\x35\x94\x2a\x8c\x84\xd9\xf4\xb5\xd3\x7e\x1b\x25\xf9\x1e\xa4\x80\x4c", " RAO", 18}, // eth / RadioYo - { 1, "\xfc\x2c\x4d\x8f\x95\x00\x2c\x14\xed\x0a\x7a\xa6\x51\x02\xca\xc9\xe5\x95\x3b\x5e", " RBLX", 18}, // eth / Rublix - { 1, "\xf9\x70\xb8\xe3\x6e\x23\xf7\xfc\x3f\xd7\x52\xee\xa8\x6f\x8b\xe8\xd8\x33\x75\xa6", " RCN", 18}, // eth / Ripio Credit Network - { 1, "\x2a\x3a\xa9\xec\xa4\x1e\x72\x0e\xd4\x6b\x5a\x70\xd6\xc3\x7e\xfa\x47\xf7\x68\xac", " RCT", 18}, // eth / RCT - { 1, "\x25\x5a\xa6\xdf\x07\x54\x0c\xb5\xd3\xd2\x97\xf0\xd0\xd4\xd8\x4c\xb5\x2b\xc8\xe6", " RDN", 18}, // eth / Raiden Network - { 1, "\x76\x7b\xa2\x91\x5e\xc3\x44\x01\x5a\x79\x38\xe3\xee\xdf\xec\x27\x85\x19\x5d\x05", " REA", 18}, // eth / Realisto - { 1, "\x5f\x53\xf7\xa8\x07\x56\x14\xb6\x99\xba\xad\x0b\xc2\xc8\x99\xf4\xba\xd8\xfb\xbf", " REBL", 18}, // eth / Rebellious - { 1, "\x76\x96\x0d\xcc\xd5\xa1\xfe\x79\x9f\x7c\x29\xbe\x9f\x19\xce\xb4\x62\x7a\xeb\x2f", " RED", 18}, // eth / Red Community Token - { 1, "\xb5\x63\x30\x0a\x3b\xac\x79\xfc\x09\xb9\x3b\x6f\x84\xce\x0d\x44\x65\xa2\xac\x27", " REDC", 18}, // eth / RedCab - { 1, "\x40\x8e\x41\x87\x6c\xcc\xdc\x0f\x92\x21\x06\x00\xef\x50\x37\x26\x56\x05\x2a\x38", " REN", 18}, // eth / Republic Token - { 1, "\xe9\x43\x27\xd0\x7f\xc1\x79\x07\xb4\xdb\x78\x8e\x5a\xdf\x2e\xd4\x24\xad\xdf\xf6", " REP", 18}, // eth / Augur - { 1, "\x19\x85\x36\x5e\x9f\x78\x35\x9a\x9b\x6a\xd7\x60\xe3\x24\x12\xf4\xa4\x45\xe8\x62", " REP", 18}, // eth / Augur - { 1, "\x8f\x82\x21\xaf\xbb\x33\x99\x8d\x85\x84\xa2\xb0\x57\x49\xba\x73\xc3\x7a\x93\x8a", " REQ", 18}, // eth / Request Network - { 1, "\xf0\x5a\x93\x82\xa4\xc3\xf2\x9e\x27\x84\x50\x27\x54\x29\x3d\x88\xb8\x35\x10\x9c", " REX", 18}, // eth / REX - { 1, "\xd0\x92\x9d\x41\x19\x54\xc4\x74\x38\xdc\x1d\x87\x1d\xd6\x08\x1f\x5c\x5e\x14\x9c", " RFR", 4}, // eth / Refereum - { 1, "\x86\xe5\x6f\x3c\x89\xa1\x45\x28\x85\x8e\x58\xb3\xde\x48\xc0\x74\x53\x8b\xaf\x2c", " RING", 18}, // eth / Evolution Land Global Token - { 1, "\xdd\x00\x72\x78\xb6\x67\xf6\xbe\xf5\x2f\xd0\xa4\xc2\x36\x04\xaa\x1f\x96\x03\x9a", " RIPT", 8}, // eth / RiptideCoin - { 1, "\x60\x7f\x4c\x5b\xb6\x72\x23\x0e\x86\x72\x08\x55\x32\xf7\xe9\x01\x54\x4a\x73\x75", " RLC", 9}, // eth / IEx.ec - { 1, "\xcc\xed\x5b\x82\x88\x08\x6b\xe8\xc3\x8e\x23\x56\x7e\x68\x4c\x37\x40\xbe\x4d\x48", " RLT", 10}, // eth / RLT - { 1, "\xbe\x99\xb0\x97\x09\xfc\x75\x3b\x09\xbc\xf5\x57\xa9\x92\xf6\x60\x5d\x59\x97\xb0", " RLTY", 8}, // eth / SMARTRealty - { 1, "\x4a\x42\xd2\xc5\x80\xf8\x3d\xce\x40\x4a\xca\xd1\x8d\xab\x26\xdb\x11\xa1\x75\x0e", " RLX", 18}, // eth / Relex - { 1, "\x09\x96\xbf\xb5\xd0\x57\xfa\xa2\x37\x64\x0e\x25\x06\xbe\x7b\x4f\x9c\x46\xde\x0b", " RNDR", 18}, // eth / Render Token - { 1, "\xa4\x01\x06\x13\x4c\x5b\xf4\xc4\x14\x11\x55\x4e\x6d\xb9\x9b\x95\xa1\x5e\xd9\xd8", " ROCK", 18}, // eth / Rocket Token - { 1, "\xc9\xde\x4b\x7f\x0c\x3d\x99\x1e\x96\x71\x58\xe4\xd4\xbf\xa4\xb5\x1e\xc0\xb1\x14", " ROK", 18}, // eth / Rocketchain - { 1, "\x49\x93\xcb\x95\xc7\x44\x3b\xdc\x06\x15\x5c\x5f\x56\x88\xbe\x9d\x8f\x69\x99\xa5", " ROUND", 18}, // eth / ROUND - { 1, "\xb4\xef\xd8\x5c\x19\x99\x9d\x84\x25\x13\x04\xbd\xa9\x9e\x90\xb9\x23\x00\xbd\x93", " RPL", 18}, // eth / Rocket Pool - { 1, "\x54\xb2\x93\x22\x60\x00\xcc\xbf\xc0\x4d\xf9\x02\xee\xc5\x67\xcb\x4c\x35\xa9\x03", " RTN", 18}, // eth / RiderToken - { 1, "\x41\xf6\x15\xe2\x4f\xab\xd2\xb0\x97\xa3\x20\xe9\xe6\xc1\xf4\x48\xcb\x40\x52\x1c", " RVL", 18}, // eth / RVL - { 1, "\x3d\x1b\xa9\xbe\x9f\x66\xb8\xee\x10\x19\x11\xbc\x36\xd3\xfb\x56\x2e\xac\x22\x44", " RVT", 18}, // eth / Rivetz - { 1, "\x1e\xc8\xfe\x51\xa9\xb6\xa3\xa6\xc4\x27\xd1\x7d\x9e\xcc\x30\x60\xfb\xc4\xa4\x5c", " S-A-PAT", 18}, // eth / S-A-PAT - { 1, "\x3e\xb9\x1d\x23\x7e\x49\x1e\x0d\xee\x85\x82\xc4\x02\xd8\x5c\xb4\x40\xfb\x6b\x54", " S-ETH", 18}, // eth / S-ETH - { 1, "\x41\x56\xd3\x34\x2d\x5c\x38\x5a\x87\xd2\x64\xf9\x06\x53\x73\x35\x92\x00\x05\x81", " SALT", 8}, // eth / Salt Lending Token - { 1, "\x7c\x5a\x0c\xe9\x26\x7e\xd1\x9b\x22\xf8\xca\xe6\x53\xf1\x98\xe3\xe8\xda\xf0\x98", " SAN", 18}, // eth / Santiment - { 1, "\x78\xfe\x18\xe4\x1f\x43\x6e\x19\x81\xa3\xa6\x0d\x15\x57\xc8\xa7\xa9\x37\x04\x61", " SCANDI", 2}, // eth / Scandiweb Coin - { 1, "\xd7\x63\x17\x87\xb4\xdc\xc8\x7b\x12\x54\xcf\xd1\xe5\xce\x48\xe9\x68\x23\xde\xe8", " SCL", 8}, // eth / SocialCoin - { 1, "\x4c\xa7\x41\x85\x53\x2d\xc1\x78\x95\x27\x19\x4e\x5b\x9c\x86\x6d\xd3\x3f\x4e\x82", " SenSatorI", 18}, // eth / SenSatorI Token - { 1, "\x67\x45\xfa\xb6\x80\x1e\x37\x6c\xd2\x4f\x03\x57\x2b\x9c\x9b\x0d\x4e\xdd\xdc\xcf", " SENSE", 8}, // eth / Sensay - { 1, "\xe0\x6e\xda\x74\x35\xba\x74\x9b\x04\x73\x80\xce\xd4\x91\x21\xdd\xe9\x33\x34\xae", " SET", 0}, // eth / SET - { 1, "\x98\xf5\xe9\xb7\xf0\xe3\x39\x56\xc0\x44\x3e\x81\xbf\x7d\xeb\x8b\x5b\x1e\xd5\x45", " SEXY", 18}, // eth / Sexy Token - { 1, "\xa1\xcc\xc1\x66\xfa\xf0\xe9\x98\xb3\xe3\x32\x25\xa1\xa0\x30\x1b\x1c\x86\x11\x9d", " SGEL", 18}, // eth / SGELDER - { 1, "\x37\x42\x75\x76\x32\x4f\xe1\xf3\x62\x5c\x91\x02\x67\x47\x72\xd7\xcf\x71\x37\x7d", " SGT", 18}, // eth / SelfieYo Gold Token - { 1, "\xd2\x48\xb0\xd4\x8e\x44\xaa\xf9\xc4\x9a\xea\x03\x12\xbe\x7e\x13\xa6\xdc\x14\x68", " SGT", 1}, // eth / SGT - { 1, "\xef\x2e\x99\x66\xeb\x61\xbb\x49\x4e\x53\x75\xd5\xdf\x8d\x67\xb7\xdb\x8a\x78\x0d", " SHIT", 0}, // eth / SHIT - { 1, "\x8a\x18\x7d\x52\x85\xd3\x16\xbc\xbc\x9a\xda\xfc\x08\xb5\x1d\x70\xa0\xd8\xe0\x00", " SIFT", 0}, // eth / SIFT - { 1, "\x68\x88\xa1\x6e\xa9\x79\x2c\x15\xa4\xdc\xf2\xf6\xc6\x23\xd0\x55\xc8\xed\xe7\x92", " SIG", 18}, // eth / Signal - { 1, "\x2b\xdc\x0d\x42\x99\x60\x17\xfc\xe2\x14\xb2\x16\x07\xa5\x15\xda\x41\xa9\xe0\xc5", " SKIN", 6}, // eth / SKIN - { 1, "\x49\x94\xe8\x18\x97\xa9\x20\xc0\xfe\xa2\x35\xeb\x8c\xed\xee\xd3\xc6\xff\xf6\x97", " SKO1", 18}, // eth / Sikoba - { 1, "\x4c\x38\x2f\x8e\x09\x61\x5a\xc8\x6e\x08\xce\x58\x26\x6c\xc2\x27\xe7\xd4\xd9\x13", " SKR", 6}, // eth / SKR Token - { 1, "\x32\x4a\x48\xeb\xcb\xb4\x6e\x61\x99\x39\x31\xef\x9d\x35\xf6\x69\x7c\xd2\x90\x1b", " SKRP", 18}, // eth / Skraps - { 1, "\x6e\x34\xd8\xd8\x47\x64\xd4\x0f\x6d\x7b\x39\xcd\x56\x9f\xd0\x17\xbf\x53\x17\x7d", " SKRP", 18}, // eth / Skraps - { 1, "\xfd\xfe\x8b\x7a\xb6\xcf\x1b\xd1\xe3\xd1\x45\x38\xef\x40\x68\x62\x96\xc4\x20\x52", " SKRP", 18}, // eth / Skraps - { 1, "\x7a\x5f\xf2\x95\xdc\x82\x39\xd5\xc2\x37\x4e\x4d\x89\x42\x02\xaa\xf0\x29\xca\xb6", " SLT", 3}, // eth / Smartlands - { 1, "\x79\x28\xc8\xab\xf1\xf7\x4e\xf9\xf9\x6d\x4d\x0a\x44\xe3\xb4\x20\x9d\x36\x07\x85", " SLY", 18}, // eth / Selfllery - { 1, "\x6f\x6d\xeb\x5d\xb0\xc4\x99\x4a\x82\x83\xa0\x1d\x6c\xfe\xeb\x27\xfc\x3b\xbe\x9c", " SMART", 0}, // eth / Smart Billions - { 1, "\x2d\xcf\xaa\xc1\x1c\x9e\xeb\xd8\xc6\xc4\x21\x03\xfe\x9e\x2a\x6a\xd2\x37\xaf\x27", " SMT", 18}, // eth / Smart Node - { 1, "\x55\xf9\x39\x85\x43\x1f\xc9\x30\x40\x77\x68\x7a\x35\xa1\xba\x10\x3d\xc1\xe0\x81", " SMT", 18}, // eth / SmartMesh - { 1, "\x78\xeb\x8d\xc6\x41\x07\x7f\x04\x9f\x91\x06\x59\xb6\xd5\x80\xe8\x0d\xc4\xd2\x37", " SMT", 8}, // eth / Social Media Market - { 1, "\xf4\x13\x41\x46\xaf\x2d\x51\x1d\xd5\xea\x8c\xdb\x1c\x4a\xc8\x8c\x57\xd6\x04\x04", " SNC", 18}, // eth / SNC - { 1, "\xf3\x33\xb2\xac\xe9\x92\xac\x2b\xbd\x87\x98\xbf\x57\xbc\x65\xa0\x61\x84\xaf\xba", " SND", 0}, // eth / Sandcoin - { 1, "\xcf\xd6\xae\x8b\xf1\x3f\x42\xde\x14\x86\x73\x51\xea\xff\x7a\x8a\x3b\x9f\xbb\xe7", " SNG", 8}, // eth / SINERGIA - { 1, "\xae\xc2\xe8\x7e\x0a\x23\x52\x66\xd9\xc5\xad\xc9\xde\xb4\xb2\xe2\x9b\x54\xd0\x09", " SNGLS", 0}, // eth / SingularDTV - { 1, "\x44\xf5\x88\xae\xeb\x8c\x44\x47\x14\x39\xd1\x27\x0b\x36\x03\xc6\x6a\x92\x62\xf1", " SNIP", 18}, // eth / SNIP - { 1, "\x98\x3f\x6d\x60\xdb\x79\xea\x8c\xa4\xeb\x99\x68\xc6\xaf\xf8\xcf\xa0\x4b\x3c\x63", " SNM", 18}, // eth / SNM - { 1, "\xbd\xc5\xba\xc3\x9d\xbe\x13\x2b\x1e\x03\x0e\x89\x8a\xe3\x83\x00\x17\xd7\xd9\x69", " SNOV", 18}, // eth / SNOV - { 1, "\x74\x4d\x70\xfd\xbe\x2b\xa4\xcf\x95\x13\x16\x26\x61\x4a\x17\x63\xdf\x80\x5b\x9e", " SNT", 18}, // eth / Status Network Token - { 1, "\x1f\x54\x63\x8b\x77\x37\x19\x3f\xfd\x86\xc1\x9e\xc5\x19\x07\xa7\xc4\x17\x55\xd8", " SOL", 6}, // eth / Sola Token - { 1, "\x42\xd6\x62\x2d\xec\xe3\x94\xb5\x49\x99\xfb\xd7\x3d\x10\x81\x23\x80\x6f\x6a\x18", " SPANK", 18}, // eth / SpankChain - { 1, "\x58\xbf\x7d\xf5\x7d\x9d\xa7\x11\x3c\x4c\xcb\x49\xd8\x46\x3d\x49\x08\xc7\x35\xcb", " SPARC", 18}, // eth / SPARC - { 1, "\x24\xae\xf3\xbf\x1a\x47\x56\x15\x00\xf9\x43\x0d\x74\xed\x40\x97\xc4\x7f\x51\xf2", " SPARTA", 4}, // eth / SPARTA - { 1, "\x85\x08\x93\x89\xc1\x4b\xd9\xc7\x7f\xc2\xb8\xf0\xc3\xd1\xdc\x33\x63\xbf\x06\xef", " SPF", 18}, // eth / Sportify - { 1, "\x20\xf7\xa3\xdd\xf2\x44\xdc\x92\x99\x97\x5b\x4d\xa1\xc3\x9f\x8d\x5d\x75\xf0\x5a", " SPN", 6}, // eth / Sapien - { 1, "\x68\xd5\x7c\x9a\x1c\x35\xf6\x3e\x2c\x83\xee\x8e\x49\xa6\x4e\x9d\x70\x52\x8d\x25", " SRN", 18}, // eth / Sirin Labs - { 1, "\xb1\x5f\xe5\xa1\x23\xe6\x47\xba\x59\x4c\xea\x7a\x1e\x64\x86\x46\xf9\x5e\xb4\xaa", " SS", 18}, // eth / Sharder - { 1, "\xbb\xff\x86\x2d\x90\x6e\x34\x8e\x99\x46\xbf\xb2\x13\x2e\xcb\x15\x7d\xa3\xd4\xb4", " SS", 18}, // eth / Sharder - { 1, "\x6e\x20\x50\xcb\xfb\x3e\xd8\xa4\xd3\x9b\x64\xcc\x9f\x47\xe7\x11\xa0\x3a\x5a\x89", " SSH", 18}, // eth / StreamShares - { 1, "\x4a\x89\xcd\x48\x6f\xa9\x96\xad\x50\xc0\xa6\x3c\x35\xc7\x87\x02\xf5\x42\x2a\x50", " STABIT", 3}, // eth / StabitCoin - { 1, "\x9a\x00\x5c\x9a\x89\xbd\x72\xa4\xbd\x27\x72\x1e\x7a\x09\xa3\xc1\x1d\x2b\x03\xc4", " STAC", 18}, // eth / Starter Coin - { 1, "\xf7\x0a\x64\x2b\xd3\x87\xf9\x43\x80\xff\xb9\x04\x51\xc2\xc8\x1d\x4e\xb8\x2c\xbc", " STAR", 18}, // eth / Star Token - { 1, "\x62\x9a\xee\x55\xed\x49\x58\x1c\x33\xab\x27\xf9\x40\x3f\x79\x92\xa2\x89\xff\xd5", " STC", 18}, // eth / StrikeCoin Token - { 1, "\xae\x73\xb3\x8d\x1c\x9a\x8b\x27\x41\x27\xec\x30\x16\x0a\x49\x27\xc4\xd7\x18\x24", " STK", 18}, // eth / STK Token - { 1, "\x59\x93\x46\x77\x9e\x90\xfc\x3f\x5f\x99\x7b\x5e\xa7\x15\x34\x98\x20\xf9\x15\x71", " STN", 4}, // eth / Saturn Network - { 1, "\xb6\x4e\xf5\x1c\x88\x89\x72\xc9\x08\xcf\xac\xf5\x9b\x47\xc1\xaf\xbc\x0a\xb8\xac", " STORJ", 8}, // eth / STORJ - { 1, "\xd0\xa4\xb8\x94\x6c\xb5\x2f\x06\x61\x27\x3b\xfb\xc6\xfd\x0e\x0c\x75\xfc\x64\x33", " STORM", 18}, // eth / Storm Token - { 1, "\xec\xd5\x70\xbb\xf7\x47\x61\xb9\x60\xfa\x04\xcc\x10\xfe\x2c\x4e\x86\xff\xda\x36", " STP", 8}, // eth / StashPay - { 1, "\x5c\x3a\x22\x85\x10\xd2\x46\xb7\x8a\x37\x65\xc2\x02\x21\xcb\xf3\x08\x2b\x44\xa4", " STQ", 18}, // eth / Storiqa - { 1, "\x46\x49\x24\x73\x75\x5e\x8d\xf9\x60\xf8\x03\x48\x77\xf6\x17\x32\xd7\x18\xce\x96", " STRC", 8}, // eth / STRC - { 1, "\x00\x6b\xea\x43\xba\xa3\xf7\xa6\xf7\x65\xf1\x4f\x10\xa1\xa1\xb0\x83\x34\xef\x45", " STX", 18}, // eth / StoxToken - { 1, "\x12\x48\x0e\x24\xeb\x5b\xec\x1a\x9d\x43\x69\xca\xb6\xa8\x0c\xad\x3c\x0a\x37\x7a", " SUB", 2}, // eth / Substratum - { 1, "\x9e\x88\x61\x34\x18\xcf\x03\xdc\xa5\x4d\x6a\x2c\xf6\xad\x93\x4a\x78\xc7\xa1\x7a", " SWM", 18}, // eth / Swarm Fund Token - { 1, "\xb9\xe7\xf8\x56\x8e\x08\xd5\x65\x9f\x5d\x29\xc4\x99\x71\x73\xd8\x4c\xdf\x26\x07", " SWT", 18}, // eth / Swarm City Token - { 1, "\x12\xb3\x06\xfa\x98\xf4\xcb\xb8\xd4\x45\x7f\xdf\xf3\xa0\xa0\xa5\x6f\x07\xcc\xdf", " SXDT", 18}, // eth / Spectre.ai D-Token - { 1, "\x2c\x82\xc7\x3d\x5b\x34\xaa\x01\x59\x89\x46\x2b\x29\x48\xcd\x61\x6a\x37\x64\x1f", " SXUT", 18}, // eth / Spectre.ai U-Token - { 1, "\x10\xb1\x23\xfd\xdd\xe0\x03\x24\x31\x99\xaa\xd0\x35\x22\x06\x5d\xc0\x58\x27\xa0", " SYN", 18}, // eth / Synapse - { 1, "\xe7\x77\x5a\x6e\x9b\xcf\x90\x4e\xb3\x9d\xa2\xb6\x8c\x5e\xfb\x4f\x93\x60\xe0\x8c", " TaaS", 6}, // eth / Token-as-a-Service - { 1, "\xc2\x7a\x2f\x05\xfa\x57\x7a\x83\xba\x0f\xdb\x4c\x38\x44\x3c\x07\x18\x35\x65\x01", " TAU", 18}, // eth / Lamden Tau - { 1, "\xfa\xcc\xd5\xfc\x83\xc3\xe4\xc3\xc1\xac\x1e\xf3\x5d\x15\xad\xf0\x6b\xcf\x20\x9c", " TBC2", 8}, // eth / TBC2 - { 1, "\xaf\xe6\x05\x11\x34\x1a\x37\x48\x8d\xe2\x5b\xef\x35\x19\x52\x56\x2e\x31\xfc\xc1", " TBT", 8}, // eth / TBitBot - { 1, "\xfa\x0e\xf5\xe0\x34\xca\xe1\xae\x75\x2d\x59\xbd\xb8\xad\xcd\xe3\x7e\xd7\xab\x97", " TCA", 18}, // eth / TangguoTao Token - { 1, "\x2a\x1d\xba\xbe\x65\xc5\x95\xb0\x02\x2e\x75\x20\x8c\x34\x01\x41\x39\xd5\xd3\x57", " TDH", 18}, // eth / TrustedHealth - { 1, "\x85\xe0\x76\x36\x1c\xc8\x13\xa9\x08\xff\x67\x2f\x9b\xad\x15\x41\x47\x44\x02\xb2", " TEL", 2}, // eth / Telcoin - { 1, "\xa7\xf9\x76\xc3\x60\xeb\xbe\xd4\x46\x5c\x28\x55\x68\x4d\x1a\xae\x52\x71\xef\xa9", " TFL", 8}, // eth / TrueFlip - { 1, "\x38\x83\xf5\xe1\x81\xfc\xca\xf8\x41\x0f\xa6\x1e\x12\xb5\x9b\xad\x96\x3f\xb6\x45", " THETA", 18}, // eth / Theta Token - { 1, "\xfe\x7b\x91\x5a\x0b\xaa\x0e\x79\xf8\x5c\x55\x53\x26\x65\x13\xf7\xc1\xc0\x3e\xd0", " THUG", 18}, // eth / THUG - { 1, "\xa5\xdb\x1d\x6f\x7a\x0d\x5b\xcc\xc1\x7d\x0b\xfd\x39\xd7\xaf\x32\xd5\xe5\xed\xc6", " TICO", 5}, // eth / Topinvestmentcoin - { 1, "\x65\x31\xf1\x33\xe6\xde\xeb\xe7\xf2\xdc\xe5\xa0\x44\x1a\xa7\xef\x33\x0b\x4e\x53", " TIME", 8}, // eth / Chronobank - { 1, "\x80\xbc\x55\x12\x56\x1c\x7f\x85\xa3\xa9\x50\x8c\x7d\xf7\x90\x1b\x37\x0f\xa1\xdf", " TIO", 18}, // eth / TIO - { 1, "\xea\x1f\x34\x6f\xaf\x02\x3f\x97\x4e\xb5\xad\xaf\x08\x8b\xbc\xdf\x02\xd7\x61\xf4", " TIX", 18}, // eth / Blocktix - { 1, "\xaa\xaf\x91\xd9\xb9\x0d\xf8\x00\xdf\x4f\x55\xc2\x05\xfd\x69\x89\xc9\x77\xe7\x3a", " TKN", 8}, // eth / TokenCard - { 1, "\x08\xf5\xa9\x23\x5b\x08\x17\x3b\x75\x69\xf8\x36\x45\xd2\xc7\xfb\x55\xe8\xcc\xd8", " TNT", 8}, // eth / Tierion Network Token - { 1, "\x8e\xb9\x65\xee\x9c\xcf\xbc\xe7\x6c\x0a\x06\x26\x44\x92\xc0\xaf\xef\xc2\x82\x6d", " TOOR", 18}, // eth / ToorCoin - { 1, "\xcb\x3f\x90\x2b\xf9\x76\x26\x39\x1b\xf8\xba\x87\x26\x4b\xbc\x3d\xc1\x34\x69\xbe", " TRC", 18}, // eth / The Real Coin - { 1, "\x56\x6f\xd7\x99\x9b\x1f\xc3\x98\x80\x22\xbd\x38\x50\x7a\x48\xf0\xbc\xf2\x2c\x77", " TRCN", 18}, // eth / The Real Coin - { 1, "\xcb\x94\xbe\x6f\x13\xa1\x18\x2e\x4a\x4b\x61\x40\xcb\x7b\xf2\x02\x5d\x28\xe4\x1b", " TRST", 6}, // eth / TRST - { 1, "\xf2\x30\xb7\x90\xe0\x53\x90\xfc\x82\x95\xf4\xd3\xf6\x03\x32\xc9\x3b\xed\x42\xe2", " TRX", 6}, // eth / Tron Lab Token - { 1, "\x6b\x87\x99\x9b\xe8\x73\x58\x06\x5b\xbd\xe4\x1e\x8a\x0f\xe0\xb7\xb1\xcd\x25\x14", " TSW", 18}, // eth / TeslaWatt - { 1, "\x2e\xf1\xab\x8a\x26\x18\x7c\x58\xbb\x8a\xae\xb1\x1b\x2f\xc6\xd2\x5c\x5c\x07\x16", " TWN", 18}, // eth / The World News - { 1, "\xfb\xd0\xd1\xc7\x7b\x50\x17\x96\xa3\x5d\x86\xcf\x91\xd6\x5d\x97\x78\xee\xe6\x95", " TWNKL", 3}, // eth / Twinkle - { 1, "\x24\x69\x27\x91\xbc\x44\x4c\x5c\xd0\xb8\x1e\x3c\xbc\xab\xa4\xb0\x4a\xcd\x1f\x3b", " UKG", 18}, // eth / UnikoinGold - { 1, "\x10\x5d\x97\xef\x2e\x72\x3f\x1c\xfb\x24\x51\x9b\xc6\xff\x15\xa6\xd0\x91\xa3\xf1", " UMKA", 4}, // eth / UMKA - { 1, "\x8e\x5a\xfc\x69\xf6\x22\x7a\x3a\xd7\x5e\xd3\x46\xc8\x72\x3b\xc6\x2c\xe9\x71\x23", " UMKA", 4}, // eth / UMKA - { 1, "\x89\x20\x5a\x3a\x3b\x2a\x69\xde\x6d\xbf\x7f\x01\xed\x13\xb2\x10\x8b\x2c\x43\xe7", " Unicorn", 0}, // eth / Unicorn - { 1, "\xd0\x1d\xb7\x3e\x04\x78\x55\xef\xb4\x14\xe6\x20\x20\x98\xc4\xbe\x4c\xd2\x42\x3b", " UQC", 18}, // eth / Uquid Coin - { 1, "\x93\x16\x84\x13\x9f\x75\x6c\x24\xec\x07\x31\xe9\xf7\x4f\xe5\x0e\x55\x48\xdd\xef", " URB", 18}, // eth / Urbit Data - { 1, "\xd7\x60\xad\xdf\xb2\x4d\x9c\x01\xfe\x4b\xfe\xa7\x47\x5c\x5e\x36\x36\x68\x40\x58", " USDM", 2}, // eth / Mether (USDM) - { 1, "\xda\xc1\x7f\x95\x8d\x2e\xe5\x23\xa2\x20\x62\x06\x99\x45\x97\xc1\x3d\x83\x1e\xc7", " USDT", 6}, // eth / USD Tether (erc20) - { 1, "\x70\xa7\x28\x33\xd6\xbf\x7f\x50\x8c\x82\x24\xce\x59\xea\x1e\xf3\xd0\xea\x3a\x38", " UTK", 18}, // eth / UTK - { 1, "\x9e\x33\x19\x63\x6e\x21\x26\xe3\xc0\xbc\x9e\x31\x34\xae\xc5\xe1\x50\x8a\x46\xc7", " UTN-P", 18}, // eth / Universa - { 1, "\x35\x43\x63\x8e\xd4\xa9\x00\x6e\x48\x40\xb1\x05\x94\x42\x71\xbc\xea\x15\x60\x5d", " UUU", 18}, // eth / U Networks - { 1, "\x57\xc7\x5e\xcc\xc8\x55\x71\x36\xd3\x26\x19\xa1\x91\xfb\xcd\xc8\x85\x60\xd7\x11", " VDG", 0}, // eth / VeriDocGlobal - { 1, "\x82\xbd\x52\x6b\xdb\x71\x8c\x6d\x4d\xd2\x29\x1e\xd0\x13\xa5\x18\x6c\xae\x2d\xca", " VDOC", 18}, // eth / Duty of Care Token - { 1, "\x34\x0d\x2b\xde\x5e\xb2\x8c\x1e\xed\x91\xb2\xf7\x90\x72\x3e\x3b\x16\x06\x13\xb7", " VEE", 18}, // eth / BLOCKv - { 1, "\xd8\x50\x94\x2e\xf8\x81\x1f\x2a\x86\x66\x92\xa6\x23\x01\x1b\xde\x52\xa4\x62\xc1", " VEN", 18}, // eth / Vechain - { 1, "\xeb\xed\x4f\xf9\xfe\x34\x41\x3d\xb8\xfc\x82\x94\x55\x6b\xbd\x15\x28\xa4\xda\xca", " VENUS", 3}, // eth / VENUS - { 1, "\x8f\x34\x70\xa7\x38\x8c\x05\xee\x4e\x7a\xf3\xd0\x1d\x8c\x72\x2b\x0f\xf5\x23\x74", " VERI", 18}, // eth / Veritas - { 1, "\x2c\x97\x4b\x2d\x0b\xa1\x71\x6e\x64\x4c\x1f\xc5\x99\x82\xa8\x9d\xdd\x2f\xf7\x24", " VIB", 18}, // eth / VIB - { 1, "\x88\x24\x48\xf8\x3d\x90\xb2\xbf\x47\x7a\xf2\xea\x79\x32\x7f\xde\xa1\x33\x5d\x93", " VIBEX", 18}, // eth / VIBEX Exchange Token - { 1, "\xe8\xff\x5c\x9c\x75\xde\xb3\x46\xac\xac\x49\x3c\x46\x3c\x89\x50\xbe\x03\xdf\xba", " VIBEX", 18}, // eth / VIBEX - { 1, "\xf0\x3f\x8d\x65\xba\xfa\x59\x86\x11\xc3\x49\x51\x24\x09\x3c\x56\xe8\xf6\x38\xf0", " VIEW", 18}, // eth / Viewly - { 1, "\x23\xb7\x5b\xc7\xaa\xf2\x8e\x2d\x66\x28\xc3\xf4\x24\xb3\x88\x2f\x8f\x07\x2a\x3c", " VIT", 18}, // eth / Vice Industry Token - { 1, "\x51\x94\x75\xb3\x16\x53\xe4\x6d\x20\xcd\x09\xf9\xfd\xcf\x3b\x12\xbd\xac\xb4\xf5", " VIU", 18}, // eth / VIU - { 1, "\x92\x2a\xc4\x73\xa3\xcc\x24\x1f\xd3\xa0\x04\x9e\xd1\x45\x36\x45\x2d\x58\xd7\x3c", " VLD", 18}, // eth / VETRI - { 1, "\xc3\xbc\x9e\xb7\x1f\x75\xec\x43\x9a\x6b\x6c\x8e\x8b\x74\x6f\xcf\x5b\x62\xf7\x03", " VOC", 18}, // eth / VORMACOIN - { 1, "\x83\xee\xa0\x0d\x83\x8f\x92\xde\xc4\xd1\x47\x56\x97\xb9\xf4\xd3\x53\x7b\x56\xe3", " VOISE", 8}, // eth / Voise - { 1, "\xed\xba\xf3\xc5\x10\x03\x02\xdc\xdd\xa5\x32\x69\x32\x2f\x37\x30\xb1\xf0\x41\x6d", " VRS", 5}, // eth / Veros - { 1, "\x5c\x54\x3e\x7a\xe0\xa1\x10\x4f\x78\x40\x6c\x34\x0e\x9c\x64\xfd\x9f\xce\x51\x70", " VSL", 18}, // eth / Vdice - { 1, "\x28\x6b\xda\x14\x13\xa2\xdf\x81\x73\x1d\x49\x30\xce\x2f\x86\x2a\x35\xa6\x09\xfe", " WaBi", 18}, // eth / WaBi - { 1, "\x39\xbb\x25\x9f\x66\xe1\xc5\x9d\x5a\xbe\xf8\x83\x75\x97\x9b\x4d\x20\xd9\x80\x22", " WAX", 8}, // eth / WAX - { 1, "\x74\x95\x1b\x67\x7d\xe3\x2d\x59\x6e\xe8\x51\xa2\x33\x33\x69\x26\xe6\xa2\xcd\x09", " WBA", 7}, // eth / WeBetCrypto - { 1, "\x8f\x93\x6f\xe0\xfa\xf0\x60\x4c\x9c\x0e\xf2\x40\x6b\xde\x0a\x65\x36\x55\x15\xd6", " WCN", 18}, // eth / WorldCoinNetwork - { 1, "\x6a\x0a\x97\xe4\x7d\x15\xaa\xd1\xd1\x32\xa1\xac\x79\xa4\x80\xe3\xf2\x07\x90\x63", " WCT", 18}, // eth / WePower - { 1, "\xc0\x2a\xaa\x39\xb2\x23\xfe\x8d\x0a\x0e\x5c\x4f\x27\xea\xd9\x08\x3c\x75\x6c\xc2", " WETH", 18}, // eth / WETH - { 1, "\xf4\xfe\x95\x60\x38\x81\xd0\xe0\x79\x54\xfd\x76\x05\xe0\xe9\xa9\x16\xe4\x2c\x44", " WHEN", 18}, // eth / WHEN Token - { 1, "\xe2\x00\x64\x18\x90\x77\x2f\xce\x8e\xe6\xed\xc5\x35\x4c\xce\xa3\x0a\xc9\x2f\x49", " WHO", 18}, // eth / WhoHas - { 1, "\xe9\x33\xc0\xcd\x97\x84\x41\x4d\x5f\x27\x8c\x11\x49\x04\xf5\xa8\x4b\x39\x69\x19", " WHO", 18}, // eth / WhoHas - { 1, "\x5e\x4a\xbe\x64\x19\x65\x0c\xa8\x39\xce\x5b\xb7\xdb\x42\x2b\x88\x1a\x60\x64\xbb", " WiC", 18}, // eth / Wi Coin - { 1, "\x62\xcd\x07\xd4\x14\xec\x50\xb6\x8c\x7e\xca\xa8\x63\xa2\x3d\x34\x4f\x2d\x06\x2f", " WIC", 0}, // eth / WickNote - { 1, "\xd3\xc0\x07\x72\xb2\x4d\x99\x7a\x81\x22\x49\xca\x63\x7a\x92\x1e\x81\x35\x77\x01", " WILD", 18}, // eth / WILD Token - { 1, "\x66\x70\x88\xb2\x12\xce\x3d\x06\xa1\xb5\x53\xa7\x22\x1e\x1f\xd1\x90\x00\xd9\xaf", " WINGS", 18}, // eth / WINGS - { 1, "\xbf\xbe\x53\x32\xf1\x72\xd7\x78\x11\xbc\x6c\x27\x28\x44\xf3\xe5\x4a\x7b\x23\xbb", " WMK", 18}, // eth / WemarkToken - { 1, "\xd7\x3a\x66\xb8\xfb\x26\xbe\x8b\x0a\xcd\x7c\x52\xbd\x32\x50\x54\xac\x7d\x46\x8b", " WNK", 18}, // eth / Woonk - { 1, "\x72\x87\x81\xe7\x57\x35\xdc\x09\x62\xdf\x3a\x51\xd7\xef\x47\xe7\x98\xa7\x10\x7e", " WOLK", 18}, // eth / WOLK - { 1, "\xf6\xb5\x5a\xcb\xbc\x49\xf4\x52\x4a\xa4\x8d\x19\x28\x1a\x9a\x77\xc5\x4d\xe1\x0f", " WOLK", 18}, // eth / Wolk Token - { 1, "\xd1\x8e\x45\x4d\x84\x4e\xb0\x00\x9d\x32\xe0\x7a\x0c\xde\x89\xe1\x8d\x64\xcf\xb4", " WORK", 18}, // eth / workTOKEN - { 1, "\x62\x08\x72\x45\x08\x71\x25\xd3\xdb\x5b\x9a\x3d\x71\x3d\x78\xe7\xbb\xc3\x1e\x54", " WPC", 18}, // eth / WorldPeaceCoin - { 1, "\x4c\xf4\x88\x38\x7f\x03\x5f\xf0\x8c\x37\x15\x15\x56\x2c\xba\x71\x2f\x90\x15\xd4", " WPR", 18}, // eth / WePower Token - { 1, "\x71\xe8\xd7\x4f\xf1\xc9\x23\xe3\x69\xd0\xe7\x0d\xfb\x09\x86\x66\x29\xc4\xdd\x35", " WRK", 18}, // eth / WorkCoin - { 1, "\xb7\xcb\x1c\x96\xdb\x6b\x22\xb0\xd3\xd9\x53\x6e\x01\x08\xd0\x62\xbd\x48\x8f\x74", " WTC", 18}, // eth / Walton - { 1, "\xd8\x95\x0f\xde\xaa\x10\x30\x4b\x7a\x7f\xd0\x3a\x2f\xc6\x6b\xc3\x9f\x3c\x71\x1a", " WYS", 18}, // eth / wystoken - { 1, "\x05\x60\x17\xc5\x5a\xe7\xae\x32\xd1\x2a\xef\x7c\x67\x9d\xf8\x3a\x85\xca\x75\xff", " WYV", 18}, // eth / WyvernToken - { 1, "\x91\x0d\xfc\x18\xd6\xea\x3d\x6a\x71\x24\xa6\xf8\xb5\x45\x8f\x28\x10\x60\xfa\x4c", " X8X", 18}, // eth / X8X - { 1, "\x4d\xf8\x12\xf6\x06\x4d\xef\x1e\x5e\x02\x9f\x1c\xa8\x58\x77\x7c\xc9\x8d\x2d\x81", " XAUR", 8}, // eth / Xaurum - { 1, "\x28\xde\xe0\x1d\x53\xfe\xd0\xed\xf5\xf6\xe3\x10\xbf\x8e\xf9\x31\x15\x13\xae\x40", " XBP", 18}, // eth / BlitzPredict - { 1, "\x4d\x82\x9f\x8c\x92\xa6\x69\x1c\x56\x30\x0d\x02\x0c\x9e\x0d\xb9\x84\xcf\xe2\xba", " XCC", 18}, // eth / CoinCrowd - { 1, "\x16\xaf\x5b\xfb\x4a\xe7\xe4\x75\xb9\xad\xc3\xbf\x5c\xb2\xf1\xe6\xa5\x0d\x79\x40", " XFS", 8}, // eth / Fanship - { 1, "\xf6\xb6\xaa\x0e\xf0\xf5\xed\xc2\xc1\xc5\xd9\x25\x47\x7f\x97\xea\xf6\x63\x03\xe7", " XGG", 8}, // eth / Going Gems - { 1, "\x53\x3e\xf0\x98\x4b\x2f\xaa\x22\x7a\xcc\x62\x0c\x67\xcc\xe1\x2a\xa3\x9c\xd8\xcd", " XGM", 8}, // eth / XGM - { 1, "\x30\xf4\xa3\xe0\xab\x7a\x76\x73\x3d\x8b\x60\xb8\x9d\xd9\x3c\x3d\x0b\x4c\x9e\x2f", " XGT", 18}, // eth / XGT - { 1, "\xb1\x10\xec\x7b\x1d\xcb\x8f\xab\x8d\xed\xbf\x28\xf5\x3b\xc6\x3e\xa5\xbe\xdd\x84", " XID", 8}, // eth / XID - { 1, "\xbc\x86\x72\x7e\x77\x0d\xe6\x8b\x10\x60\xc9\x1f\x6b\xb6\x94\x5c\x73\xe1\x03\x88", " XNK", 18}, // eth / Ink Protocol - { 1, "\xab\x95\xe9\x15\xc1\x23\xfd\xed\x5b\xdf\xb6\x32\x5e\x35\xef\x55\x15\xf1\xea\x69", " XNN", 18}, // eth / XENON - { 1, "\x57\x2e\x6f\x31\x80\x56\xba\x0c\x5d\x47\xa4\x22\x65\x31\x13\x84\x3d\x25\x06\x91", " XNT", 0}, // eth / XNT - { 1, "\xb2\x47\x54\xbe\x79\x28\x15\x53\xdc\x1a\xdc\x16\x0d\xdf\x5c\xd9\xb7\x43\x61\xa4", " XRL", 9}, // eth / XRL - { 1, "\x0f\x51\x3f\xfb\x49\x26\xff\x82\xd7\xf6\x0a\x05\x06\x90\x47\xac\xa2\x95\xc4\x13", " XSC", 18}, // eth / XSC - { 1, "\x6f\x7a\x4b\xac\x33\x15\xb5\x08\x2f\x79\x31\x61\xa2\x2e\x26\x66\x6d\x22\x71\x7f", " YEED", 18}, // eth / YEED - { 1, "\xca\x27\x96\xf9\xf6\x1d\xc7\xb2\x38\xaa\xb0\x43\x97\x1e\x49\xc6\x16\x4d\xf3\x75", " YEED", 18}, // eth / YGGDRASH - { 1, "\xd9\xa1\x2c\xde\x03\xa8\x6e\x80\x04\x96\x46\x98\x58\xde\x85\x81\xd3\xa5\x35\x3d", " YUP", 18}, // eth / YUP - { 1, "\x0f\x33\xbb\x20\xa2\x82\xa7\x64\x9c\x7b\x3a\xff\x64\x4f\x08\x4a\x93\x48\xe9\x33", " YUPIE", 18}, // eth / YUPIE - { 1, "\x67\x81\xa0\xf8\x4c\x7e\x9e\x84\x6d\xcb\x84\xa9\xa5\xbd\x49\x33\x30\x67\xb1\x04", " ZAP", 18}, // eth / ZAP - { 1, "\x7a\x41\xe0\x51\x7a\x5e\xca\x4f\xdb\xc7\xfb\xeb\xa4\xd4\xc4\x7b\x9f\xf6\xdc\x63", " ZCS", 18}, // eth / Zeusshield - { 1, "\x05\xf4\xa4\x2e\x25\x1f\x2d\x52\xb8\xed\x15\xe9\xfe\xda\xac\xfc\xef\x1f\xad\x27", " ZIL", 12}, // eth / Zilliqa - { 1, "\x55\x4f\xfc\x77\xf4\x25\x1a\x9f\xb3\xc0\xe3\x59\x0a\x6a\x20\x5f\x8d\x4e\x06\x7d", " ZMN", 18}, // eth / ZMINE - { 1, "\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98", " ZRX", 18}, // eth / 0x Project - { 1, "\xe3\x86\xb1\x39\xed\x37\x15\xca\x4b\x18\xfd\x52\x67\x1b\xdc\xea\x1c\xdf\xe4\xb1", " ZST", 8}, // eth / Zeus Exchange - {42, "\x86\x67\x55\x92\x54\x24\x1d\xde\xd4\xd1\x13\x92\xf8\x68\xd7\x20\x92\x76\x53\x67", " Aeternity", 18}, // kov / Aeternity - {42, "\xc4\x37\x5b\x7d\xe8\xaf\x5a\x38\xa9\x35\x48\xeb\x84\x53\xa4\x98\x22\x2c\x4f\xf2", " DAI", 18}, // kov / RadarRelay test Dai Stablecoin v1.0 - {42, "\xee\xe3\x87\x06\x57\xe4\x71\x66\x70\xf1\x85\xdf\x08\x65\x2d\xd8\x48\xfe\x8f\x7e", " DGD", 18}, // kov / RadarRelay test Digix DAO Token - {42, "\xef\x7f\xff\x64\x38\x9b\x81\x4a\x94\x6f\x3e\x92\x10\x55\x13\x70\x5c\xa6\xb9\x90", " GNT", 18}, // kov / RadarRelay test Golem Network Token - {42, "\x3c\x67\xf7\xd4\xde\xcf\x77\x95\x22\x5f\x51\xb5\x41\x34\xf8\x11\x37\x38\x5f\x83", " GUP", 3}, // kov / GUP - {42, "\x1d\xad\x47\x83\xcf\x3f\xe3\x08\x5c\x14\x26\x15\x7a\xb1\x75\xa6\x11\x9a\x04\xba", " MKR", 18}, // kov / RadarRelay test MakerDAO - {42, "\x32\x3b\x5d\x4c\x32\x34\x5c\xed\x77\x39\x3b\x35\x30\xb1\xee\xd0\xf3\x46\x42\x9d", " MLN", 18}, // kov / RadarRelay test Melon Tokens - {42, "\xb1\x88\x45\xc2\x60\xf6\x80\xd5\xb9\xd8\x46\x49\x63\x88\x13\xe3\x42\xe4\xf8\xc9", " REP", 18}, // kov / RadarRelay test Augur Reputation Token - {42, "\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70", " ZRX", 18}, // kov / RadarRelay test 0x Protocol Token - { 4, "\x39\x8a\x7a\x69\xf3\xc5\x91\x81\xa1\xff\xe3\x4b\xed\x11\xdc\xb5\xdf\x86\x3a\x8a", " AETH", 18}, // rin / AKASHA Tokens - { 4, "\xe2\x78\x26\xee\x77\x8b\x6f\x78\xa4\x9a\x68\x6d\xa7\xd6\x4f\x6e\x7b\x08\x4a\x4f", " BHNT", 0}, // rin / Berlin Hack&Tell winner token - { 4, "\x8b\x65\xd4\xb7\xee\x3f\xff\xa9\x86\xc5\x77\xf0\xf4\xb7\x0a\x21\xba\xe3\xdd\x54", " CTGA", 18}, // rin / Convenient To Go - { 4, "\x27\x5a\x5b\x34\x65\x99\xb5\x69\x17\xe7\xb1\xc9\xde\x01\x9d\xcf\x9e\xad\x86\x1a", " KC", 18}, // rin / Karma Token - { 4, "\x64\x75\xa7\xfa\x6e\xd2\xd5\x18\x0f\x0e\x0a\x07\xc2\xd9\x51\xd1\x2c\x0e\xdb\x91", " NONE", 0}, // rin / None - { 4, "\x12\xfe\x17\x4c\x09\x7f\x6b\x3e\x87\x6b\x3b\x06\x0c\x90\x61\xf4\xb9\xde\xbb\x80", " PPD", 18}, // rin / PP Donation - { 4, "\x36\x15\x75\x70\x11\x11\x25\x60\x52\x15\x36\x25\x8c\x1e\x73\x25\xae\x3b\x48\xae", " RDN", 18}, // rin / Raiden - { 4, "\x0a\x05\x7a\x87\xce\x9c\x56\xd7\xe3\x36\xb4\x17\xc7\x9c\xf3\x0e\x8d\x27\x86\x0b", " WALL", 15}, // rin / WALLETH Community-Token - { 3, "\x95\xd7\x32\x1e\xdc\xe5\x19\x41\x9b\xa1\xdb\xc6\x0a\x89\xba\xfb\xf5\x5e\xac\x0d", " PLASMA", 6}, // rop / *PLASMA - { 3, "\x6f\x95\xa3\xb6\x82\xf8\xe9\xaa\xcc\x86\xd0\x57\xa6\xdf\x88\xa0\xe6\x81\x45\xa8", " ILSC", 2}, // rop / IsraCoin - { 3, "\xfd\x5a\x69\xa1\x30\x95\x95\xff\x51\x21\x55\x3f\x52\xc8\xa5\xb2\xb1\xb3\x10\x31", " NONE", 0}, // rop / None - { 8, "\xff\x3b\xf0\x57\xad\xf3\xb0\xe0\x15\xb6\x46\x53\x31\xa6\x23\x6e\x55\x68\x82\x74", " BEER", 0}, // ubq / BEER - { 8, "\x08\x53\x3d\x6a\x06\xce\x36\x52\x98\xb1\x2e\xf9\x2e\xb4\x07\xcb\xa8\xaa\x82\x73", " CEFS", 8}, // ubq / CEFS - { 8, "\x94\xad\x7e\x41\xc1\xd4\x40\x22\xc4\xf4\x7c\xb1\xba\x01\x9f\xd1\xa0\x22\xc5\x36", " DOT", 8}, // ubq / DOT - { 8, "\x4b\x48\x99\xa1\x0f\x3e\x50\x7d\xb2\x07\xb0\xee\x24\x26\x02\x9e\xfa\x16\x8a\x67", " QWARK", 8}, // ubq / QWARK - { 8, "\x5e\x17\x15\xbb\x79\x80\x5b\xd6\x72\x72\x97\x60\xb3\xf7\xf3\x4d\x6f\x48\x50\x98", " RICKS", 8}, // ubq / RICKS -}; - -const TokenType *UnknownToken = (const TokenType *)1; - -const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address) -{ - if (!address) return 0; - for (int i = 0; i < TOKENS_COUNT; i++) { - if (chain_id == tokens[i].chain_id && memcmp(address, tokens[i].address, 20) == 0) { - return &(tokens[i]); - } - } - return UnknownToken; -} diff --git a/firmware/ethereum_tokens.c.mako b/firmware/ethereum_tokens.c.mako new file mode 100644 index 0000000000..2734c6a430 --- /dev/null +++ b/firmware/ethereum_tokens.c.mako @@ -0,0 +1,24 @@ +// This file is automatically generated from ethereum_tokens.c.mako +// DO NOT EDIT + +#include +#include "ethereum_tokens.h" + +const TokenType tokens[TOKENS_COUNT] = { +% for t in supported_on("trezor1", erc20): + {${"{:>2}".format(t.chain_id)}, ${c_str(t.address_bytes)}, " ${ascii(t.symbol)}", ${t.decimals}}, // ${t.chain} / ${t.name} +% endfor +}; + +const TokenType *UnknownToken = (const TokenType *)1; + +const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address) +{ + if (!address) return 0; + for (int i = 0; i < TOKENS_COUNT; i++) { + if (chain_id == tokens[i].chain_id && memcmp(address, tokens[i].address, 20) == 0) { + return &(tokens[i]); + } + } + return UnknownToken; +} diff --git a/firmware/ethereum_tokens.h b/firmware/ethereum_tokens.h deleted file mode 100644 index 5415ef7ee5..0000000000 --- a/firmware/ethereum_tokens.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#ifndef __ETHEREUM_TOKENS_H__ -#define __ETHEREUM_TOKENS_H__ - -#include - -#define TOKENS_COUNT 795 - -typedef struct { - uint32_t chain_id; - const char * const address; - const char * const ticker; - int decimals; -} TokenType; - -extern const TokenType tokens[TOKENS_COUNT]; - -extern const TokenType *UnknownToken; - -const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address); - -#endif diff --git a/firmware/ethereum_tokens.h.mako b/firmware/ethereum_tokens.h.mako new file mode 100644 index 0000000000..25de96ae52 --- /dev/null +++ b/firmware/ethereum_tokens.h.mako @@ -0,0 +1,25 @@ +// This file is automatically generated from ethereum_tokens.h.mako +// DO NOT EDIT + +#ifndef __ETHEREUM_TOKENS_H__ +#define __ETHEREUM_TOKENS_H__ + +#include + +<% erc20_list = list(supported_on("trezor1", erc20)) %>\ +#define TOKENS_COUNT ${len(erc20_list)} + +typedef struct { + uint32_t chain_id; + const char * const address; + const char * const ticker; + int decimals; +} TokenType; + +extern const TokenType tokens[TOKENS_COUNT]; + +extern const TokenType *UnknownToken; + +const TokenType *tokenByChainAddress(uint32_t chain_id, const uint8_t *address); + +#endif diff --git a/firmware/nem_mosaics.c.mako b/firmware/nem_mosaics.c.mako new file mode 100644 index 0000000000..9a7d77aa03 --- /dev/null +++ b/firmware/nem_mosaics.c.mako @@ -0,0 +1,36 @@ +<% +ATTRIBUTES = ( + ("name", c_str), + ("ticker", lambda s: c_str(" " + s) if s else "NULL"), + ("namespace", c_str), + ("mosaic", c_str), + ("divisibility", int), + ("levy", lambda s: "NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_" + s), + ("fee", int), + ("levy_namespace", c_str), + ("levy_mosaic", c_str), +) +%>\ +// This file is automatically generated from nem_mosaics.c.mako +// DO NOT EDIT + +#include "nem_mosaics.h" + +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = { +% for m in supported_on("trezor1", nem): +{ + % for attr, func in ATTRIBUTES: + % if attr in m: + .has_${attr} = true, + .${attr} = ${func(m[attr])}, + % endif + % endfor + % if "networks" in m: + .networks_count = ${len(m["networks"])}, + .networks = { ${", ".join(map(str, m["networks"]))} }, + % endif +}, +% endfor +}; + +const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h.mako b/firmware/nem_mosaics.h.mako new file mode 100644 index 0000000000..de4aaa0483 --- /dev/null +++ b/firmware/nem_mosaics.h.mako @@ -0,0 +1,15 @@ +// This file is automatically generated from nem_mosaics.h.mako +// DO NOT EDIT + +#ifndef __NEM_MOSAICS_H__ +#define __NEM_MOSAICS_H__ + +#include "messages-nem.pb.h" + +<% nem_list = list(supported_on("trezor1", nem)) %>\ +#define NEM_MOSAIC_DEFINITIONS_COUNT (${len(nem_list)}) + +extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; +extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; + +#endif diff --git a/firmware/nem_mosaics.py b/firmware/nem_mosaics.py deleted file mode 100755 index 708790dc66..0000000000 --- a/firmware/nem_mosaics.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -import json -import os -import sys - -import collections -import itertools -import numbers - -from google.protobuf import json_format - -try: - basestring -except NameError: - basestring = (str, bytes) - -HEADER_TEMPLATE = """ -// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! - -#ifndef __NEM_MOSAICS_H__ -#define __NEM_MOSAICS_H__ - -#include "messages-nem.pb.h" - -#define NEM_MOSAIC_DEFINITIONS_COUNT ({count}) - -extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; -extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; - -#endif -""".lstrip() # noqa: E501 - -CODE_TEMPLATE = """ -// This file is automatically generated by nem_mosaics.py -- DO NOT EDIT! - -#include "nem_mosaics.h" - -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = {code}; - -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; -""".lstrip() # noqa: E501 - - -def format_primitive(value): - if isinstance(value, bool): - return ("false", "true")[value] - elif isinstance(value, numbers.Number): - return str(value) - elif isinstance(value, basestring): - return json.dumps(value) - elif isinstance(value, collections.Sequence): - return "{ " + ", ".join( - format_primitive(item) for item in value - ) + " }" - else: - raise TypeError - - -def format_struct(struct): - return "{\n" + "\n".join( - "\t.{0} = {1},".format(member, value) - for member, value in struct.items() - ) + "\n}" - - -def format_field(field, value): - if field.message_type is not None: - raise TypeError - elif field.enum_type: - type_name = field.enum_type.full_name.replace('.', '_') - enum_name = field.enum_type.values_by_number[value].name - return "{0}_{1}".format(type_name, enum_name) - elif hasattr(value, "_values"): - return format_primitive(value._values) - else: - return format_primitive(value) - - -def field_to_meta(field, value): - if field.label == field.LABEL_REPEATED: - return ("{}_count".format(field.name), format_primitive(len(value))) - else: - return ("has_{}".format(field.name), format_primitive(True)) - - -def message_to_struct(_message, proto): - message = json_format.ParseDict(_message, proto()) - return collections.OrderedDict(itertools.chain.from_iterable( - ( - field_to_meta(field, value), - (field.name, format_field(field, value)), - ) for field, value in message.ListFields() - )) - - -def format_message(message, proto): - return format_struct(message_to_struct(message, proto)) - - -def format_messages(messages, proto): - return "{" + ",\n".join( - format_message(message, proto) for message in messages - ) + "}" - - -if __name__ == "__main__": - os.chdir(os.path.abspath(os.path.dirname(__file__))) - - sys.path.insert(0, "protob") - import messages_nem_pb2 - - messages = json.load(open("defs/nem/nem_mosaics.json")) - - with open("nem_mosaics.h", "w+") as f: - f.write(HEADER_TEMPLATE.format( - count=format_primitive(len(messages))) - ) - - with open("nem_mosaics.c", "w+") as f: - f.write(CODE_TEMPLATE.format( - code=format_messages(messages, messages_nem_pb2.NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition)) - ) diff --git a/vendor/trezor-common b/vendor/trezor-common index e0108d34bf..d37abab57d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit e0108d34bf4b741d9ddcf1e7b423e799a3a04b77 +Subproject commit d37abab57d6a03d611f4008af0cbfc1d5d872bd7 From 48b1a304b4433c08446ae541cd26b86c5a74e412 Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 30 Jul 2018 17:50:09 +0200 Subject: [PATCH 0959/1154] firmware/protob: exclude Monero messages --- firmware/protob/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index d915d79354..55be1abfb1 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -23,7 +23,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar -e MessageType_Monero -e MessageType_DebugMonero > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h From 7b07926b3ac2b6bf7b1436fd6ebdb1d6efbdac5a Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 30 Jul 2018 18:04:03 +0200 Subject: [PATCH 0960/1154] travis: move everything into pipenv, update to python 3.6 --- .travis.yml | 38 ++++++++++++++------------------------ Pipfile | 2 ++ Pipfile.lock | 47 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index f4f587a0ca..3278084912 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,21 @@ language: c addons: apt: + sources: + - deadsnakes packages: - build-essential - gcc-arm-none-eabi + - gcc-multilib - libnewlib-arm-none-eabi - - python3-pip + - python3.6 + - python3.6-venv + - python3.6-dev env: global: - MAKEFLAGS=-j2 - - PYTHON=python3 + - PYTHON=python3.6 - PROTOBUF_VERSION=3.4.0 matrix: - DEBUG_LINK=0 @@ -21,39 +26,24 @@ env: matrix: include: - - addons: - apt: - packages: - - gcc-multilib - - python3-pip env: - EMULATOR=1 HEADLESS=1 - DEBUG_LINK=1 - before_script: - - $PYTHON -m pip install --user pipenv - - pipenv install script: - # use outer environment (with protobuf & ecdsa) to build, - # then use pipenv to run tests - - ./script/cibuild && pipenv run script/test - -# using two "separate" python environments is somewhat unwieldy, and it would be nicer -# to consolidate everything into one. -# Unfortunately, installing pipenv and fetching python-trezor from git takes about one minute. -# For now, we keep the envs separate. If the number of "outer" modules grows significantly, -# they should probably be moved into pipenv. + - pipenv run ./script/cibuild && pipenv run script/test install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc - export PATH="$(pwd)/protoc/bin:$PATH" - - $PYTHON -m pip install --user "protobuf==${PROTOBUF_VERSION}" - - $PYTHON -m pip install --user ecdsa # for firmware_sign + - $PYTHON -m ensurepip --user + - $PYTHON -m pip install --user pipenv + - pipenv install script: - - script/cibuild - - make -C bootloader - - make -C demo + - pipenv run script/cibuild + - pipenv run make -C bootloader + - pipenv run make -C demo notifications: webhooks: diff --git a/Pipfile b/Pipfile index 4f11b4fc27..ba4ee323c8 100644 --- a/Pipfile +++ b/Pipfile @@ -10,3 +10,5 @@ pytest = "*" mock = "*" typing = "*" protobuf = "==3.4.0" +mako = "*" +munch = "*" diff --git a/Pipfile.lock b/Pipfile.lock index eab7261173..cd379ed76a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "495d8a64b9cfa1479cf756fc05dddbf8ca34a12186478ee46a7fa8aba140e0cb" + "sha256": "0c77aa21c1e385d7c3833a2f95bc6129394f6d9ce67e1181700a76a5e15074cb" }, "pipfile-spec": 6, "requires": {}, @@ -65,9 +65,22 @@ }, "libusb1": { "hashes": [ - "sha256:8c930d9c1d037d9c83924c82608aa6a1adcaa01ca0e4a23ee0e8e18d7eee670d" + "sha256:4707f81e933a97fed1c5bf7d4957f07bae1139cb8084bdee1f50201a40e3fd7c" ], - "version": "==1.6.4" + "version": "==1.6.5" + }, + "mako": { + "hashes": [ + "sha256:4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae" + ], + "index": "pypi", + "version": "==1.0.7" + }, + "markupsafe": { + "hashes": [ + "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" + ], + "version": "==1.0" }, "mnemonic": { "hashes": [ @@ -91,6 +104,13 @@ ], "version": "==4.2.0" }, + "munch": { + "hashes": [ + "sha256:6ae3d26b837feacf732fb8aa5b842130da1daf221f5af9f9d4b2a0a6414b0d51" + ], + "index": "pypi", + "version": "==2.3.2" + }, "pbkdf2": { "hashes": [ "sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979" @@ -99,23 +119,22 @@ }, "pbr": { "hashes": [ - "sha256:4f2b11d95917af76e936811be8361b2b19616e5ef3b55956a429ec7864378e0c", - "sha256:e0f23b61ec42473723b2fec2f33fb12558ff221ee551962f01dd4de9053c2055" + "sha256:1b8be50d938c9bb75d0eaf7eda111eec1bf6dc88a62a6412e33bf077457e0f45", + "sha256:b486975c0cafb6beeb50ca0e17ba047647f229087bd74e37f4a7e2cac17d2caa" ], - "version": "==4.1.0" + "version": "==4.2.0" }, "pluggy": { "hashes": [ - "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", - "sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", - "sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" + "sha256:6e3836e39f4d36ae72840833db137f7b7d35105079aee6ec4a62d9f80d594dd1", + "sha256:95eb8364a4708392bae89035f45341871286a333f749c3141c20573d2b3876e1" ], - "version": "==0.6.0" + "markers": "python_version != '3.2.*' and python_version != '3.1.*' and python_version >= '2.7' and python_version != '3.0.*' and python_version != '3.3.*'", + "version": "==0.7.1" }, "protobuf": { "hashes": [ "sha256:1fcb9b704bc2e30767352d86b2664d8f65f8ed49654d7a80e7a150739724e80a", - "sha256:36d871fa54ec039b9153e7cbae1fa52a7cfdcd8105e47fb7efc8292b131d0a5c", "sha256:41c4555d9754b985352ce5289fa3ba6b21ed715f595111e46e2b90ca53112475", "sha256:4d4815467f8a61b06d648699842b233017b201f7a16275d680ec5480f10e30e9", "sha256:5b816951df388f4ab2adbd3f9ae5619b9a5d7033d14b005c345dc3ee88a7faf4", @@ -149,11 +168,11 @@ }, "pytest": { "hashes": [ - "sha256:0453c8676c2bee6feb0434748b068d5510273a916295fd61d306c4f22fbfd752", - "sha256:4b208614ae6d98195430ad6bde03641c78553acee7c83cec2e85d613c0cd383d" + "sha256:341ec10361b64a24accaec3c7ba5f7d5ee1ca4cebea30f76fad3dd12db9f0541", + "sha256:952c0389db115437f966c4c2079ae9d54714b9455190e56acebe14e8c38a7efa" ], "index": "pypi", - "version": "==3.6.3" + "version": "==3.6.4" }, "requests": { "hashes": [ From c17cec93f7ba64b3e6e7773da2bdc78ef7e2bcac Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 27 Aug 2018 19:06:11 +0200 Subject: [PATCH 0961/1154] firmware: use flattened protobuf symbols --- firmware/crypto.c | 4 +- firmware/crypto.h | 2 +- firmware/ethereum.c | 36 ++--- firmware/fsm.c | 46 +++---- firmware/fsm.h | 5 +- firmware/fsm_msg_coin.h | 28 ++-- firmware/fsm_msg_common.h | 56 ++++---- firmware/fsm_msg_crypto.h | 38 +++--- firmware/fsm_msg_ethereum.h | 14 +- firmware/fsm_msg_nem.h | 26 ++-- firmware/fsm_msg_stellar.h | 74 +++++------ firmware/layout2.c | 12 +- firmware/layout2.h | 6 +- firmware/messages.c | 10 +- firmware/nem2.c | 162 +++++++++++------------ firmware/nem2.h | 52 ++++---- firmware/nem_mosaics.c.mako | 6 +- firmware/nem_mosaics.h.mako | 4 +- firmware/protect.c | 18 +-- firmware/protect.h | 2 +- firmware/protob/Makefile | 7 +- firmware/protob/messages-bitcoin.options | 34 ++--- firmware/protob/messages-nem.options | 52 ++++---- firmware/protob/messages-stellar.options | 3 - firmware/recovery.c | 26 ++-- firmware/reset.c | 14 +- firmware/signing.c | 158 +++++++++++----------- firmware/signing.h | 2 +- firmware/stellar.c | 54 ++++---- firmware/transaction.c | 50 +++---- firmware/transaction.h | 26 ++-- vendor/nanopb | 2 +- 32 files changed, 514 insertions(+), 515 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 1643acb5b1..e538aeb608 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -335,7 +335,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le } */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const MultisigRedeemScriptType_HDNodePathType *hdnodepath) +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath) { if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; static HDNode node; @@ -365,7 +365,7 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { - static const MultisigRedeemScriptType_HDNodePathType *ptr[15], *swap; + static const HDNodePathType *ptr[15], *swap; const uint32_t n = multisig->pubkeys_count; if (n < 1 || n > 15) { return 0; diff --git a/firmware/crypto.h b/firmware/crypto.h index f6133b3609..feb1c4c370 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -52,7 +52,7 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const MultisigRedeemScriptType_HDNodePathType *hdnodepath); +uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath); int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); diff --git a/firmware/ethereum.c b/firmware/ethereum.c index fffb81021f..fc7f4dcbee 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -192,7 +192,7 @@ static void send_signature(void) keccak_Final(&keccak_ctx, hash); if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); ethereum_signing_abort(); return; } @@ -446,7 +446,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) /* eip-155 chain id */ if (msg->has_chain_id) { if (msg->chain_id < 1) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Chain Id out of bounds")); + fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); ethereum_signing_abort(); return; } @@ -460,7 +460,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->tx_type == 1 || msg->tx_type == 6) { tx_type = msg->tx_type; } else { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Txtype out of bounds")); + fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); ethereum_signing_abort(); return; } @@ -470,7 +470,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_data_length && msg->data_length > 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); + fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); ethereum_signing_abort(); return; } @@ -478,7 +478,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) * prevent exceeding the limit we use a stricter limit on data length. */ if (msg->data_length > 16000000) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Data length exceeds limit")); + fsm_sendFailure(FailureType_Failure_DataError, _("Data length exceeds limit")); ethereum_signing_abort(); return; } @@ -487,14 +487,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) data_total = 0; } if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid size of initial chunk")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid size of initial chunk")); ethereum_signing_abort(); return; } // safety checks if (!ethereum_signing_check(msg)) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Safety check failed")); + fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed")); ethereum_signing_abort(); return; } @@ -513,16 +513,16 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL); } - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } if (token == NULL && data_total > 0) { layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -531,8 +531,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes, msg->gas_price.size, msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ethereum_signing_abort(); return; } @@ -587,19 +587,19 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { if (!ethereum_signing) { - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); layoutHome(); return; } if (tx->data_chunk.size > data_left) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Too much data")); + fsm_sendFailure(FailureType_Failure_DataError, _("Too much data")); ethereum_signing_abort(); return; } if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Empty data chunk received")); + fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received")); ethereum_signing_abort(); return; } @@ -657,7 +657,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu uint8_t v; if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); return; } @@ -670,7 +670,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu int ethereum_message_verify(EthereumVerifyMessage *msg) { if (msg->signature.size != 65 || msg->address.size != 20) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Malformed data")); + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); return 1; } diff --git a/firmware/fsm.c b/firmware/fsm.c index f7d4dffd72..04c1ae5bc1 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -70,13 +70,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_INITIALIZED \ if (!storage_isInitialized()) { \ - fsm_sendFailure(Failure_FailureType_Failure_NotInitialized, NULL); \ + fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ return; \ } #define CHECK_NOT_INITIALIZED \ if (storage_isInitialized()) { \ - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ return; \ } @@ -94,7 +94,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define CHECK_PARAM(cond, errormsg) \ if (!(cond)) { \ - fsm_sendFailure(Failure_FailureType_Failure_DataError, (errormsg)); \ + fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ layoutHome(); \ return; \ } @@ -110,9 +110,9 @@ void fsm_sendSuccess(const char *text) } #if DEBUG_LINK -void fsm_sendFailureDebug(Failure_FailureType code, const char *text, const char *source) +void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) #else -void fsm_sendFailure(Failure_FailureType code, const char *text) +void fsm_sendFailure(FailureType code, const char *text) #endif { if (protectAbortedByCancel) { @@ -128,43 +128,43 @@ void fsm_sendFailure(Failure_FailureType code, const char *text) resp->code = code; if (!text) { switch (code) { - case Failure_FailureType_Failure_UnexpectedMessage: + case FailureType_Failure_UnexpectedMessage: text = _("Unexpected message"); break; - case Failure_FailureType_Failure_ButtonExpected: + case FailureType_Failure_ButtonExpected: text = _("Button expected"); break; - case Failure_FailureType_Failure_DataError: + case FailureType_Failure_DataError: text = _("Data error"); break; - case Failure_FailureType_Failure_ActionCancelled: + case FailureType_Failure_ActionCancelled: text = _("Action cancelled by user"); break; - case Failure_FailureType_Failure_PinExpected: + case FailureType_Failure_PinExpected: text = _("PIN expected"); break; - case Failure_FailureType_Failure_PinCancelled: + case FailureType_Failure_PinCancelled: text = _("PIN cancelled"); break; - case Failure_FailureType_Failure_PinInvalid: + case FailureType_Failure_PinInvalid: text = _("PIN invalid"); break; - case Failure_FailureType_Failure_InvalidSignature: + case FailureType_Failure_InvalidSignature: text = _("Invalid signature"); break; - case Failure_FailureType_Failure_ProcessError: + case FailureType_Failure_ProcessError: text = _("Process error"); break; - case Failure_FailureType_Failure_NotEnoughFunds: + case FailureType_Failure_NotEnoughFunds: text = _("Not enough funds"); break; - case Failure_FailureType_Failure_NotInitialized: + case FailureType_Failure_NotInitialized: text = _("Device not initialized"); break; - case Failure_FailureType_Failure_PinMismatch: + case FailureType_Failure_PinMismatch: text = _("PIN mismatch"); break; - case Failure_FailureType_Failure_FirmwareError: + case FailureType_Failure_FirmwareError: text = _("Firmware error"); break; } @@ -193,7 +193,7 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name) coin = coinByName("Bitcoin"); } if (!coin) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid coin name")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); layoutHome(); return 0; } @@ -207,7 +207,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, *fingerprint = 0; } if (!storage_getRootNode(&node, curve, true)) { - fsm_sendFailure(Failure_FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); + fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); return 0; } @@ -215,7 +215,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); layoutHome(); return 0; } @@ -231,11 +231,11 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore display_addr += prefixlen; } layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count); - if (protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Address, false)) { + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { return true; } if (protectAbortedByCancel || protectAbortedByInitialize) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return false; } diff --git a/firmware/fsm.h b/firmware/fsm.h index 8d6bc5096e..d7d89e840e 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -33,11 +33,11 @@ void fsm_sendSuccess(const char *text); #if DEBUG_LINK -void fsm_sendFailureDebug(Failure_FailureType code, const char *text, const char *source); +void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); #define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") #else -void fsm_sendFailure(Failure_FailureType code, const char *text); +void fsm_sendFailure(FailureType code, const char *text); #endif void fsm_msgInitialize(Initialize *msg); @@ -89,7 +89,6 @@ void fsm_msgCosiSign(CosiSign *msg); // Stellar /* void fsm_msgStellarGetAddress(StellarGetAddress *msg); -void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg); void fsm_msgStellarSignTx(StellarSignTx *msg); void fsm_msgStellarPaymentOp(StellarPaymentOp *msg); void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg); diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 7123ce0e19..6152edb4ac 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -39,8 +39,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) if (msg->has_show_display && msg->show_display) { layoutPublicKey(node->public_key); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -184,7 +184,7 @@ void fsm_msgGetAddress(GetAddress *msg) layoutProgress(_("Computing address"), 0); } if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Can't encode address")); + fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); layoutHome(); return; } @@ -207,8 +207,8 @@ void fsm_msgGetAddress(GetAddress *msg) if (mismatch) { layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -235,8 +235,8 @@ void fsm_msgSignMessage(SignMessage *msg) CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -253,7 +253,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->has_address = true; hdnode_fill_public_key(node); if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error computing address")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); layoutHome(); return; } @@ -261,7 +261,7 @@ void fsm_msgSignMessage(SignMessage *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error signing message")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); } layoutHome(); } @@ -276,20 +276,20 @@ void fsm_msgVerifyMessage(VerifyMessage *msg) layoutProgressSwipe(_("Verifying"), 0); if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { layoutVerifyAddress(coin, msg->address); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } fsm_sendSuccess(_("Message verified")); } else { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid signature")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); } layoutHome(); } diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 0c6c5416b0..e9795c79f6 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -80,8 +80,8 @@ void fsm_msgPing(Ping *msg) if (msg->has_button_protection && msg->button_protection) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -93,7 +93,7 @@ void fsm_msgPing(Ping *msg) if (msg->has_passphrase_protection && msg->passphrase_protection) { if (!protectPassphrase()) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } } @@ -123,8 +123,8 @@ void fsm_msgChangePin(ChangePin *msg) layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); } } - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -139,7 +139,7 @@ void fsm_msgChangePin(ChangePin *msg) if (protectChangePin()) { fsm_sendSuccess(_("PIN changed")); } else { - fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); } } layoutHome(); @@ -149,8 +149,8 @@ void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -165,8 +165,8 @@ void fsm_msgGetEntropy(GetEntropy *msg) { #if !DEBUG_RNG layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -187,15 +187,15 @@ void fsm_msgLoadDevice(LoadDevice *msg) CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); + fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); layoutHome(); return; } @@ -249,7 +249,7 @@ void fsm_msgCancel(Cancel *msg) recovery_abort(); signing_abort(); ethereum_signing_abort(); - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } void fsm_msgClearSession(ClearSession *msg) @@ -269,32 +269,32 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_language) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_use_passphrase) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_homescreen) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -302,8 +302,8 @@ void fsm_msgApplySettings(ApplySettings *msg) if (msg->has_auto_lock_delay_ms) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -350,8 +350,8 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) if (!dry_run) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -378,8 +378,8 @@ void fsm_msgWordAck(WordAck *msg) void fsm_msgSetU2FCounter(SetU2FCounter *msg) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index 486dd74e38..2d3ddc059e 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -35,8 +35,8 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { layoutCipherKeyValue(encrypt, msg->key); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -72,8 +72,8 @@ void fsm_msgSignIdentity(SignIdentity *msg) CHECK_INITIALIZED layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -82,7 +82,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid identity")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -136,7 +136,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); } else { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error signing identity")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); } layoutHome(); } @@ -148,8 +148,8 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) CHECK_INITIALIZED layoutDecryptIdentity(&msg->identity); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -158,7 +158,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid identity")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); layoutHome(); return; } @@ -184,7 +184,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) resp->session_key.size = result_size; msg_write(MessageType_MessageType_ECDHSessionKey, resp); } else { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error getting ECDH session key")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); } layoutHome(); } @@ -216,14 +216,14 @@ void fsm_msgEncryptMessage(EncryptMessage *msg) hdnode_get_address_raw(node, coin->address_type, address_raw); } layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutProgressSwipe(_("Encrypting"), 0); if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error encrypting message")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); layoutHome(); return; } @@ -257,7 +257,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) bool signing = false; uint8_t address_raw[MAX_ADDR_RAW_SIZE]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -265,7 +265,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg) base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); } layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); - protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequestType_ButtonRequest_Other, true); if (display_only) { resp->has_address = false; resp->has_message = false; @@ -289,8 +289,8 @@ void fsm_msgCosiCommit(CosiCommit *msg) CHECK_PARAM(msg->has_data, _("No data provided")); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -329,8 +329,8 @@ void fsm_msgCosiSign(CosiSign *msg) CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index f39a9659fb..6571d7035f 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -82,8 +82,8 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) CHECK_INITIALIZED layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -103,21 +103,21 @@ void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) CHECK_PARAM(msg->has_message, _("No message provided")); if (ethereum_message_verify(msg) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid signature")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); return; } char address[43] = { '0', 'x' }; ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); layoutVerifyAddress(NULL, address); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h index 83665bcca5..878b6829b5 100644 --- a/firmware/fsm_msg_nem.h +++ b/firmware/fsm_msg_nem.h @@ -96,7 +96,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } @@ -109,7 +109,7 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { hdnode_fill_public_key(node); - const NEMSignTx_NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; char address[NEM_ADDRESS_SIZE + 1]; hdnode_get_nem_address(node, common->network, address); @@ -119,37 +119,37 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { } if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); + fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); layoutHome(); return; } @@ -260,8 +260,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) _("Decrypt message"), _("Confirm address?"), address); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -286,7 +286,7 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) size, resp->payload.bytes); if (!ret) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to decrypt payload")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); layoutHome(); return; } @@ -295,8 +295,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index e27aadcfd6..4e967ae32d 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -27,7 +27,7 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); if (!node) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); return; } @@ -40,8 +40,8 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) NULL, NULL, NULL ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } @@ -55,47 +55,47 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) layoutHome(); } -void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) -{ - RESP_INIT(StellarPublicKey); +// void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) +// { +// RESP_INIT(StellarPublicKey); - CHECK_INITIALIZED +// CHECK_INITIALIZED - CHECK_PIN +// CHECK_PIN - HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); - if (!node) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to derive private key")); - return; - } +// HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); +// if (!node) { +// fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); +// return; +// } - if (msg->has_show_display && msg->show_display) { - char hex[32 * 2 + 1]; - data2hex(node->public_key + 1, 32, hex); - const char **str_pubkey_rows = split_message((const uint8_t *)hex, 32 * 2, 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), - str_pubkey_rows[0], - str_pubkey_rows[1], - str_pubkey_rows[2], - str_pubkey_rows[3], - NULL, NULL - ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } +// if (msg->has_show_display && msg->show_display) { +// char hex[32 * 2 + 1]; +// data2hex(node->public_key + 1, 32, hex); +// const char **str_pubkey_rows = split_message((const uint8_t *)hex, 32 * 2, 16); +// layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), +// str_pubkey_rows[0], +// str_pubkey_rows[1], +// str_pubkey_rows[2], +// str_pubkey_rows[3], +// NULL, NULL +// ); +// if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { +// fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); +// layoutHome(); +// return; +// } +// } - // Read public key and write it to the response - resp->has_public_key = true; - resp->public_key.size = 32; - memcpy(resp->public_key.bytes, node->public_key + 1, 32); +// // Read public key and write it to the response +// resp->has_public_key = true; +// resp->public_key.size = 32; +// memcpy(resp->public_key.bytes, node->public_key + 1, 32); - msg_write(MessageType_MessageType_StellarPublicKey, resp); +// msg_write(MessageType_MessageType_StellarPublicKey, resp); - layoutHome(); -} +// layoutHome(); +// } void fsm_msgStellarSignTx(StellarSignTx *msg) { diff --git a/firmware/layout2.c b/firmware/layout2.c index 7ad7e27aac..ae371e0a2c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -286,7 +286,7 @@ static void render_address_dialog(const CoinInfo *coin, const char *address, con oledRefresh(); } -void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out) +void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { char str_out[32 + 3]; bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); @@ -718,7 +718,7 @@ void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, NULL); } -void layoutNEMTransferMosaic(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { char str_out[32], str_levy[32]; nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); @@ -787,8 +787,8 @@ void layoutNEMMosaicDescription(const char *description) { str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint8_t network) { - const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *mosaic; +void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { + const NEMMosaicDefinition *mosaic; if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic, network)) { mosaic = definition; } else { @@ -803,7 +803,7 @@ void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *defini char str_out[32]; switch (definition->levy) { - case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Percentile: + case NEMMosaicLevy_MosaicLevy_Percentile: bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, @@ -818,7 +818,7 @@ void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *defini NULL); break; - case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Absolute: + case NEMMosaicLevy_MosaicLevy_Absolute: default: nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out)); layoutDialogSwipe(&bmp_icon_question, diff --git a/firmware/layout2.h b/firmware/layout2.h index 5c38ad5c22..84e96fc95c 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -43,7 +43,7 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); -void layoutConfirmOutput(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *out); +void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); @@ -63,11 +63,11 @@ void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appico void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); -void layoutNEMTransferMosaic(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); void layoutNEMMosaicDescription(const char *description); -void layoutNEMLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint8_t network); +void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); diff --git a/firmware/messages.c b/firmware/messages.c index 69473ef5d7..3d4500240f 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -226,7 +226,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * if (status) { MessageProcessFunc(type, 'i', msg_id, msg_data); } else { - fsm_sendFailure(Failure_FailureType_Failure_DataError, stream.errmsg); + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); } } @@ -250,11 +250,11 @@ void msg_read_common(char type, const uint8_t *buf, uint32_t len) fields = MessageFields(type, 'i', msg_id); if (!fields) { // unknown message - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Unknown message")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); return; } if (msg_size > MSG_IN_SIZE) { // message is too big :( - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Message too big")); + fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); return; } @@ -362,11 +362,11 @@ void msg_read_tiny(const uint8_t *buf, int len) if (status) { msg_tiny_id = msg_id; } else { - fsm_sendFailure(Failure_FailureType_Failure_DataError, stream.errmsg); + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); msg_tiny_id = 0xFFFF; } } else { - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Unknown message")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); msg_tiny_id = 0xFFFF; } } diff --git a/firmware/nem2.c b/firmware/nem2.c index b973136742..216791a56f 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -27,7 +27,7 @@ #include "rng.h" #include "secp256k1.h" -const char *nem_validate_common(NEMSignTx_NEMTransactionCommon *common, bool inner) { +const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { if (!common->has_network) { common->has_network = true; common->network = NEM_NETWORK_MAINNET; @@ -60,7 +60,7 @@ const char *nem_validate_common(NEMSignTx_NEMTransactionCommon *common, bool inn return NULL; } -const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t network) { +const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { if (!transfer->has_recipient) return _("No recipient provided"); if (!transfer->has_amount) return _("No amount provided"); @@ -71,7 +71,7 @@ const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMMosaic *mosaic = &transfer->mosaics[i]; if (!mosaic->has_namespace) return _("No mosaic namespace provided"); if (!mosaic->has_mosaic) return _("No mosaic name provided"); @@ -81,7 +81,7 @@ const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t return NULL; } -const char *nem_validate_provision_namespace(const NEMSignTx_NEMProvisionNamespace *provision_namespace, uint8_t network) { +const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network) { if (!provision_namespace->has_namespace) return _("No namespace provided"); if (!provision_namespace->has_sink) return _("No rental sink provided"); if (!provision_namespace->has_fee) return _("No rental sink fee provided"); @@ -91,7 +91,7 @@ const char *nem_validate_provision_namespace(const NEMSignTx_NEMProvisionNamespa return NULL; } -const char *nem_validate_mosaic_creation(const NEMSignTx_NEMMosaicCreation *mosaic_creation, uint8_t network) { +const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) { if (!mosaic_creation->has_definition) return _("No mosaic definition provided"); if (!mosaic_creation->has_sink) return _("No creation sink provided"); if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); @@ -126,7 +126,7 @@ const char *nem_validate_mosaic_creation(const NEMSignTx_NEMMosaicCreation *mosa return NULL; } -const char *nem_validate_supply_change(const NEMSignTx_NEMMosaicSupplyChange *supply_change) { +const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change) { if (!supply_change->has_namespace) return _("No namespace provided"); if (!supply_change->has_mosaic) return _("No mosaic provided"); if (!supply_change->has_type) return _("No type provided"); @@ -135,19 +135,19 @@ const char *nem_validate_supply_change(const NEMSignTx_NEMMosaicSupplyChange *su return NULL; } -const char *nem_validate_aggregate_modification(const NEMSignTx_NEMAggregateModification *aggregate_modification, bool creation) { +const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation) { if (creation && aggregate_modification->modifications_count == 0) { return _("No modifications provided"); } for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; if (!modification->has_type) return _("No modification type provided"); if (!modification->has_public_key) return _("No cosignatory public key provided"); if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided"); - if (creation && modification->type == NEMSignTx_NEMAggregateModification_NEMCosignatoryModification_NEMModificationType_CosignatoryModification_Delete) { + if (creation && modification->type == NEMModificationType_CosignatoryModification_Delete) { return _("Cannot remove cosignatory when converting account"); } } @@ -155,7 +155,7 @@ const char *nem_validate_aggregate_modification(const NEMSignTx_NEMAggregateModi return NULL; } -const char *nem_validate_importance_transfer(const NEMSignTx_NEMImportanceTransfer *importance_transfer) { +const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer) { if (!importance_transfer->has_mode) return _("No mode provided"); if (!importance_transfer->has_public_key) return _("No remote account provided"); if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided"); @@ -163,15 +163,15 @@ const char *nem_validate_importance_transfer(const NEMSignTx_NEMImportanceTransf return NULL; } -bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer, const char *desc) { +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { if (transfer->mosaics_count) { - const NEMSignTx_NEMTransfer_NEMMosaic *xem = NULL; + const NEMMosaic *xem = NULL; bool unknownMosaic = false; - const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definitions[transfer->mosaics_count]; + const NEMMosaicDefinition *definitions[transfer->mosaics_count]; for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMMosaic *mosaic = &transfer->mosaics[i]; definitions[i] = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); @@ -196,18 +196,18 @@ bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSign NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMMosaic *mosaic = &transfer->mosaics[i]; if (mosaic == xem) { continue; @@ -219,20 +219,20 @@ bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSign layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaic->quantity, &multiplier); } - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } } else { layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } if (transfer->has_payload) { layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, transfer->has_public_key); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -243,14 +243,14 @@ bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSign desc, _("Confirm transfer to"), transfer->recipient); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer) { +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) { static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; const uint8_t *payload = transfer->payload.bytes; @@ -258,7 +258,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM if (transfer->has_public_key) { if (node == NULL) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); return false; } @@ -277,7 +277,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM buffer); if (!ret) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to encrypt payload")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload")); return false; } @@ -299,12 +299,12 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM transfer->mosaics_count); if (!ret) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); return false; } for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &transfer->mosaics[i]; + const NEMMosaic *mosaic = &transfer->mosaics[i]; ret = nem_transaction_write_mosaic(context, mosaic->namespace, @@ -312,7 +312,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM mosaic->quantity); if (!ret) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to attach mosaics")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics")); return false; } } @@ -320,7 +320,7 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM return true; } -bool nem_askProvisionNamespace(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace, const char *desc) { +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -331,19 +331,19 @@ bool nem_askProvisionNamespace(const NEMSignTx_NEMTransactionCommon *common, con provision_namespace->has_parent ? provision_namespace->parent : NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), provision_namespace->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace) { +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) { return nem_transaction_create_provision_namespace(context, common->network, common->timestamp, @@ -356,7 +356,7 @@ bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMSignTx_NEM provision_namespace->fee); } -bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { +bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -367,12 +367,12 @@ bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const N mosaic_creation->definition.namespace, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMMosaicDescription(mosaic_creation->definition.description); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -397,13 +397,13 @@ bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const N mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"), NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } if (mosaic_creation->definition.has_levy) { layoutNEMLevy(&mosaic_creation->definition, common->network); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -427,20 +427,20 @@ bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const N mosaic_creation->definition.levy_address); } - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation) { +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) { return nem_transaction_create_mosaic_creation(context, common->network, common->timestamp, @@ -463,7 +463,7 @@ bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMSignTx_NEMTran mosaic_creation->fee); } -bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change, const char *desc) { +bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), @@ -474,7 +474,7 @@ bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEM supply_change->namespace, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } @@ -485,25 +485,25 @@ bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEM _("Cancel"), _("Next"), desc, - supply_change->type == NEMSignTx_NEMMosaicSupplyChange_NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), + supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), str_out, _("whole units"), NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change) { +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) { return nem_transaction_create_mosaic_supply_change(context, common->network, common->timestamp, @@ -516,7 +516,7 @@ bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMSignTx_NEMTransa supply_change->delta); } -bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { +bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { if (creation) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), @@ -528,7 +528,7 @@ bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -536,16 +536,16 @@ bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, char address[NEM_ADDRESS_SIZE + 1]; for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; nem_get_address(modification->public_key.bytes, common->network, address); layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Next"), desc, - modification->type == NEMSignTx_NEMAggregateModification_NEMCosignatoryModification_NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), + modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), address); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } @@ -572,20 +572,20 @@ bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification) { +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) { bool ret = nem_transaction_create_aggregate_modification(context, common->network, common->timestamp, @@ -597,7 +597,7 @@ bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_ if (!ret) return false; for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMSignTx_NEMAggregateModification_NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; ret = nem_transaction_write_cosignatory_modification(context, modification->type, @@ -613,30 +613,30 @@ bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_ return true; } -bool nem_askImportanceTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer, const char *desc) { +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, - importance_transfer->mode == NEMSignTx_NEMImportanceTransfer_NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), + importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), _("harvesting?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { return false; } return true; } -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer) { +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) { return nem_transaction_create_importance_transfer(context, common->network, common->timestamp, @@ -654,19 +654,19 @@ bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint desc, cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), address); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return false; } return true; } -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { bool ret; if (cosigning) { ret = nem_transaction_create_multisig_signature(context, @@ -687,16 +687,16 @@ bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMSignTx_NEMTransactio } if (!ret) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); return false; } return true; } -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { - const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; + const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; if (nem_mosaicMatches(definition, namespace, mosaic, network)) { return definition; @@ -706,7 +706,7 @@ const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *nem_mosaicByName(const ch return NULL; } -static inline size_t format_amount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { +static inline size_t format_amount(const NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { bignum256 val; memcpy(&val, amnt, sizeof(bignum256)); @@ -725,7 +725,7 @@ static inline size_t format_amount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDe size); } -size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t mosaics_count) { +size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { if (mosaics_count <= 1) { return mosaics_count; } @@ -739,16 +739,16 @@ size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t for (size_t i = 0; i < mosaics_count; i++) { if (skip[i]) continue; - NEMSignTx_NEMTransfer_NEMMosaic *mosaic = &mosaics[actual_count]; + NEMMosaic *mosaic = &mosaics[actual_count]; if (actual_count++ != i) { - memcpy(mosaic, &mosaics[i], sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); + memcpy(mosaic, &mosaics[i], sizeof(NEMMosaic)); } for (size_t j = i + 1; j < mosaics_count; j++) { if (skip[j]) continue; - const NEMSignTx_NEMTransfer_NEMMosaic *new_mosaic = &mosaics[j]; + const NEMMosaic *new_mosaic = &mosaics[j]; if (nem_mosaicCompare(mosaic, new_mosaic) == 0) { skip[j] = true; @@ -757,19 +757,19 @@ size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t } } - NEMSignTx_NEMTransfer_NEMMosaic temp; + NEMMosaic temp; // Sort mosaics for (size_t i = 0; i < actual_count - 1; i++) { - NEMSignTx_NEMTransfer_NEMMosaic *a = &mosaics[i]; + NEMMosaic *a = &mosaics[i]; for (size_t j = i + 1; j < actual_count; j++) { - NEMSignTx_NEMTransfer_NEMMosaic *b = &mosaics[j]; + NEMMosaic *b = &mosaics[j]; if (nem_mosaicCompare(a, b) > 0) { - memcpy(&temp, a, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); - memcpy(a, b, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); - memcpy(b, &temp, sizeof(NEMSignTx_NEMTransfer_NEMMosaic)); + memcpy(&temp, a, sizeof(NEMMosaic)); + memcpy(a, b, sizeof(NEMMosaic)); + memcpy(b, &temp, sizeof(NEMMosaic)); } } } @@ -777,14 +777,14 @@ size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t return actual_count; } -void nem_mosaicFormatAmount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { bignum256 amnt; bn_read_uint64(quantity, &amnt); format_amount(definition, &amnt, multiplier, 0, str_out, size); } -bool nem_mosaicFormatLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { if (!definition->has_levy || !definition->has_fee) { return false; } @@ -793,13 +793,13 @@ bool nem_mosaicFormatLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition bn_read_uint64(quantity, &amnt); bn_read_uint64(definition->fee, &fee); - const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); + const NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); switch (definition->levy) { - case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Absolute: + case NEMMosaicLevy_MosaicLevy_Absolute: return format_amount(mosaic, &fee, NULL, 0, str_out, size); - case NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_MosaicLevy_Percentile: + case NEMMosaicLevy_MosaicLevy_Percentile: bn_multiply(&fee, &amnt, &secp256k1.prime); return format_amount(mosaic, &amnt, multiplier, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); diff --git a/firmware/nem2.h b/firmware/nem2.h index f26f1220ff..13f0390fab 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -27,40 +27,40 @@ #include -const char *nem_validate_common(NEMSignTx_NEMTransactionCommon *common, bool inner); -const char *nem_validate_transfer(const NEMSignTx_NEMTransfer *transfer, uint8_t network); -const char *nem_validate_provision_namespace(const NEMSignTx_NEMProvisionNamespace *provision_namespace, uint8_t network); -const char *nem_validate_mosaic_creation(const NEMSignTx_NEMMosaicCreation *mosaic_creation, uint8_t network); -const char *nem_validate_supply_change(const NEMSignTx_NEMMosaicSupplyChange *supply_change); -const char *nem_validate_aggregate_modification(const NEMSignTx_NEMAggregateModification *aggregate_modification, bool creation); -const char *nem_validate_importance_transfer(const NEMSignTx_NEMImportanceTransfer *importance_transfer); +const char *nem_validate_common(NEMTransactionCommon *common, bool inner); +const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); +const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); +const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); +const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); +const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); +const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); -bool nem_askTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer, const char *desc); -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMTransfer *transfer); +bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); -bool nem_askProvisionNamespace(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace, const char *desc); -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMProvisionNamespace *provision_namespace); +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); +bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); -bool nem_askMosaicCreation(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicCreation *mosaic_creation); +bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); -bool nem_askSupplyChange(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change, const char *desc); -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMMosaicSupplyChange *supply_change); +bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); +bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); -bool nem_askAggregateModification(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification, const char *desc, bool creation); -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMAggregateModification *aggregate_modification); +bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); +bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); -bool nem_askImportanceTransfer(const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer, const char *desc); -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const NEMSignTx_NEMImportanceTransfer *importance_transfer); +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); +bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMSignTx_NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); +bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); -size_t nem_canonicalizeMosaics(NEMSignTx_NEMTransfer_NEMMosaic *mosaics, size_t mosaics_count); -void nem_mosaicFormatAmount(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); -bool nem_mosaicFormatLevy(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); +size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { strlcpy(str_out, namespace, size); @@ -68,7 +68,7 @@ static inline void nem_mosaicFormatName(const char *namespace, const char *mosai strlcat(str_out, mosaic, size); } -static inline bool nem_mosaicMatches(const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { +static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { if (definition->networks_count == 0) { return true; @@ -84,7 +84,7 @@ static inline bool nem_mosaicMatches(const NEMSignTx_NEMMosaicCreation_NEMMosaic return false; } -static inline int nem_mosaicCompare(const NEMSignTx_NEMTransfer_NEMMosaic *a, const NEMSignTx_NEMTransfer_NEMMosaic *b) { +static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) { size_t namespace_length = strlen(a->namespace); // Ensure that strlen(a->namespace) <= strlen(b->namespace) diff --git a/firmware/nem_mosaics.c.mako b/firmware/nem_mosaics.c.mako index 9a7d77aa03..fffde0499d 100644 --- a/firmware/nem_mosaics.c.mako +++ b/firmware/nem_mosaics.c.mako @@ -5,7 +5,7 @@ ATTRIBUTES = ( ("namespace", c_str), ("mosaic", c_str), ("divisibility", int), - ("levy", lambda s: "NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition_NEMMosaicLevy_" + s), + ("levy", lambda s: "NEMMosaicLevy_" + s), ("fee", int), ("levy_namespace", c_str), ("levy_mosaic", c_str), @@ -16,7 +16,7 @@ ATTRIBUTES = ( #include "nem_mosaics.h" -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = { +const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT] = { % for m in supported_on("trezor1", nem): { % for attr, func in ATTRIBUTES: @@ -33,4 +33,4 @@ const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM % endfor }; -const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; +const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM = NEM_MOSAIC_DEFINITIONS; diff --git a/firmware/nem_mosaics.h.mako b/firmware/nem_mosaics.h.mako index de4aaa0483..5667713b9c 100644 --- a/firmware/nem_mosaics.h.mako +++ b/firmware/nem_mosaics.h.mako @@ -9,7 +9,7 @@ <% nem_list = list(supported_on("trezor1", nem)) %>\ #define NEM_MOSAIC_DEFINITIONS_COUNT (${len(nem_list)}) -extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; -extern const NEMSignTx_NEMMosaicCreation_NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; +extern const NEMMosaicDefinition NEM_MOSAIC_DEFINITIONS[NEM_MOSAIC_DEFINITIONS_COUNT]; +extern const NEMMosaicDefinition *NEM_MOSAIC_DEFINITION_XEM; #endif diff --git a/firmware/protect.c b/firmware/protect.c index a9f5a1dc0a..cbce28acde 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -38,7 +38,7 @@ bool protectAbortedByCancel = false; bool protectAbortedByInitialize = false; -bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only) +bool protectButton(ButtonRequestType type, bool confirm_only) { ButtonRequest resp; bool result = false; @@ -111,7 +111,7 @@ bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only) return result; } -const char *requestPin(PinMatrixRequest_PinMatrixRequestType type, const char *text) +const char *requestPin(PinMatrixRequestType type, const char *text) { PinMatrixRequest resp; memset(&resp, 0, sizeof(PinMatrixRequest)); @@ -187,20 +187,20 @@ bool protectPin(bool use_cached) protectAbortedByInitialize = true; msg_tiny_id = 0xFFFF; usbTiny(0); - fsm_sendFailure(Failure_FailureType_Failure_PinCancelled, NULL); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } wait--; } usbTiny(0); const char *pin; - pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); if (!pin) { - fsm_sendFailure(Failure_FailureType_Failure_PinCancelled, NULL); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } if (!storage_increasePinFails(fails)) { - fsm_sendFailure(Failure_FailureType_Failure_PinInvalid, NULL); + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); return false; } if (storage_containsPin(pin)) { @@ -209,7 +209,7 @@ bool protectPin(bool use_cached) return true; } else { protectCheckMaxTry(storage_getPinWait(fails)); - fsm_sendFailure(Failure_FailureType_Failure_PinInvalid, NULL); + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); return false; } } @@ -218,7 +218,7 @@ bool protectChangePin(void) { static CONFIDENTIAL char pin_compare[17]; - const char *pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); if (!pin) { return false; @@ -226,7 +226,7 @@ bool protectChangePin(void) strlcpy(pin_compare, pin, sizeof(pin_compare)); - pin = requestPin(PinMatrixRequest_PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); const bool result = pin && (strncmp(pin_compare, pin, sizeof(pin_compare)) == 0); diff --git a/firmware/protect.h b/firmware/protect.h index db5edb0222..8a3af45108 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -23,7 +23,7 @@ #include #include "messages-common.pb.h" -bool protectButton(ButtonRequest_ButtonRequestType type, bool confirm_only); +bool protectButton(ButtonRequestType type, bool confirm_only); bool protectPin(bool use_cached); bool protectChangePin(void); bool protectPassphrase(void); diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 55be1abfb1..4d61b75527 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -8,7 +8,10 @@ PYTHON ?= python %.pb.c: %.pb %.options @printf " NANOPB $@\n" - $(Q)$(PYTHON) ../../vendor/nanopb/generator/nanopb_generator.py $< -L '#include "%s"' -T + $(Q)$(PYTHON) ../../vendor/nanopb/generator/nanopb_generator.py $< \ + -L '#include "%s"' \ + -T \ + -s "mangle_names:M_FLATTEN" %.pb: %.proto @printf " PROTOC $@\n" @@ -23,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar -e MessageType_Monero -e MessageType_DebugMonero > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Stellar -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/messages-bitcoin.options b/firmware/protob/messages-bitcoin.options index 26e06de98c..68a1817616 100644 --- a/firmware/protob/messages-bitcoin.options +++ b/firmware/protob/messages-bitcoin.options @@ -23,29 +23,29 @@ VerifyMessage.coin_name max_size:21 MessageSignature.address max_size:130 MessageSignature.signature max_size:65 -TxAck.TransactionType.inputs max_count:1 -TxAck.TransactionType.bin_outputs max_count:1 -TxAck.TransactionType.outputs max_count:1 -TxAck.TransactionType.extra_data max_size:1024 +TransactionType.inputs max_count:1 +TransactionType.bin_outputs max_count:1 +TransactionType.outputs max_count:1 +TransactionType.extra_data max_size:1024 -TxAck.TransactionType.TxInputType.address_n max_count:8 -TxAck.TransactionType.TxInputType.prev_hash max_size:32 -TxAck.TransactionType.TxInputType.script_sig max_size:1650 -TxAck.TransactionType.TxInputType.prev_block_hash_bip115 max_size:32 +TxInputType.address_n max_count:8 +TxInputType.prev_hash max_size:32 +TxInputType.script_sig max_size:1650 +TxInputType.prev_block_hash_bip115 max_size:32 -TxAck.TransactionType.TxOutputType.address max_size:130 -TxAck.TransactionType.TxOutputType.address_n max_count:8 -TxAck.TransactionType.TxOutputType.op_return_data max_size:80 -TxAck.TransactionType.TxOutputType.block_hash_bip115 max_size:32 +TxOutputType.address max_size:130 +TxOutputType.address_n max_count:8 +TxOutputType.op_return_data max_size:80 +TxOutputType.block_hash_bip115 max_size:32 -TxAck.TransactionType.TxOutputBinType.script_pubkey max_size:520 +TxOutputBinType.script_pubkey max_size:520 -TxRequest.TxRequestDetailsType.tx_hash max_size:32 +TxRequestDetailsType.tx_hash max_size:32 -TxRequest.TxRequestSerializedType.signature max_size:73 -TxRequest.TxRequestSerializedType.serialized_tx max_size:2048 +TxRequestSerializedType.signature max_size:73 +TxRequestSerializedType.serialized_tx max_size:2048 MultisigRedeemScriptType.pubkeys max_count:15 MultisigRedeemScriptType.signatures max_count:15 max_size:73 -MultisigRedeemScriptType.HDNodePathType.address_n max_count:8 +HDNodePathType.address_n max_count:8 diff --git a/firmware/protob/messages-nem.options b/firmware/protob/messages-nem.options index 546c580da1..2d7be939fe 100644 --- a/firmware/protob/messages-nem.options +++ b/firmware/protob/messages-nem.options @@ -8,41 +8,41 @@ NEMDecryptMessage.payload max_ NEMDecryptedMessage.payload max_size:1024 -NEMSignTx.NEMTransactionCommon.address_n max_count:8 -NEMSignTx.NEMTransactionCommon.signer max_size:32 +NEMTransactionCommon.address_n max_count:8 +NEMTransactionCommon.signer max_size:32 -NEMSignTx.NEMTransfer.recipient max_size:41 -NEMSignTx.NEMTransfer.public_key max_size:32 -NEMSignTx.NEMTransfer.payload max_size:1024 -NEMSignTx.NEMTransfer.mosaics max_count:16 +NEMTransfer.recipient max_size:41 +NEMTransfer.public_key max_size:32 +NEMTransfer.payload max_size:1024 +NEMTransfer.mosaics max_count:16 -NEMSignTx.NEMTransfer.NEMMosaic.namespace max_size:145 -NEMSignTx.NEMTransfer.NEMMosaic.mosaic max_size:33 +NEMMosaic.namespace max_size:145 +NEMMosaic.mosaic max_size:33 -NEMSignTx.NEMProvisionNamespace.namespace max_size:65 -NEMSignTx.NEMProvisionNamespace.parent max_size:81 -NEMSignTx.NEMProvisionNamespace.sink max_size:41 +NEMProvisionNamespace.namespace max_size:65 +NEMProvisionNamespace.parent max_size:81 +NEMProvisionNamespace.sink max_size:41 -NEMSignTx.NEMMosaicCreation.sink max_size:41 +NEMMosaicCreation.sink max_size:41 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.name max_size:32 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.ticker max_size:16 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.namespace max_size:145 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.mosaic max_size:33 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_address max_size:41 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_namespace max_size:145 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.levy_mosaic max_size:33 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.description max_size:513 -NEMSignTx.NEMMosaicCreation.NEMMosaicDefinition.networks max_count:8 +NEMMosaicDefinition.name max_size:32 +NEMMosaicDefinition.ticker max_size:16 +NEMMosaicDefinition.namespace max_size:145 +NEMMosaicDefinition.mosaic max_size:33 +NEMMosaicDefinition.levy_address max_size:41 +NEMMosaicDefinition.levy_namespace max_size:145 +NEMMosaicDefinition.levy_mosaic max_size:33 +NEMMosaicDefinition.description max_size:513 +NEMMosaicDefinition.networks max_count:8 -NEMSignTx.NEMMosaicSupplyChange.namespace max_size:145 -NEMSignTx.NEMMosaicSupplyChange.mosaic max_size:33 +NEMMosaicSupplyChange.namespace max_size:145 +NEMMosaicSupplyChange.mosaic max_size:33 -NEMSignTx.NEMAggregateModification.modifications max_count:16 +NEMAggregateModification.modifications max_count:16 -NEMSignTx.NEMAggregateModification.NEMCosignatoryModification.public_key max_size:32 +NEMCosignatoryModification.public_key max_size:32 -NEMSignTx.NEMImportanceTransfer.public_key max_size:32 +NEMImportanceTransfer.public_key max_size:32 NEMSignedTx.data max_size:2048 NEMSignedTx.signature max_size:64 diff --git a/firmware/protob/messages-stellar.options b/firmware/protob/messages-stellar.options index ecfb295f7a..ce3de65c22 100644 --- a/firmware/protob/messages-stellar.options +++ b/firmware/protob/messages-stellar.options @@ -4,9 +4,6 @@ StellarGetAddress.address_n max_count:10 StellarAddress.address max_size:57 -StellarGetPublicKey.address_n max_count:10 - -StellarPublicKey.public_key max_size:32 StellarSignTx.source_account max_size:57 StellarSignTx.address_n max_count:10 diff --git a/firmware/recovery.c b/firmware/recovery.c index 8dd2299fa0..703fb07185 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -143,9 +143,9 @@ static void recovery_request(void) { WordRequest resp; memset(&resp, 0, sizeof(WordRequest)); resp.has_type = true; - resp.type = awaiting_word == 1 ? WordRequest_WordRequestType_WordRequestType_Plain - : (word_index % 4 == 3) ? WordRequest_WordRequestType_WordRequestType_Matrix6 - : WordRequest_WordRequestType_WordRequestType_Matrix9; + resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain + : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 + : WordRequestType_WordRequestType_Matrix9; msg_write(MessageType_MessageType_WordRequest, &resp); } @@ -181,15 +181,15 @@ static void recovery_done(void) { _("The seed is valid"), _("and MATCHES"), _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequestType_ButtonRequest_Other, true); fsm_sendSuccess(_("The seed is valid and matches the one in the device")); } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is valid"), _("but does NOT MATCH"), _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); - fsm_sendFailure(Failure_FailureType_Failure_DataError, + protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendFailure(FailureType_Failure_DataError, _("The seed is valid but does not match the one in the device")); } } @@ -201,9 +201,9 @@ static void recovery_done(void) { } else { layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); - protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_Other, true); + protectButton(ButtonRequestType_ButtonRequest_Other, true); } - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); } awaiting_word = 0; layoutHome(); @@ -458,7 +458,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr if (!dry_run) { if (pin_protection && !protectChangePin()) { - fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } @@ -470,7 +470,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr storage_update(); } - if ((type & RecoveryDevice_RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { + if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { awaiting_word = 2; word_index = 0; word_pincode = 0; @@ -496,7 +496,7 @@ static void recovery_scrambledword(const char *word) if (!dry_run) { session_clear(true); } - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Wrong word retyped")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); layoutHome(); return; } @@ -515,7 +515,7 @@ static void recovery_scrambledword(const char *word) if (!dry_run) { session_clear(true); } - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Word not found in a wordlist")); + fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); layoutHome(); return; } @@ -544,7 +544,7 @@ void recovery_word(const char *word) recovery_scrambledword(word); break; default: - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); break; } } diff --git a/firmware/reset.c b/firmware/reset.c index b0013939d9..2f350e8de8 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -52,15 +52,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect if (display_random) { layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ResetDevice, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (pin_protection && !protectChangePin()) { - fsm_sendFailure(Failure_FailureType_Failure_PinMismatch, NULL); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); layoutHome(); return; } @@ -80,7 +80,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { if (!awaiting_entropy) { - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } SHA256_CTX ctx; @@ -109,7 +109,7 @@ static char current_word[10]; void reset_backup(bool separated) { if (!storage_needsBackup()) { - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } @@ -136,13 +136,13 @@ void reset_backup(bool separated) i++; } layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmWord, true)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { storage_clear_update(); session_clear(true); } layoutHome(); - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } word_pos++; diff --git a/firmware/signing.c b/firmware/signing.c index f2a0ae4edf..ddf3c7557a 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -52,8 +52,8 @@ enum { static uint32_t idx1, idx2; static uint32_t signatures; static TxRequest resp; -static TxAck_TransactionType_TxInputType input; -static TxAck_TransactionType_TxOutputBinType bin_output; +static TxInputType input; +static TxOutputBinType bin_output; static TxStruct to, tp, ti; static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check, hasher_preimage; static uint8_t CONFIDENTIAL privkey[32]; @@ -211,7 +211,7 @@ void send_req_1_input(void) { signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -222,7 +222,7 @@ void send_req_2_prev_meta(void) { signing_stage = STAGE_REQUEST_2_PREV_META; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXMETA; + resp.request_type = RequestType_TXMETA; resp.has_details = true; resp.details.has_tx_hash = true; resp.details.tx_hash.size = input.prev_hash.size; @@ -234,7 +234,7 @@ void send_req_2_prev_input(void) { signing_stage = STAGE_REQUEST_2_PREV_INPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -248,7 +248,7 @@ void send_req_2_prev_output(void) { signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXOUTPUT; + resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -262,7 +262,7 @@ void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) { signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXEXTRADATA; + resp.request_type = RequestType_TXEXTRADATA; resp.has_details = true; resp.details.has_extra_data_offset = true; resp.details.extra_data_offset = chunk_offset; @@ -278,7 +278,7 @@ void send_req_3_output(void) { signing_stage = STAGE_REQUEST_3_OUTPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXOUTPUT; + resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -289,7 +289,7 @@ void send_req_4_input(void) { signing_stage = STAGE_REQUEST_4_INPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -300,7 +300,7 @@ void send_req_4_output(void) { signing_stage = STAGE_REQUEST_4_OUTPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXOUTPUT; + resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx2; @@ -311,7 +311,7 @@ void send_req_segwit_input(void) { signing_stage = STAGE_REQUEST_SEGWIT_INPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -322,7 +322,7 @@ void send_req_segwit_witness(void) { signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -333,7 +333,7 @@ void send_req_decred_witness(void) { signing_stage = STAGE_REQUEST_DECRED_WITNESS; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXINPUT; + resp.request_type = RequestType_TXINPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -344,7 +344,7 @@ void send_req_5_output(void) { signing_stage = STAGE_REQUEST_5_OUTPUT; resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXOUTPUT; + resp.request_type = RequestType_TXOUTPUT; resp.has_details = true; resp.details.has_request_index = true; resp.details.request_index = idx1; @@ -354,7 +354,7 @@ void send_req_5_output(void) void send_req_finished(void) { resp.has_request_type = true; - resp.request_type = TxRequest_RequestType_TXFINISHED; + resp.request_type = RequestType_TXFINISHED; msg_write(MessageType_MessageType_TxRequest, &resp); } @@ -385,7 +385,7 @@ void phase2_request_next_input(void) } } -void extract_input_bip32_path(const TxAck_TransactionType_TxInputType *tinput) +void extract_input_bip32_path(const TxInputType *tinput) { if (in_address_n_count == BIP32_NOCHANGEALLOWED) { return; @@ -418,7 +418,7 @@ void extract_input_bip32_path(const TxAck_TransactionType_TxInputType *tinput) } } -bool check_change_bip32_path(const TxAck_TransactionType_TxOutputType *toutput) +bool check_change_bip32_path(const TxOutputType *toutput) { size_t count = toutput->address_n_count; @@ -435,7 +435,7 @@ bool check_change_bip32_path(const TxAck_TransactionType_TxOutputType *toutput) && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } -bool compile_input_script_sig(TxAck_TransactionType_TxInputType *tinput) +bool compile_input_script_sig(TxInputType *tinput) { if (!multisig_fp_mismatch) { // check that this is still multisig @@ -497,7 +497,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) spending = 0; change_spend = 0; authorized_amount = 0; - memset(&input, 0, sizeof(TxAck_TransactionType_TxInputType)); + memset(&input, 0, sizeof(TxInputType)); memset(&resp, 0, sizeof(TxRequest)); signing = true; @@ -544,13 +544,13 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) #define MIN(a,b) (((a)<(b))?(a):(b)) -static bool signing_check_input(TxAck_TransactionType_TxInputType *txinput) { +static bool signing_check_input(TxInputType *txinput) { /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ if (txinput->has_multisig && !multisig_fp_mismatch) { uint8_t h[32]; if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); signing_abort(); return false; } @@ -573,7 +573,7 @@ static bool signing_check_input(TxAck_TransactionType_TxInputType *txinput) { tx_sequence_hash(&hasher_sequence, txinput); if (coin->decred) { if (txinput->decred_script_version > 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); + fsm_sendFailure(FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); signing_abort(); return false; } @@ -597,7 +597,7 @@ static bool signing_check_prevtx_hash(void) { uint8_t hash[32]; tx_hash_final(&tp, hash, true); if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Encountered invalid prevhash")); + fsm_sendFailure(FailureType_Failure_DataError, _("Encountered invalid prevhash")); signing_abort(); return false; } @@ -605,7 +605,7 @@ static bool signing_check_prevtx_hash(void) { return true; } -static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { +static bool signing_check_output(TxOutputType *txoutput) { // Phase1: Check outputs // add it to hash_outputs // ask user for permission @@ -614,7 +614,7 @@ static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { bool is_change = false; if (txoutput->address_n_count > 0) { if (txoutput->has_address) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Address in change output")); + fsm_sendFailure(FailureType_Failure_DataError, _("Address in change output")); signing_abort(); return false; } @@ -637,8 +637,8 @@ static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { * to make sure the user is not tricked to use witness change output * instead of regular one therefore creating ANYONECANSPEND output */ - if ((txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS - || txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS) + if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS + || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) && txoutput->amount > authorized_amount) { is_change = false; } @@ -654,7 +654,7 @@ static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { } if (spending + txoutput->amount < spending) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return false; } @@ -664,11 +664,11 @@ static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { layoutProgress(_("Signing transaction"), progress); } if (co < 0) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } else if (co == 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return false; } @@ -689,23 +689,23 @@ static bool signing_check_output(TxAck_TransactionType_TxOutputType *txoutput) { static bool signing_check_fee(void) { // check fees if (spending > to_spend) { - fsm_sendFailure(Failure_FailureType_Failure_NotEnoughFunds, _("Not enough funds")); + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); signing_abort(); return false; } uint64_t fee = to_spend - spending; if (fee > ((uint64_t) tx_weight * coin->maxfee_kb)/4000) { layoutFeeOverThreshold(coin, fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } } // last confirmation layoutConfirmTx(coin, to_spend - change_spend, fee); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(Failure_FailureType_Failure_ActionCancelled, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); signing_abort(); return false; } @@ -748,7 +748,7 @@ static void phase1_request_next_output(void) { } } -static void signing_hash_bip143(const TxAck_TransactionType_TxInputType *txinput, uint8_t *hash) { +static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); hasher_Reset(&hasher_preimage); hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion @@ -764,7 +764,7 @@ static void signing_hash_bip143(const TxAck_TransactionType_TxInputType *txinput hasher_Final(&hasher_preimage, hash); } -static void signing_hash_zip143(const TxAck_TransactionType_TxInputType *txinput, uint8_t *hash) { +static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); hasher_Reset(&hasher_preimage); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered @@ -796,13 +796,13 @@ static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { hasher_Final(&hasher_preimage, hash); } -static bool signing_sign_hash(TxAck_TransactionType_TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { +static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; resp.serialized.has_serialized_tx = true; if (ecdsa_sign_digest(coin->curve->params, private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing failed")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); signing_abort(); return false; } @@ -813,7 +813,7 @@ static bool signing_sign_hash(TxAck_TransactionType_TxInputType *txinput, const // fill in the signature int pubkey_idx = cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); if (pubkey_idx < 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Pubkey not found in multisig script")); + fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); signing_abort(); return false; } @@ -821,7 +821,7 @@ static bool signing_sign_hash(TxAck_TransactionType_TxInputType *txinput, const txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; txinput->script_sig.size = serialize_script_multisig(coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); if (txinput->script_sig.size == 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); signing_abort(); return false; } @@ -835,7 +835,7 @@ static bool signing_sign_input(void) { uint8_t hash[32]; hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -850,19 +850,19 @@ static bool signing_sign_input(void) { return true; } -static bool signing_sign_segwit_input(TxAck_TransactionType_TxInputType *txinput) { +static bool signing_sign_segwit_input(TxInputType *txinput) { // idx1: index to sign uint8_t hash[32]; if (txinput->script_type == InputScriptType_SPENDWITNESS || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return false; } if (txinput->amount > authorized_amount) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return false; } @@ -918,7 +918,7 @@ static bool signing_sign_segwit_input(TxAck_TransactionType_TxInputType *txinput return true; } -static bool signing_sign_decred_input(TxAck_TransactionType_TxInputType *txinput) { +static bool signing_sign_decred_input(TxInputType *txinput) { uint8_t hash[32], hash_witness[32]; tx_hash_final(&ti, hash_witness, false); signing_hash_decred(hash_witness, hash); @@ -931,10 +931,10 @@ static bool signing_sign_decred_input(TxAck_TransactionType_TxInputType *txinput #define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 -void signing_txack(TxAck_TransactionType *tx) +void signing_txack(TransactionType *tx) { if (!signing) { - fsm_sendFailure(Failure_FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); layoutHome(); return; } @@ -958,11 +958,11 @@ void signing_txack(TxAck_TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - memcpy(&input, tx->inputs, sizeof(TxAck_TransactionType_TxInputType)); + memcpy(&input, tx->inputs, sizeof(TxInputType)); #if !ENABLE_SEGWIT_NONSEGWIT_MIXING // don't mix segwit and non-segwit inputs if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); + fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -970,12 +970,12 @@ void signing_txack(TxAck_TransactionType *tx) if (coin->force_bip143 || overwintered) { if (!tx->inputs[0].has_amount) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); + fsm_sendFailure(FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -992,22 +992,22 @@ void signing_txack(TxAck_TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { if (coin->decred) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred does not support Segwit")); + fsm_sendFailure(FailureType_Failure_DataError, _("Decred does not support Segwit")); signing_abort(); return; } if (!coin->has_segwit) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Segwit not enabled on this coin")); + fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); signing_abort(); return; } if (!tx->inputs[0].has_amount) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Segwit input without amount")); + fsm_sendFailure(FailureType_Failure_DataError, _("Segwit input without amount")); signing_abort(); return; } if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -1019,7 +1019,7 @@ void signing_txack(TxAck_TransactionType *tx) if (idx1 == 0) { to.is_segwit = true; } else if (to.is_segwit == false) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); + fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); signing_abort(); return; } @@ -1030,19 +1030,19 @@ void signing_txack(TxAck_TransactionType *tx) authorized_amount += tx->inputs[0].amount; phase1_request_next_input(); } else { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Wrong input script type")); + fsm_sendFailure(FailureType_Failure_DataError, _("Wrong input script type")); signing_abort(); return; } return; case STAGE_REQUEST_2_PREV_META: if (tx->outputs_cnt <= input.prev_index) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); + fsm_sendFailure(FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); signing_abort(); return; } if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } @@ -1063,7 +1063,7 @@ void signing_txack(TxAck_TransactionType *tx) case STAGE_REQUEST_2_PREV_INPUT: progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1078,18 +1078,18 @@ void signing_txack(TxAck_TransactionType *tx) case STAGE_REQUEST_2_PREV_OUTPUT: progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize output")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } if (idx2 == input.prev_index) { if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Value overflow")); + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); signing_abort(); return; } if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Decred script version does not match previous output")); + fsm_sendFailure(FailureType_Failure_DataError, _("Decred script version does not match previous output")); signing_abort(); return; } @@ -1109,7 +1109,7 @@ void signing_txack(TxAck_TransactionType *tx) return; case STAGE_REQUEST_2_PREV_EXTRADATA: if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize extra data")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize extra data")); signing_abort(); return; } @@ -1137,7 +1137,7 @@ void signing_txack(TxAck_TransactionType *tx) hasher_Update(&hasher_check, (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1153,7 +1153,7 @@ void signing_txack(TxAck_TransactionType *tx) tx->inputs[0].script_sig.size = 0; } if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1164,7 +1164,7 @@ void signing_txack(TxAck_TransactionType *tx) uint8_t hash[32]; hasher_Final(&hasher_check, hash); if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } @@ -1176,14 +1176,14 @@ void signing_txack(TxAck_TransactionType *tx) case STAGE_REQUEST_4_OUTPUT: progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } // check hashOutputs tx_output_hash(&hasher_check, &bin_output, coin->decred); if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize output")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); signing_abort(); return; } @@ -1217,17 +1217,17 @@ void signing_txack(TxAck_TransactionType *tx) if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { if (!(coin->force_bip143 || overwintered)) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } if (tx->inputs[0].amount > authorized_amount) { - fsm_sendFailure(Failure_FailureType_Failure_DataError, _("Transaction has changed during signing")); + fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); signing_abort(); return; } @@ -1249,7 +1249,7 @@ void signing_txack(TxAck_TransactionType *tx) } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS && !tx->inputs[0].has_multisig) { if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1268,7 +1268,7 @@ void signing_txack(TxAck_TransactionType *tx) tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) // compute digest of multisig script if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1288,7 +1288,7 @@ void signing_txack(TxAck_TransactionType *tx) case STAGE_REQUEST_5_OUTPUT: if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile output")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; } @@ -1337,7 +1337,7 @@ void signing_txack(TxAck_TransactionType *tx) ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to compile input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); signing_abort(); return; } @@ -1351,7 +1351,7 @@ void signing_txack(TxAck_TransactionType *tx) } if (!r) { - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Failed to serialize input")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); signing_abort(); return; } @@ -1375,7 +1375,7 @@ void signing_txack(TxAck_TransactionType *tx) return; } - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Signing error")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); signing_abort(); } diff --git a/firmware/signing.h b/firmware/signing.h index 90475d9a4a..d27ebf7cf1 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -29,6 +29,6 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root); void signing_abort(void); -void signing_txack(TxAck_TransactionType *tx); +void signing_txack(TransactionType *tx); #endif diff --git a/firmware/stellar.c b/firmware/stellar.c index e8d66c1e37..ff3f6fc621 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -177,7 +177,7 @@ bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -225,7 +225,7 @@ bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) str_addr_rows[2], str_amount_line ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -283,7 +283,7 @@ bool stellar_confirmPaymentOp(StellarPaymentOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -352,7 +352,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) str_dest_rows[1], str_dest_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -372,7 +372,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) _("This is the amount debited"), _("from your account.") ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -467,7 +467,7 @@ bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) str_buying, str_buying_asset ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -547,7 +547,7 @@ bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) str_buying, str_buying_asset ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -606,7 +606,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -638,7 +638,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -672,7 +672,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -745,7 +745,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -775,7 +775,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) NULL, NULL ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -817,7 +817,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -834,7 +834,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("(confirm hash on next"), _("screen)") ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -851,7 +851,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) _("(confirm hash on next"), _("screen)") ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -871,7 +871,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) rows[2], rows[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -931,7 +931,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE]; if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) { stellar_signingAbort(_("User canceled")); - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, _("Invalid asset issuer")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Invalid asset issuer")); return false; } @@ -945,7 +945,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1006,7 +1006,7 @@ bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) str_trustor_rows[1], str_trustor_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1064,7 +1064,7 @@ bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) str_destination_rows[1], str_destination_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1107,7 +1107,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) str_key_lines[2], str_key_lines[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1127,7 +1127,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) str_hash_lines[2], str_hash_lines[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1173,7 +1173,7 @@ bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) NULL, NULL ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; } @@ -1193,7 +1193,7 @@ void stellar_signingAbort(const char *reason) } stellar_signing = false; - fsm_sendFailure(Failure_FailureType_Failure_ProcessError, reason); + fsm_sendFailure(FailureType_Failure_ProcessError, reason); layoutHome(); } @@ -1676,7 +1676,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_addr_rows[1], str_addr_rows[2] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } @@ -1730,7 +1730,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[3], str_lines[4] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } @@ -1778,7 +1778,7 @@ void stellar_layoutTransactionSummary(StellarSignTx *msg) str_lines[2], str_lines[3] ); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ProtectCall, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return; } diff --git a/firmware/transaction.c b/firmware/transaction.c index ae66a3517c..122e9632a2 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -186,22 +186,22 @@ bool compute_address(const CoinInfo *coin, return 1; } -int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionType_TxOutputType *in, TxAck_TransactionType_TxOutputBinType *out, bool needs_confirm) +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) { - memset(out, 0, sizeof(TxAck_TransactionType_TxOutputBinType)); + memset(out, 0, sizeof(TxOutputBinType)); out->amount = in->amount; out->decred_script_version = in->decred_script_version; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; size_t addr_raw_len; - if (in->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOOPRETURN) { + if (in->script_type == OutputScriptType_PAYTOOPRETURN) { // only 0 satoshi allowed for OP_RETURN if (in->amount != 0) { return 0; // failed to compile output } if (needs_confirm) { layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } } @@ -218,16 +218,16 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionTy InputScriptType input_script_type; switch (in->script_type) { - case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOADDRESS: + case OutputScriptType_PAYTOADDRESS: input_script_type = InputScriptType_SPENDADDRESS; break; - case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOMULTISIG: + case OutputScriptType_PAYTOMULTISIG: input_script_type = InputScriptType_SPENDMULTISIG; break; - case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS: + case OutputScriptType_PAYTOWITNESS: input_script_type = InputScriptType_SPENDWITNESS; break; - case TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS: + case OutputScriptType_PAYTOP2SHWITNESS: input_script_type = InputScriptType_SPENDP2SHWITNESS; break; default: @@ -307,7 +307,7 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionTy if (needs_confirm) { layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequest_ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } } @@ -420,7 +420,7 @@ uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScr // tx methods -uint32_t tx_prevout_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input) +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) { for (int i = 0; i < 32; i++) { hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); @@ -436,13 +436,13 @@ uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) return r + size; } -uint32_t tx_sequence_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input) +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) { hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); return 4; } -uint32_t tx_output_hash(Hasher *hasher, const TxAck_TransactionType_TxOutputBinType *output, bool decred) +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) { uint32_t r = 0; hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; @@ -497,7 +497,7 @@ uint32_t tx_serialize_header_hash(TxStruct *tx) return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } -uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out) +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -526,7 +526,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputTyp return r; } -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input) +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -551,7 +551,7 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInp return r; } -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out) +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) { static const uint64_t amount = 0; static const uint32_t block_height = 0x00000000; @@ -576,7 +576,7 @@ uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_T return r; } -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input) +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) { if (tx->have_inputs >= tx->inputs_len) { // already got all inputs @@ -638,7 +638,7 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx) return 4; } -uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output, uint8_t *out) +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) { if (tx->have_inputs < tx->inputs_len) { // not all inputs provided @@ -667,7 +667,7 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputB return r; } -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output) +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) { if (tx->have_inputs < tx->inputs_len) { // not all inputs provided @@ -741,7 +741,7 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) } } -static uint32_t tx_input_script_size(const TxAck_TransactionType_TxInputType *txinput) { +static uint32_t tx_input_script_size(const TxInputType *txinput) { uint32_t input_script_size; if (txinput->has_multisig) { uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT @@ -756,7 +756,7 @@ static uint32_t tx_input_script_size(const TxAck_TransactionType_TxInputType *tx return input_script_size; } -uint32_t tx_input_weight(const CoinInfo *coin, const TxAck_TransactionType_TxInputType *txinput) { +uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) { if (coin->decred) { return 4 * (TXSIZE_INPUT + 1); // Decred tree } @@ -780,16 +780,16 @@ uint32_t tx_input_weight(const CoinInfo *coin, const TxAck_TransactionType_TxInp return weight; } -uint32_t tx_output_weight(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *txoutput) { +uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { uint32_t output_script_size = 0; - if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOOPRETURN) { + if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { output_script_size = 1 + op_push_size(txoutput->op_return_data.size) + txoutput->op_return_data.size; } else if (txoutput->address_n_count > 0) { - if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOWITNESS) { + if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { output_script_size = txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; - } else if (txoutput->script_type == TxAck_TransactionType_TxOutputType_OutputScriptType_PAYTOP2SHWITNESS) { + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { output_script_size = TXSIZE_P2SCRIPT; } else { output_script_size = txoutput->has_multisig @@ -832,7 +832,7 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxAck_TransactionType_TxOu return 4 * (size + output_script_size); } -uint32_t tx_decred_witness_weight(const TxAck_TransactionType_TxInputType *txinput) { +uint32_t tx_decred_witness_weight(const TxInputType *txinput) { uint32_t input_script_size = tx_input_script_size(txinput); uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; diff --git a/firmware/transaction.h b/firmware/transaction.h index c247b5c079..5180a58e5a 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -59,29 +59,29 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinInfo *coin, const HDNode *root, TxAck_TransactionType_TxOutputType *in, TxAck_TransactionType_TxOutputBinType *out, bool needs_confirm); +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); -uint32_t tx_prevout_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input); +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); -uint32_t tx_sequence_hash(Hasher *hasher, const TxAck_TransactionType_TxInputType *input); -uint32_t tx_output_hash(Hasher *hasher, const TxAck_TransactionType_TxOutputBinType *output, bool decred); +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); -uint32_t tx_serialize_input(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out); -uint32_t tx_serialize_output(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output, uint8_t *out); -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxAck_TransactionType_TxInputType *input, uint8_t *out); +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id); uint32_t tx_serialize_header_hash(TxStruct *tx); -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input); -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxAck_TransactionType_TxOutputBinType *output); +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxAck_TransactionType_TxInputType *input); +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); -uint32_t tx_input_weight(const CoinInfo *coin, const TxAck_TransactionType_TxInputType *txinput); -uint32_t tx_output_weight(const CoinInfo *coin, const TxAck_TransactionType_TxOutputType *txoutput); -uint32_t tx_decred_witness_weight(const TxAck_TransactionType_TxInputType *txinput); +uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput); +uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput); +uint32_t tx_decred_witness_weight(const TxInputType *txinput); #endif diff --git a/vendor/nanopb b/vendor/nanopb index 71ba4e68da..37cdb0df67 160000 --- a/vendor/nanopb +++ b/vendor/nanopb @@ -1 +1 @@ -Subproject commit 71ba4e68da4b3c986d454e34c4666a82fbdf4176 +Subproject commit 37cdb0df67b2adc1c70b3b5e6bc26657f844c1dd From c6b8cc8b5c4ca916d80762cd0dce391449cb2f55 Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 5 Sep 2018 14:29:59 +0200 Subject: [PATCH 0962/1154] vendor: update to upstream nanopb, refresh trezor-common --- vendor/nanopb | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/nanopb b/vendor/nanopb index 37cdb0df67..cdb6161219 160000 --- a/vendor/nanopb +++ b/vendor/nanopb @@ -1 +1 @@ -Subproject commit 37cdb0df67b2adc1c70b3b5e6bc26657f844c1dd +Subproject commit cdb61612197feca5391593d051c8d4892e940228 diff --git a/vendor/trezor-common b/vendor/trezor-common index d37abab57d..5d472e8a11 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit d37abab57d6a03d611f4008af0cbfc1d5d872bd7 +Subproject commit 5d472e8a116c2c9cf6c1a6d0e1de0a1465377d91 From efeedbe69b7fa9845462775c7a528c4f1838b7d8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 6 Sep 2018 19:09:00 +0200 Subject: [PATCH 0963/1154] fsm: implement script_type handling in GetPublicKey --- firmware/coin_info.c.mako | 3 ++- firmware/coins.h | 3 ++- firmware/fsm_msg_coin.h | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/firmware/coin_info.c.mako b/firmware/coin_info.c.mako index e504bde2cd..80ba716ff3 100644 --- a/firmware/coin_info.c.mako +++ b/firmware/coin_info.c.mako @@ -38,7 +38,8 @@ const CoinInfo coins[COINS_COUNT] = { .address_type = ${c.address_type}, .address_type_p2sh = ${c.address_type_p2sh}, .xpub_magic = ${hex(c.xpub_magic)}, - .xprv_magic = ${hex(c.xprv_magic)}, + .xpub_magic_segwit_p2sh = ${hex(c.xpub_magic_segwit_p2sh)}, + .xpub_magic_segwit_native = ${hex(c.xpub_magic_segwit_native)}, .fork_id = ${c_int(c.fork_id)}, .version_group_id = ${hex(c.version_group_id)}, .bech32_prefix = ${c_str(c.bech32_prefix)}, diff --git a/firmware/coins.h b/firmware/coins.h index 3a3b8116b8..b313c6c8d8 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -41,7 +41,8 @@ typedef struct _CoinInfo { uint32_t address_type; uint32_t address_type_p2sh; uint32_t xpub_magic; - uint32_t xprv_magic; + uint32_t xpub_magic_segwit_p2sh; + uint32_t xpub_magic_segwit_native; uint32_t fork_id; uint32_t version_group_id; const char *bech32_prefix; diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 6152edb4ac..8c810205bd 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -25,6 +25,8 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) CHECK_PIN + InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); if (!coin) return; @@ -60,7 +62,21 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) resp->node.public_key.bytes[0] = 0; } resp->has_xpub = true; - hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); + + if (coin->xpub_magic && script_type == InputScriptType_SPENDADDRESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); + } else + if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, resp->xpub, sizeof(resp->xpub)); + } else + if (coin->has_segwit && coin->xpub_magic_segwit_native && script_type == InputScriptType_SPENDWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, resp->xpub, sizeof(resp->xpub)); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid combination of coin and script_type")); + layoutHome(); + return; + } + msg_write(MessageType_MessageType_PublicKey, resp); layoutHome(); } From 2310d96ee1c8288656de8a98d677da6ce20beb80 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 17:40:43 +0200 Subject: [PATCH 0964/1154] vendor: update trezor-crypto --- firmware/crypto.c | 1 - firmware/fsm.c | 1 - firmware/storage.c | 2 +- firmware/transaction.c | 6 +++--- vendor/trezor-crypto | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index e538aeb608..3254b23b36 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -20,7 +20,6 @@ #include #include "crypto.h" #include "sha2.h" -#include "ripemd160.h" #include "pbkdf2.h" #include "aes/aes.h" #include "hmac.h" diff --git a/firmware/fsm.c b/firmware/fsm.c index ab60788273..1a142817f0 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -47,7 +47,6 @@ #include "crypto.h" #include "base58.h" #include "bip39.h" -#include "ripemd160.h" #include "curves.h" #include "secp256k1.h" #include "ethereum.h" diff --git a/firmware/storage.c b/firmware/storage.c index 429a82e93f..95b7d2ba42 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -566,7 +566,7 @@ bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; char oldTiny = usbTiny(1); - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); for (int i = 0; i < 8; i++) { pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); diff --git a/firmware/transaction.c b/firmware/transaction.c index 122e9632a2..4e16f55730 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -134,8 +134,8 @@ bool compute_address(const CoinInfo *coin, } raw[0] = 0; // push version raw[1] = 32; // push 32 bytes - memcpy(raw+2, digest, 32); // push hash - hasher_Raw(coin->curve->hasher_pubkey, raw, 34, digest); + memcpy(raw + 2, digest, 32); // push hash + hasher_Raw(coin->curve->hasher_multisig, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); ripemd160(digest, 32, raw + prelen); @@ -364,7 +364,7 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem if (n < 1 || n > 15) return 0; Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_pubkey); + hasher_Init(&hasher, coin->curve->hasher_multisig); uint8_t d[2]; d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 3e8974ff88..f9caee2489 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 3e8974ff8871263a70b7fbb9a27a1da5b0d810f7 +Subproject commit f9caee2489aa1ca8a3380c9fc79465a83c848b7f From d07d865155fef629d4f31d12f1feec40d39760f6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 19:07:17 +0200 Subject: [PATCH 0965/1154] demo: fix crypto call --- demo/demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/demo.c b/demo/demo.c index d77279f0b8..b2bbe8f98f 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -269,7 +269,7 @@ int main(void) switch (state) { case 1: layoutProgress("WORKING", frame % 41 * 25); - pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed); + pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); break; } From b7d38973e2e65a2d01c57dd61687234c1378c4e1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 5 Sep 2018 20:04:54 +0200 Subject: [PATCH 0966/1154] rename hasher_multisig to hasher_script --- firmware/transaction.c | 6 +++--- vendor/trezor-crypto | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index 4e16f55730..d84b2ac64c 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -135,10 +135,10 @@ bool compute_address(const CoinInfo *coin, raw[0] = 0; // push version raw[1] = 32; // push 32 bytes memcpy(raw + 2, digest, 32); // push hash - hasher_Raw(coin->curve->hasher_multisig, raw, 34, digest); + hasher_Raw(coin->curve->hasher_pubkey, raw, 34, digest); prelen = address_prefix_bytes_len(coin->address_type_p2sh); address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); + memcpy(raw + prelen, digest, 32); if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { return 0; } @@ -364,7 +364,7 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem if (n < 1 || n > 15) return 0; Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_multisig); + hasher_Init(&hasher, coin->curve->hasher_script); uint8_t d[2]; d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f9caee2489..b679a6b2a7 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f9caee2489aa1ca8a3380c9fc79465a83c848b7f +Subproject commit b679a6b2a73ed8adfe236cfa0ba73c5d86661633 From aa403d17c446757c96c05f0ff98da42766e9ae47 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Sep 2018 15:28:09 +0200 Subject: [PATCH 0967/1154] travis: build emulator in both gcc and clang --- .travis.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3278084912..f8814d42c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,11 +26,19 @@ env: matrix: include: - env: - - EMULATOR=1 HEADLESS=1 - - DEBUG_LINK=1 - script: - - pipenv run ./script/cibuild && pipenv run script/test + compiler: + - clang + env: + - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 + script: + - pipenv run ./script/cibuild && pipenv run script/test + include: + compiler: + - gcc + env: + - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 + script: + - pipenv run ./script/cibuild && pipenv run script/test install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 15f28836dc7ae0dd09dcf856873d02b7fb35dd81 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Sep 2018 15:29:35 +0200 Subject: [PATCH 0968/1154] travis: fix last commit --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f8814d42c4..d7c7535800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,12 +28,6 @@ matrix: include: compiler: - clang - env: - - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 - script: - - pipenv run ./script/cibuild && pipenv run script/test - include: - compiler: - gcc env: - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 From 1a02750486a770dc219c07f377a2f3047a4e49a0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Sep 2018 15:33:37 +0200 Subject: [PATCH 0969/1154] travis: trying to enable clang/gcc --- .travis.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d7c7535800..525d8d33b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,10 @@ sudo: false dist: trusty language: c +compiler: + - clang + - gcc + addons: apt: sources: @@ -26,13 +30,15 @@ env: matrix: include: - compiler: - - clang - - gcc env: - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 script: - pipenv run ./script/cibuild && pipenv run script/test + exclude: + - compiler: clang + env: DEBUG_LINK=0 + - compiler: clang + env: DEBUG_LINK=1 install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 61d3daa936ad977a514e4f8440baa022bee1f13d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Sep 2018 15:43:30 +0200 Subject: [PATCH 0970/1154] travis: trying anoter trick --- .travis.yml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 525d8d33b5..18b4412626 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,6 @@ sudo: false dist: trusty language: c -compiler: - - clang - - gcc - addons: apt: sources: @@ -30,15 +26,14 @@ env: matrix: include: - env: - - EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 - script: - - pipenv run ./script/cibuild && pipenv run script/test - exclude: - - compiler: clang - env: DEBUG_LINK=0 - - compiler: clang - env: DEBUG_LINK=1 + - name: "Emulator GCC" + env: EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 + compiler: gcc + script: pipenv run ./script/cibuild && pipenv run script/test + - name: "Emulator Clang" + env: EMULATOR=1 HEADLESS=1 DEBUG_LINK=1 + compiler: clang + script: pipenv run ./script/cibuild && pipenv run script/test install: - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" From 14b1a04b0a65112c42879aefaf669d868be02537 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Sep 2018 15:58:11 +0200 Subject: [PATCH 0971/1154] fix Clang compile issue with unicode literals https://lists.llvm.org/pipermail/llvm-bugs/2015-July/040965.html --- Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index 01fa7fdb4e..8e1cff25cd 100644 --- a/Makefile.include +++ b/Makefile.include @@ -37,7 +37,7 @@ endif CFLAGS += $(OPTFLAGS) \ $(DBGFLAGS) \ - -std=gnu99 \ + -std=gnu11 \ -W \ -Wall \ -Wextra \ From 4ac99f3470336fe24997c8ba3abf0115955c01ea Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 13 Sep 2018 15:01:58 +0200 Subject: [PATCH 0972/1154] vendor: update trezor-crypto --- firmware/crypto.c | 2 +- firmware/ethereum.c | 2 +- vendor/trezor-crypto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 3254b23b36..68019cb5aa 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -163,7 +163,7 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes // check if signature verifies the digest and recover the public key uint8_t pubkey[65]; - if (ecdsa_verify_digest_recover(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { + if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { return 3; } // convert public key to compressed pubkey if necessary diff --git a/firmware/ethereum.c b/firmware/ethereum.c index fc7f4dcbee..4995e1e9b4 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -687,7 +687,7 @@ int ethereum_message_verify(EthereumVerifyMessage *msg) v -= 27; } if (v >= 2 || - ecdsa_verify_digest_recover(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { + ecdsa_recover_pub_from_sig(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { return 2; } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index b679a6b2a7..f9523f97df 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit b679a6b2a73ed8adfe236cfa0ba73c5d86661633 +Subproject commit f9523f97df2c965835001d551738bbe1b93b53df From 34aad724f0bc7ba13e8e92e80047e45e72539136 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 13 Sep 2018 19:58:34 +0200 Subject: [PATCH 0973/1154] usb: don't use CONFIDENTIAL inside DEBUG_LINK code This will make confidential sections identical for production and debug build. --- firmware/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/usb.c b/firmware/usb.c index 733a55b344..a40ce122b2 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -299,7 +299,7 @@ static void u2f_rx_callback(usbd_device *dev, uint8_t ep) static void debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; - static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); + static uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; debugLog(0, "", "debug_rx_callback"); if (!tiny) { From b0a7ea1f31693623ad46faa31691a1e419112287 Mon Sep 17 00:00:00 2001 From: alepop Date: Fri, 14 Sep 2018 13:13:41 +0300 Subject: [PATCH 0974/1154] add Lisk support (#351) --- firmware/Makefile | 2 + firmware/fsm.c | 4 +- firmware/fsm.h | 8 + firmware/fsm_msg_lisk.h | 127 ++++++++ firmware/lisk.c | 428 ++++++++++++++++++++++++++ firmware/lisk.h | 50 +++ firmware/protob/Makefile | 4 +- firmware/protob/messages-lisk.options | 30 ++ firmware/protob/messages-lisk.proto | 1 + 9 files changed, 651 insertions(+), 3 deletions(-) create mode 100644 firmware/fsm_msg_lisk.h create mode 100644 firmware/lisk.c create mode 100644 firmware/lisk.h create mode 100644 firmware/protob/messages-lisk.options create mode 120000 firmware/protob/messages-lisk.proto diff --git a/firmware/Makefile b/firmware/Makefile index 4c0f7858ba..1790be53ec 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -29,6 +29,7 @@ OBJS += ethereum_tokens.o OBJS += nem2.o OBJS += nem_mosaics.o OBJS += stellar.o +OBJS += lisk.o OBJS += debug.o @@ -91,6 +92,7 @@ OBJS += protob/messages-ethereum.pb.o OBJS += protob/messages-management.pb.o OBJS += protob/messages-nem.pb.o OBJS += protob/messages-stellar.pb.o +OBJS += protob/messages-lisk.pb.o OPTFLAGS ?= -Os diff --git a/firmware/fsm.c b/firmware/fsm.c index 1a142817f0..bc249de1b7 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -55,8 +55,9 @@ #include "rfc6979.h" #include "gettext.h" #include "supervise.h" -#include "stellar.h" #include "messages.pb.h" +#include "stellar.h" +#include "lisk.h" // message methods @@ -248,4 +249,5 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore #include "fsm_msg_crypto.h" #include "fsm_msg_nem.h" #include "fsm_msg_stellar.h" +#include "fsm_msg_lisk.h" #include "fsm_msg_debug.h" diff --git a/firmware/fsm.h b/firmware/fsm.h index a102c785a0..f1484903f8 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -27,6 +27,7 @@ #include "messages-management.pb.h" #include "messages-nem.pb.h" #include "messages-stellar.pb.h" +#include "messages-lisk.pb.h" // message functions @@ -101,6 +102,13 @@ void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); +// Lisk +void fsm_msgLiskGetAddress(LiskGetAddress *msg); +void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg); +void fsm_msgLiskSignMessage(LiskSignMessage *msg); +void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg); +void fsm_msgLiskSignTx(LiskSignTx *msg); + // debug message functions #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); diff --git a/firmware/fsm_msg_lisk.h b/firmware/fsm_msg_lisk.h new file mode 100644 index 0000000000..667e295452 --- /dev/null +++ b/firmware/fsm_msg_lisk.h @@ -0,0 +1,127 @@ +void fsm_msgLiskGetAddress(LiskGetAddress *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN + + RESP_INIT(LiskAddress); + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + resp->has_address = true; + + if (!hdnode_get_lisk_address(node, resp->address)) + return; + + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, "Address:", sizeof(desc)); + + if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { + return; + } + } + + msg_write(MessageType_MessageType_LiskAddress, resp); + + layoutHome(); +} + +void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN + + RESP_INIT(LiskPublicKey); + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + hdnode_fill_public_key(node); + + resp->has_public_key = true; + resp->public_key.size = 32; + + if (msg->has_show_display && msg->show_display) { + layoutLiskPublicKey(&node->public_key[1]); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); + + msg_write(MessageType_MessageType_LiskPublicKey, resp); + + layoutHome(); +} + +void fsm_msgLiskSignMessage(LiskSignMessage *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN + + RESP_INIT(LiskMessageSignature); + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + hdnode_fill_public_key(node); + + lisk_sign_message(node, msg, resp); + + msg_write(MessageType_MessageType_LiskMessageSignature, resp); + + layoutHome(); +} + +void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg) +{ + if (lisk_verify_message(msg)) { + char address[23]; + lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); + + layoutLiskVerifyAddress(address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + } + + layoutHome(); +} + +void fsm_msgLiskSignTx(LiskSignTx *msg) +{ + CHECK_INITIALIZED + + CHECK_PIN + + RESP_INIT(LiskSignedTx); + + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; + + hdnode_fill_public_key(node); + + lisk_sign_tx(node, msg, resp); + + msg_write(MessageType_MessageType_LiskSignedTx, resp); + + layoutHome(); +} diff --git a/firmware/lisk.c b/firmware/lisk.c new file mode 100644 index 0000000000..ad43d9c80c --- /dev/null +++ b/firmware/lisk.c @@ -0,0 +1,428 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2017 Saleem Rashid + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +#include + +#include "lisk.h" +#include "curves.h" +#include "layout2.h" +#include "bitmaps.h" +#include "util.h" +#include "gettext.h" +#include "crypto.h" +#include "protect.h" +#include "messages.pb.h" + +int hdnode_get_lisk_address(HDNode *node, char *address) { + if (node->curve != get_curve_by_name(ED25519_NAME)) { + return 0; + } + hdnode_fill_public_key(node); + lisk_get_address_from_public_key(&node->public_key[1], address); + return 1; +} + +void lisk_get_address_from_public_key(const uint8_t* public_key, char *address) { + uint8_t digest[32]; + uint8_t address_bytes[8]; + + sha256_Raw(public_key, 32, digest); + + uint8_t i; + for (i = 0; i < 8; i++) { + address_bytes[i] = digest[ 7 - i]; + } + + uint64_t encodedAddress = 0; + for (i = 0; i < 8; i++ ) { + encodedAddress = encodedAddress << 8; + encodedAddress += address_bytes[i]; + } + + bn_format_uint64(encodedAddress, NULL, "L", 0, 0, false, address, 23); +} + +void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) { + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + sha256_Update(&ctx, varint, l); + sha256_Update(&ctx, message, message_len); + sha256_Final(&ctx, hash); + sha256_Raw(hash, 32, hash); +} + +void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp) +{ + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + layoutProgressSwipe(_("Signing"), 0); + + uint8_t signature[64]; + uint8_t hash[32]; + lisk_message_hash(msg->message.bytes, msg->message.size, hash); + + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); + + memcpy(resp->signature.bytes, signature, sizeof(signature)); + memcpy(resp->public_key.bytes, &node->public_key[1], 32); + + resp->has_signature = true; + resp->signature.size = 64; + resp->has_public_key = true; + resp->public_key.size = 32; +} + +bool lisk_verify_message(LiskVerifyMessage *msg) +{ + uint8_t hash[32]; + lisk_message_hash(msg->message.bytes, msg->message.size, hash); + + return ed25519_sign_open( + hash, + 32, + msg->public_key.bytes, + msg->signature.bytes + ) == 0; +} + +void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg) +{ + if(!msg->transaction.has_sender_public_key) { + memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32); + } + + // For CastVotes transactions, recipientId should be equal to transaction creator address. + if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) { + char address[23]; + lisk_get_address_from_public_key(&node->public_key[1], address); + memcpy(msg->transaction.recipient_id, address, sizeof(address)); + msg->transaction.has_recipient_id = true; + } +} + +void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value) +{ + uint8_t data[4]; + write_le(data, value); + sha256_Update(ctx, data, sizeof(data)); +} + +void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i) +{ + uint8_t data[8]; + // i = true ? big-endian : little-endian + data[i ? 0 : 7] = (value >> 56); + data[i ? 1 : 6] = (value >> 48); + data[i ? 2 : 5] = (value >> 40); + data[i ? 3 : 4] = (value >> 32); + data[i ? 4 : 3] = (value >> 24); + data[i ? 5 : 2] = (value >> 16); + data[i ? 6 : 1] = (value >> 8); + data[i ? 7 : 0] = value; + sha256_Update(ctx, data, sizeof(data)); +} + +void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset) +{ + switch (type) { + case LiskTransactionType_Transfer: + if (asset->has_data) { + sha256_Update(ctx, (const uint8_t *)asset->data, strlen(asset->data)); + } + break; + case LiskTransactionType_RegisterDelegate: + if (asset->has_delegate && asset->delegate.has_username) { + sha256_Update(ctx, (const uint8_t *)asset->delegate.username, strlen(asset->delegate.username)); + } + break; + case LiskTransactionType_CastVotes: { + char str[asset->votes_count * 66]; + strlcpy(str, asset->votes[0], sizeof(str)); + for (int i = 1; i < asset->votes_count; i++) { + strlcat(str, asset->votes[i], sizeof(str)); + }; + sha256_Update(ctx, (const uint8_t *)str, strlen(str)); + break; + } + case LiskTransactionType_RegisterSecondPassphrase: + if (asset->has_signature && asset->signature.has_public_key) { + sha256_Update(ctx, asset->signature.public_key.bytes, asset->signature.public_key.size); + } + break; + case LiskTransactionType_RegisterMultisignatureAccount: { + if (asset->has_multisignature) { + char str[asset->multisignature.keys_group_count * 66 + 4 + 4]; + uint8_t min[4]; + uint8_t life_time[4]; + + // convert uint32_t to uint8_t + write_le(min, asset->multisignature.min); + write_le(life_time, asset->multisignature.life_time); + + // calculate sha from min + life_time + keys_group + strlcpy(str, (const char *)min, sizeof(str)); + strlcat(str, (const char *)life_time, sizeof(str)); + for (int i = 0; i < asset->multisignature.keys_group_count; i++) { + strlcat(str, asset->multisignature.keys_group[i], sizeof(str)); + }; + + sha256_Update(ctx, (const uint8_t *)str, strlen(str)); + } + break; + } + default: + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); + break; + } +} + +void lisk_format_value(uint64_t value, char *formated_value) +{ + bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, 20); +} + +void liks_get_vote_txt(char *prefix, int num, char *txt, size_t size) +{ + char buffer[4]; + sprintf(buffer, "%d", num); + + strlcpy(txt, prefix, size); + strlcat(txt, buffer, size); + strlcat(txt, (num != 1) ? " votes" : " vote", size); +} + +void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) +{ + lisk_update_raw_tx(node, msg); + + if(msg->has_transaction) { + SHA256_CTX ctx; + sha256_Init(&ctx); + + switch (msg->transaction.type) { + case LiskTransactionType_Transfer: + layoutRequireConfirmTx(msg->transaction.recipient_id, msg->transaction.amount); + break; + case LiskTransactionType_RegisterDelegate: + layoutRequireConfirmDelegateRegistration(&msg->transaction.asset); + break; + case LiskTransactionType_CastVotes: + layoutRequireConfirmCastVotes(&msg->transaction.asset); + break; + case LiskTransactionType_RegisterSecondPassphrase: + layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes ); + break; + case LiskTransactionType_RegisterMultisignatureAccount: + layoutRequireConfirmMultisig(&msg->transaction.asset); + break; + default: + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); + layoutHome(); + break; + } + if (!protectButton(( + msg->transaction.type == LiskTransactionType_RegisterSecondPassphrase ? + ButtonRequestType_ButtonRequest_PublicKey : + ButtonRequestType_ButtonRequest_SignTx), + false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled"); + layoutHome(); + return; + } + + layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled"); + layoutHome(); + return; + } + layoutProgressSwipe(_("Signing transaction"), 0); + + sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1); + + lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp); + + sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32); + + if (msg->transaction.has_requester_public_key) { + sha256_Update(&ctx, msg->transaction.requester_public_key.bytes, msg->transaction.requester_public_key.size); + } + + uint64_t recipient_id = 0; + if (msg->transaction.has_recipient_id) { + // parse integer from lisk address (string -> number) + sscanf(msg->transaction.recipient_id, "%llu", (long long unsigned int *)&recipient_id ); + } + lisk_hashupdate_uint64(&ctx, recipient_id, true); + lisk_hashupdate_uint64(&ctx, msg->transaction.amount, false); + + lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset); + + // if signature exist calculate second signature + if (msg->transaction.has_signature) { + sha256_Update(&ctx, msg->transaction.signature.bytes, msg->transaction.signature.size); + } + + uint8_t signature[64]; + uint8_t hash[32]; + + sha256_Final(&ctx, hash); + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); + + memcpy(resp->signature.bytes, signature, sizeof(signature)); + resp->has_signature = true; + resp->signature.size = 64; + } +} + +// Layouts +void layoutLiskPublicKey(const uint8_t *pubkey) +{ + char hex[32 * 2 + 1], desc[13]; + strlcpy(desc, "Public Key:", sizeof(desc)); + data2hex(pubkey, 32, hex); + const char **str = split_message((const uint8_t *)hex, 32 * 2, 16); + layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, + desc, str[0], str[1], str[2], str[3], NULL); +} + +void layoutLiskVerifyAddress(const char *address) +{ + const char **str = split_message((const uint8_t *)address, strlen(address), 10); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Confirm address?"), + _("Message signed by:"), + str[0], str[1], NULL, NULL, NULL); +} + +void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) +{ + char formated_amount[20]; + const char **str = split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16); + lisk_format_value(amount, formated_amount); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + NULL, + _("Confirm sending"), + formated_amount, + _("to:"), + str[0], + str[1], + NULL + ); +} + +void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) +{ + char formated_amount[20]; + char formated_fee[20]; + lisk_format_value(amount, formated_amount); + lisk_format_value(fee, formated_fee); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + NULL, + _("Confirm transaction"), + formated_amount, + _("fee:"), + formated_fee, + NULL, + NULL + ); +} + +void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) +{ + if (asset->has_delegate && asset->delegate.has_username) { + const char **str = split_message((const uint8_t *)asset->delegate.username, strlen(asset->delegate.username), 20); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + NULL, + _("Confirm transaction"), + _("Do you really want to"), + _("register a delegate?"), + str[0], + str[1], + NULL + ); + } +} + +void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) +{ + uint8_t plus = 0; + uint8_t minus = 0; + char add_votes_txt[13]; + char remove_votes_txt[16]; + + for (int i = 0; i < asset->votes_count; i++) { + if (strncmp(asset->votes[i], "+", 1) == 0) { + plus += 1; + } else { + minus += 1; + } + } + + liks_get_vote_txt("Add ", plus, add_votes_txt, sizeof(add_votes_txt)); + liks_get_vote_txt("Remove ", minus, remove_votes_txt, sizeof(remove_votes_txt)); + + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + NULL, + _("Confirm transaction"), + add_votes_txt, + remove_votes_txt, + NULL, + NULL, + NULL + ); +} + +void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) +{ + char keys_group_str[22]; + char life_time_str[14]; + char min_str[8]; + char buffer[8]; + + strlcpy(keys_group_str, "Keys group length: ", sizeof(keys_group_str)); + strlcpy(life_time_str, "Life time: ", sizeof(life_time_str)); + strlcpy(min_str, "Min: ", sizeof(min_str)); + + sprintf(buffer, "%u", (unsigned int)asset->multisignature.keys_group_count); + strlcat(keys_group_str, buffer, sizeof(keys_group_str)); + + sprintf(buffer, "%u", (unsigned int)asset->multisignature.life_time); + strlcat(life_time_str, buffer, sizeof(life_time_str)); + + sprintf(buffer, "%u", (unsigned int)asset->multisignature.min); + strlcat(min_str, buffer, sizeof(min_str)); + + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + NULL, + _("Confirm transaction"), + keys_group_str, + life_time_str, + min_str, + NULL, + NULL + ); +} \ No newline at end of file diff --git a/firmware/lisk.h b/firmware/lisk.h new file mode 100644 index 0000000000..db7d2a004d --- /dev/null +++ b/firmware/lisk.h @@ -0,0 +1,50 @@ +/* + * This file is part of the TREZOR project. + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __LISK_H__ +#define __LISK_H__ + +#include +#include "bip32.h" +#include "fsm.h" +#include "messages-lisk.pb.h" + +// Main +int hdnode_get_lisk_address(HDNode *node, char *address); + +void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp); +bool lisk_verify_message(LiskVerifyMessage *msg); +void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); + +// Helpers +void lisk_get_address_from_public_key(const uint8_t *public_key, char *address); +void lisk_format_value(uint64_t value, char *formated_value); +void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg); +void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i); +void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value); +void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset); + +// Layout +void layoutLiskPublicKey(const uint8_t *pubkey); +void layoutLiskVerifyAddress(const char *address); +void layoutRequireConfirmTx(char *recipient_id, uint64_t amount); +void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset); +void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset); +void layoutRequireConfirmMultisig(LiskTransactionAsset *asset); +void layoutRequireConfirmFee(uint64_t fee, uint64_t amount); + +#endif diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index bd12603fbf..4b372fe5bb 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -2,7 +2,7 @@ ifneq ($(V),1) Q := @ endif -all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages_nem_pb2.py +all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages-lisk.pb.c messages_nem_pb2.py PYTHON ?= python @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Lisk -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/messages-lisk.options b/firmware/protob/messages-lisk.options new file mode 100644 index 0000000000..a3860d57b4 --- /dev/null +++ b/firmware/protob/messages-lisk.options @@ -0,0 +1,30 @@ +LiskGetAddress.address_n max_count:8 +LiskAddress.address max_size:23 + +LiskGetPublicKey.address_n max_count:8 +LiskPublicKey.public_key max_size:32 + +LiskSignMessage.address_n max_count:8 +LiskSignMessage.message max_size:1024 +LiskMessageSignature.public_key max_size:32 +LiskMessageSignature.signature max_size:64 + +LiskVerifyMessage.public_key max_size:33 +LiskVerifyMessage.message max_size:1024 +LiskVerifyMessage.signature max_size:65 + +LiskSignTx.address_n max_count:8 + +LiskSignedTx.signature max_size:64 + +LiskTransactionCommon.recipient_id max_size:23 +LiskTransactionCommon.sender_public_key max_size:32 +LiskTransactionCommon.requester_public_key max_size:32 +LiskTransactionCommon.signature max_size:64 + +LiskTransactionAsset.data max_size:64 +LiskTransactionAsset.votes max_count:33 max_size:66 + +LiskSignatureType.public_key max_size:32 +LiskDelegateType.username max_size:20 +LiskMultisignatureType.keys_group max_count:10 max_size:66 diff --git a/firmware/protob/messages-lisk.proto b/firmware/protob/messages-lisk.proto new file mode 120000 index 0000000000..9214fc8b26 --- /dev/null +++ b/firmware/protob/messages-lisk.proto @@ -0,0 +1 @@ +../../vendor/trezor-common/protob/messages-lisk.proto \ No newline at end of file From a4058e1061d6cfd3d03f7d82126335d8d9a6c672 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 14 Sep 2018 13:53:14 +0200 Subject: [PATCH 0975/1154] lisk: cleanup code --- firmware/fsm_msg_lisk.h | 119 ++++++++------- firmware/lisk.c | 202 ++++++++++---------------- firmware/lisk.h | 17 +-- firmware/protob/messages-lisk.options | 8 +- 4 files changed, 151 insertions(+), 195 deletions(-) diff --git a/firmware/fsm_msg_lisk.h b/firmware/fsm_msg_lisk.h index 667e295452..60649cb4dd 100644 --- a/firmware/fsm_msg_lisk.h +++ b/firmware/fsm_msg_lisk.h @@ -1,48 +1,63 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 alepop + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + void fsm_msgLiskGetAddress(LiskGetAddress *msg) { - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskAddress); + RESP_INIT(LiskAddress); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; - resp->has_address = true; - - if (!hdnode_get_lisk_address(node, resp->address)) - return; + resp->has_address = true; + hdnode_fill_public_key(node); + lisk_get_address_from_public_key(&node->public_key[1], resp->address); if (msg->has_show_display && msg->show_display) { - char desc[16]; - strlcpy(desc, "Address:", sizeof(desc)); - - if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count)) { return; } } - msg_write(MessageType_MessageType_LiskAddress, resp); + msg_write(MessageType_MessageType_LiskAddress, resp); - layoutHome(); + layoutHome(); } void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg) { - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskPublicKey); + RESP_INIT(LiskPublicKey); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - resp->has_public_key = true; - resp->public_key.size = 32; + resp->has_public_key = true; + resp->public_key.size = 32; if (msg->has_show_display && msg->show_display) { layoutLiskPublicKey(&node->public_key[1]); @@ -53,57 +68,57 @@ void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg) } } - memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); + memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); - msg_write(MessageType_MessageType_LiskPublicKey, resp); + msg_write(MessageType_MessageType_LiskPublicKey, resp); - layoutHome(); + layoutHome(); } void fsm_msgLiskSignMessage(LiskSignMessage *msg) { - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskMessageSignature); + RESP_INIT(LiskMessageSignature); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - lisk_sign_message(node, msg, resp); + lisk_sign_message(node, msg, resp); - msg_write(MessageType_MessageType_LiskMessageSignature, resp); + msg_write(MessageType_MessageType_LiskMessageSignature, resp); - layoutHome(); + layoutHome(); } void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg) { - if (lisk_verify_message(msg)) { - char address[23]; - lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); + if (lisk_verify_message(msg)) { + char address[MAX_LISK_ADDRESS_SIZE]; + lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); - layoutLiskVerifyAddress(address); + layoutLiskVerifyAddress(address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - layoutVerifyMessage(msg->message.bytes, msg->message.size); + layoutVerifyMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - fsm_sendSuccess(_("Message verified")); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - } + fsm_sendSuccess(_("Message verified")); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + } - layoutHome(); + layoutHome(); } void fsm_msgLiskSignTx(LiskSignTx *msg) @@ -112,16 +127,16 @@ void fsm_msgLiskSignTx(LiskSignTx *msg) CHECK_PIN - RESP_INIT(LiskSignedTx); + RESP_INIT(LiskSignedTx); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - lisk_sign_tx(node, msg, resp); + lisk_sign_tx(node, msg, resp); - msg_write(MessageType_MessageType_LiskSignedTx, resp); + msg_write(MessageType_MessageType_LiskSignedTx, resp); - layoutHome(); + layoutHome(); } diff --git a/firmware/lisk.c b/firmware/lisk.c index ad43d9c80c..3bc7777aee 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -1,7 +1,7 @@ /* * This file is part of the TREZOR project, https://trezor.io/ * - * Copyright (C) 2017 Saleem Rashid + * Copyright (C) 2018 alepop * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -16,9 +16,9 @@ * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ -#include #include "lisk.h" +#include "fsm.h" #include "curves.h" #include "layout2.h" #include "bitmaps.h" @@ -28,33 +28,10 @@ #include "protect.h" #include "messages.pb.h" -int hdnode_get_lisk_address(HDNode *node, char *address) { - if (node->curve != get_curve_by_name(ED25519_NAME)) { - return 0; - } - hdnode_fill_public_key(node); - lisk_get_address_from_public_key(&node->public_key[1], address); - return 1; -} - -void lisk_get_address_from_public_key(const uint8_t* public_key, char *address) { - uint8_t digest[32]; - uint8_t address_bytes[8]; - - sha256_Raw(public_key, 32, digest); - - uint8_t i; - for (i = 0; i < 8; i++) { - address_bytes[i] = digest[ 7 - i]; - } - - uint64_t encodedAddress = 0; - for (i = 0; i < 8; i++ ) { - encodedAddress = encodedAddress << 8; - encodedAddress += address_bytes[i]; - } - - bn_format_uint64(encodedAddress, NULL, "L", 0, 0, false, address, 23); +void lisk_get_address_from_public_key(const uint8_t *public_key, char *address) { + uint64_t digest[4]; + sha256_Raw(public_key, 32, (uint8_t *)digest); + bn_format_uint64(digest[0], NULL, "L", 0, 0, false, address, MAX_LISK_ADDRESS_SIZE); } void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) { @@ -69,7 +46,7 @@ void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[ sha256_Raw(hash, 32, hash); } -void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp) +void lisk_sign_message(const HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp) { layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -84,9 +61,9 @@ void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature uint8_t hash[32]; lisk_message_hash(msg->message.bytes, msg->message.size, hash); - ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); - memcpy(resp->signature.bytes, signature, sizeof(signature)); + memcpy(resp->signature.bytes, signature, sizeof(signature)); memcpy(resp->public_key.bytes, &node->public_key[1], 32); resp->has_signature = true; @@ -99,16 +76,10 @@ bool lisk_verify_message(LiskVerifyMessage *msg) { uint8_t hash[32]; lisk_message_hash(msg->message.bytes, msg->message.size, hash); - - return ed25519_sign_open( - hash, - 32, - msg->public_key.bytes, - msg->signature.bytes - ) == 0; + return 0 == ed25519_sign_open(hash, 32, msg->public_key.bytes, msg->signature.bytes ); } -void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg) +static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) { if(!msg->transaction.has_sender_public_key) { memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32); @@ -116,105 +87,86 @@ void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg) // For CastVotes transactions, recipientId should be equal to transaction creator address. if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) { - char address[23]; + char address[MAX_LISK_ADDRESS_SIZE]; lisk_get_address_from_public_key(&node->public_key[1], address); memcpy(msg->transaction.recipient_id, address, sizeof(address)); msg->transaction.has_recipient_id = true; } } -void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value) +static void lisk_hashupdate_uint32(SHA256_CTX *ctx, uint32_t value) { uint8_t data[4]; write_le(data, value); sha256_Update(ctx, data, sizeof(data)); } -void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i) +static void lisk_hashupdate_uint64_le(SHA256_CTX *ctx, uint64_t value) +{ + sha256_Update(ctx, (uint8_t *)&value, sizeof(uint64_t)); +} + +static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value) { uint8_t data[8]; - // i = true ? big-endian : little-endian - data[i ? 0 : 7] = (value >> 56); - data[i ? 1 : 6] = (value >> 48); - data[i ? 2 : 5] = (value >> 40); - data[i ? 3 : 4] = (value >> 32); - data[i ? 4 : 3] = (value >> 24); - data[i ? 5 : 2] = (value >> 16); - data[i ? 6 : 1] = (value >> 8); - data[i ? 7 : 0] = value; + data[0] = value >> 56; + data[1] = value >> 48; + data[2] = value >> 40; + data[3] = value >> 32; + data[4] = value >> 24; + data[5] = value >> 16; + data[6] = value >> 8; + data[7] = value; sha256_Update(ctx, data, sizeof(data)); } -void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset) +static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, LiskTransactionAsset *asset) { switch (type) { case LiskTransactionType_Transfer: if (asset->has_data) { sha256_Update(ctx, (const uint8_t *)asset->data, strlen(asset->data)); } - break; + break; case LiskTransactionType_RegisterDelegate: if (asset->has_delegate && asset->delegate.has_username) { sha256_Update(ctx, (const uint8_t *)asset->delegate.username, strlen(asset->delegate.username)); } - break; + break; case LiskTransactionType_CastVotes: { - char str[asset->votes_count * 66]; - strlcpy(str, asset->votes[0], sizeof(str)); - for (int i = 1; i < asset->votes_count; i++) { - strlcat(str, asset->votes[i], sizeof(str)); - }; - sha256_Update(ctx, (const uint8_t *)str, strlen(str)); - break; + for (int i = 0; i < asset->votes_count; i++) { + sha256_Update(ctx, (uint8_t *)asset->votes[i], strlen(asset->votes[i])); + } + break; } case LiskTransactionType_RegisterSecondPassphrase: if (asset->has_signature && asset->signature.has_public_key) { sha256_Update(ctx, asset->signature.public_key.bytes, asset->signature.public_key.size); } - break; - case LiskTransactionType_RegisterMultisignatureAccount: { + break; + case LiskTransactionType_RegisterMultisignatureAccount: if (asset->has_multisignature) { - char str[asset->multisignature.keys_group_count * 66 + 4 + 4]; - uint8_t min[4]; - uint8_t life_time[4]; - - // convert uint32_t to uint8_t - write_le(min, asset->multisignature.min); - write_le(life_time, asset->multisignature.life_time); - - // calculate sha from min + life_time + keys_group - strlcpy(str, (const char *)min, sizeof(str)); - strlcat(str, (const char *)life_time, sizeof(str)); + sha256_Update(ctx, (uint8_t *)&(asset->multisignature.min), 1); + sha256_Update(ctx, (uint8_t *)&(asset->multisignature.life_time), 1); for (int i = 0; i < asset->multisignature.keys_group_count; i++) { - strlcat(str, asset->multisignature.keys_group[i], sizeof(str)); + sha256_Update(ctx, (uint8_t *)asset->multisignature.keys_group[i], strlen(asset->multisignature.keys_group[i])); }; - - sha256_Update(ctx, (const uint8_t *)str, strlen(str)); } - break; - } + break; default: fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); - break; + break; } } -void lisk_format_value(uint64_t value, char *formated_value) +#define MAX_LISK_VALUE_SIZE 20 + +static void lisk_format_value(uint64_t value, char *formated_value) { - bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, 20); + bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, MAX_LISK_VALUE_SIZE); } -void liks_get_vote_txt(char *prefix, int num, char *txt, size_t size) -{ - char buffer[4]; - sprintf(buffer, "%d", num); - - strlcpy(txt, prefix, size); - strlcat(txt, buffer, size); - strlcat(txt, (num != 1) ? " votes" : " vote", size); -} - -void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) +void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) { lisk_update_raw_tx(node, msg); @@ -233,7 +185,7 @@ void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) layoutRequireConfirmCastVotes(&msg->transaction.asset); break; case LiskTransactionType_RegisterSecondPassphrase: - layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes ); + layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes); break; case LiskTransactionType_RegisterMultisignatureAccount: layoutRequireConfirmMultisig(&msg->transaction.asset); @@ -248,14 +200,14 @@ void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) ButtonRequestType_ButtonRequest_PublicKey : ButtonRequestType_ButtonRequest_SignTx), false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); layoutHome(); return; } layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing Canceled"); + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); layoutHome(); return; } @@ -273,11 +225,19 @@ void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) uint64_t recipient_id = 0; if (msg->transaction.has_recipient_id) { - // parse integer from lisk address (string -> number) - sscanf(msg->transaction.recipient_id, "%llu", (long long unsigned int *)&recipient_id ); + // parse integer from lisk address ("123L" -> 123) + for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) { + if (msg->transaction.recipient_id[i] < '0' || msg->transaction.recipient_id[i] > '9') { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid recipient_id")); + layoutHome(); + return; + } + recipient_id *= 10; + recipient_id += (msg->transaction.recipient_id[i] - '0'); + } } - lisk_hashupdate_uint64(&ctx, recipient_id, true); - lisk_hashupdate_uint64(&ctx, msg->transaction.amount, false); + lisk_hashupdate_uint64_be(&ctx, recipient_id); + lisk_hashupdate_uint64_le(&ctx, msg->transaction.amount); lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset); @@ -286,13 +246,10 @@ void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) sha256_Update(&ctx, msg->transaction.signature.bytes, msg->transaction.signature.size); } - uint8_t signature[64]; uint8_t hash[32]; - sha256_Final(&ctx, hash); - ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], resp->signature.bytes); - memcpy(resp->signature.bytes, signature, sizeof(signature)); resp->has_signature = true; resp->signature.size = 64; } @@ -301,12 +258,11 @@ void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) // Layouts void layoutLiskPublicKey(const uint8_t *pubkey) { - char hex[32 * 2 + 1], desc[13]; - strlcpy(desc, "Public Key:", sizeof(desc)); + char hex[32 * 2 + 1]; data2hex(pubkey, 32, hex); const char **str = split_message((const uint8_t *)hex, 32 * 2, 16); layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, - desc, str[0], str[1], str[2], str[3], NULL); + _("Public Key:"), str[0], str[1], str[2], str[3], NULL); } void layoutLiskVerifyAddress(const char *address) @@ -320,7 +276,7 @@ void layoutLiskVerifyAddress(const char *address) void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) { - char formated_amount[20]; + char formated_amount[MAX_LISK_VALUE_SIZE]; const char **str = split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16); lisk_format_value(amount, formated_amount); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), @@ -336,8 +292,8 @@ void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) { - char formated_amount[20]; - char formated_fee[20]; + char formated_amount[MAX_LISK_VALUE_SIZE]; + char formated_fee[MAX_LISK_VALUE_SIZE]; lisk_format_value(amount, formated_amount); lisk_format_value(fee, formated_fee); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), @@ -375,15 +331,15 @@ void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) char remove_votes_txt[16]; for (int i = 0; i < asset->votes_count; i++) { - if (strncmp(asset->votes[i], "+", 1) == 0) { + if (asset->votes[i][0] == '+') { plus += 1; } else { minus += 1; } } - liks_get_vote_txt("Add ", plus, add_votes_txt, sizeof(add_votes_txt)); - liks_get_vote_txt("Remove ", minus, remove_votes_txt, sizeof(remove_votes_txt)); + bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_votes_txt, sizeof(add_votes_txt)); + bn_format_uint64(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt, sizeof(remove_votes_txt)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, @@ -398,23 +354,13 @@ void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) { - char keys_group_str[22]; + char keys_group_str[25]; char life_time_str[14]; char min_str[8]; - char buffer[8]; - strlcpy(keys_group_str, "Keys group length: ", sizeof(keys_group_str)); - strlcpy(life_time_str, "Life time: ", sizeof(life_time_str)); - strlcpy(min_str, "Min: ", sizeof(min_str)); - - sprintf(buffer, "%u", (unsigned int)asset->multisignature.keys_group_count); - strlcat(keys_group_str, buffer, sizeof(keys_group_str)); - - sprintf(buffer, "%u", (unsigned int)asset->multisignature.life_time); - strlcat(life_time_str, buffer, sizeof(life_time_str)); - - sprintf(buffer, "%u", (unsigned int)asset->multisignature.min); - strlcat(min_str, buffer, sizeof(min_str)); + bn_format_uint64(asset->multisignature.keys_group_count, "Keys group length: ", NULL, 0, 0, false, keys_group_str, sizeof(keys_group_str)); + bn_format_uint64(asset->multisignature.life_time, "Life time: ", NULL, 0, 0, false, life_time_str, sizeof(life_time_str)); + bn_format_uint64(asset->multisignature.min, "Min: ", NULL, 0, 0, false, min_str, sizeof(min_str)); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, diff --git a/firmware/lisk.h b/firmware/lisk.h index db7d2a004d..0c571db707 100644 --- a/firmware/lisk.h +++ b/firmware/lisk.h @@ -1,5 +1,7 @@ /* - * This file is part of the TREZOR project. + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2018 alepop * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -20,23 +22,16 @@ #include #include "bip32.h" -#include "fsm.h" #include "messages-lisk.pb.h" -// Main -int hdnode_get_lisk_address(HDNode *node, char *address); +#define MAX_LISK_ADDRESS_SIZE 23 -void lisk_sign_message(HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp); +void lisk_sign_message(const HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp); bool lisk_verify_message(LiskVerifyMessage *msg); -void lisk_sign_tx(HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); +void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); // Helpers void lisk_get_address_from_public_key(const uint8_t *public_key, char *address); -void lisk_format_value(uint64_t value, char *formated_value); -void lisk_update_raw_tx(HDNode *node, LiskSignTx *msg); -void lisk_hashupdate_uint64(SHA256_CTX* ctx, uint64_t value, bool i); -void lisk_hashupdate_uint32(SHA256_CTX* ctx, uint32_t value); -void lisk_hashupdate_asset(SHA256_CTX* ctx, LiskTransactionType type, LiskTransactionAsset *asset); // Layout void layoutLiskPublicKey(const uint8_t *pubkey); diff --git a/firmware/protob/messages-lisk.options b/firmware/protob/messages-lisk.options index a3860d57b4..489c2ac685 100644 --- a/firmware/protob/messages-lisk.options +++ b/firmware/protob/messages-lisk.options @@ -1,11 +1,11 @@ -LiskGetAddress.address_n max_count:8 -LiskAddress.address max_size:23 +LiskGetAddress.address_n max_count:8 +LiskAddress.address max_size:23 LiskGetPublicKey.address_n max_count:8 LiskPublicKey.public_key max_size:32 -LiskSignMessage.address_n max_count:8 -LiskSignMessage.message max_size:1024 +LiskSignMessage.address_n max_count:8 +LiskSignMessage.message max_size:1024 LiskMessageSignature.public_key max_size:32 LiskMessageSignature.signature max_size:64 From 7b4f02744582b223cbb8da4edb94e58a7387e1a3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 14 Sep 2018 14:40:29 +0200 Subject: [PATCH 0976/1154] fsm: use const where applicable, document where it isn't and why --- firmware/ethereum.c | 6 +- firmware/ethereum.h | 6 +- firmware/fsm.h | 146 ++++++++++++++++++------------------ firmware/fsm_msg_coin.h | 10 +-- firmware/fsm_msg_common.h | 34 ++++----- firmware/fsm_msg_crypto.h | 99 +----------------------- firmware/fsm_msg_debug.h | 10 +-- firmware/fsm_msg_ethereum.h | 8 +- firmware/fsm_msg_lisk.h | 8 +- firmware/fsm_msg_stellar.h | 68 ++++------------- firmware/lisk.c | 4 +- firmware/lisk.h | 4 +- firmware/signing.c | 2 +- firmware/stellar.c | 42 +++++------ firmware/stellar.h | 42 +++++------ firmware/storage.c | 2 +- firmware/storage.h | 2 +- 17 files changed, 182 insertions(+), 311 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 4995e1e9b4..ee58c0b4f6 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -584,7 +584,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } } -void ethereum_signing_txack(EthereumTxAck *tx) +void ethereum_signing_txack(const EthereumTxAck *tx) { if (!ethereum_signing) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); @@ -644,7 +644,7 @@ static void ethereum_message_hash(const uint8_t *message, size_t message_len, ui keccak_Final(&ctx, hash); } -void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) { uint8_t hash[32]; @@ -667,7 +667,7 @@ void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, Ethereu msg_write(MessageType_MessageType_EthereumMessageSignature, resp); } -int ethereum_message_verify(EthereumVerifyMessage *msg) +int ethereum_message_verify(const EthereumVerifyMessage *msg) { if (msg->signature.size != 65 || msg->address.size != 20) { fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); diff --git a/firmware/ethereum.h b/firmware/ethereum.h index 374c885e67..f36b4e34ff 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -27,9 +27,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); void ethereum_signing_abort(void); -void ethereum_signing_txack(EthereumTxAck *msg); +void ethereum_signing_txack(const EthereumTxAck *msg); -void ethereum_message_sign(EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); -int ethereum_message_verify(EthereumVerifyMessage *msg); +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); +int ethereum_message_verify(const EthereumVerifyMessage *msg); #endif diff --git a/firmware/fsm.h b/firmware/fsm.h index f1484903f8..75de088c51 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -41,82 +41,86 @@ void fsm_sendFailureDebug(FailureType code, const char *text, const char *source void fsm_sendFailure(FailureType code, const char *text); #endif -void fsm_msgInitialize(Initialize *msg); -void fsm_msgGetFeatures(GetFeatures *msg); -void fsm_msgPing(Ping *msg); -void fsm_msgChangePin(ChangePin *msg); -void fsm_msgWipeDevice(WipeDevice *msg); -void fsm_msgGetEntropy(GetEntropy *msg); -void fsm_msgGetPublicKey(GetPublicKey *msg); -void fsm_msgLoadDevice(LoadDevice *msg); -void fsm_msgResetDevice(ResetDevice *msg); -void fsm_msgBackupDevice(BackupDevice *msg); -void fsm_msgSignTx(SignTx *msg); -//void fsm_msgPinMatrixAck(PinMatrixAck *msg); -void fsm_msgCancel(Cancel *msg); -void fsm_msgTxAck(TxAck *msg); -void fsm_msgCipherKeyValue(CipherKeyValue *msg); -void fsm_msgClearSession(ClearSession *msg); -void fsm_msgApplySettings(ApplySettings *msg); -void fsm_msgApplyFlags(ApplyFlags *msg); -//void fsm_msgButtonAck(ButtonAck *msg); -void fsm_msgGetAddress(GetAddress *msg); -void fsm_msgEntropyAck(EntropyAck *msg); -void fsm_msgSignMessage(SignMessage *msg); -void fsm_msgVerifyMessage(VerifyMessage *msg); -void fsm_msgSignIdentity(SignIdentity *msg); -void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg); -/* ECIES disabled -void fsm_msgEncryptMessage(EncryptMessage *msg); -void fsm_msgDecryptMessage(DecryptMessage *msg); -*/ -//void fsm_msgPassphraseAck(PassphraseAck *msg); -void fsm_msgRecoveryDevice(RecoveryDevice *msg); -void fsm_msgWordAck(WordAck *msg); -void fsm_msgSetU2FCounter(SetU2FCounter *msg); -void fsm_msgEthereumGetAddress(EthereumGetAddress *msg); -void fsm_msgEthereumSignTx(EthereumSignTx *msg); -void fsm_msgEthereumTxAck(EthereumTxAck *msg); -void fsm_msgEthereumSignMessage(EthereumSignMessage *msg); -void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg); +// void fsm_msgPinMatrixAck(const PinMatrixAck *msg); // tiny +// void fsm_msgButtonAck(const ButtonAck *msg); // tiny +// void fsm_msgPassphraseAck(const PassphraseAck *msg); // tiny -void fsm_msgNEMGetAddress(NEMGetAddress *msg); -void fsm_msgNEMSignTx(NEMSignTx *msg); -void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); +// common +void fsm_msgInitialize(const Initialize *msg); +void fsm_msgGetFeatures(const GetFeatures *msg); +void fsm_msgPing(const Ping *msg); +void fsm_msgChangePin(const ChangePin *msg); +void fsm_msgWipeDevice(const WipeDevice *msg); +void fsm_msgGetEntropy(const GetEntropy *msg); +void fsm_msgLoadDevice(const LoadDevice *msg); +void fsm_msgResetDevice(const ResetDevice *msg); +void fsm_msgEntropyAck(const EntropyAck *msg); +void fsm_msgBackupDevice(const BackupDevice *msg); +void fsm_msgCancel(const Cancel *msg); +void fsm_msgClearSession(const ClearSession *msg); +void fsm_msgApplySettings(const ApplySettings *msg); +void fsm_msgApplyFlags(const ApplyFlags *msg); +void fsm_msgRecoveryDevice(const RecoveryDevice *msg); +void fsm_msgWordAck(const WordAck *msg); +void fsm_msgSetU2FCounter(const SetU2FCounter *msg); -void fsm_msgCosiCommit(CosiCommit *msg); -void fsm_msgCosiSign(CosiSign *msg); +// coin +void fsm_msgGetPublicKey(const GetPublicKey *msg); +void fsm_msgSignTx(const SignTx *msg); +void fsm_msgTxAck(TxAck *msg); // not const because we mutate input/output scripts +void fsm_msgGetAddress(const GetAddress *msg); +void fsm_msgSignMessage(const SignMessage *msg); +void fsm_msgVerifyMessage(const VerifyMessage *msg); -// Stellar -void fsm_msgStellarGetAddress(StellarGetAddress *msg); -void fsm_msgStellarSignTx(StellarSignTx *msg); -void fsm_msgStellarPaymentOp(StellarPaymentOp *msg); -void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg); -void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg); -void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg); -void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); -void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg); -void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg); -void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg); -void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg); -void fsm_msgStellarManageDataOp(StellarManageDataOp *msg); -void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg); +// crypto +void fsm_msgCipherKeyValue(CipherKeyValue *msg); // not const because we mutate msg->iv +void fsm_msgSignIdentity(const SignIdentity *msg); +void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg); +void fsm_msgCosiCommit(const CosiCommit *msg); +void fsm_msgCosiSign(const CosiSign *msg); -// Lisk -void fsm_msgLiskGetAddress(LiskGetAddress *msg); -void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg); -void fsm_msgLiskSignMessage(LiskSignMessage *msg); -void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg); -void fsm_msgLiskSignTx(LiskSignTx *msg); - -// debug message functions +// debug #if DEBUG_LINK -//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); -void fsm_msgDebugLinkGetState(DebugLinkGetState *msg); -void fsm_msgDebugLinkStop(DebugLinkStop *msg); -void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg); -void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg); -void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg); +// void fsm_msgDebugLinkDecision(const DebugLinkDecision *msg); // tiny +void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg); +void fsm_msgDebugLinkStop(const DebugLinkStop *msg); +void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg); +void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg); +void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg); #endif +// ethereum +void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg); +void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction +void fsm_msgEthereumTxAck(const EthereumTxAck *msg); +void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg); +void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg); + +// lisk +void fsm_msgLiskGetAddress(const LiskGetAddress *msg); +void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg); +void fsm_msgLiskSignMessage(const LiskSignMessage *msg); +void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg); +void fsm_msgLiskSignTx(LiskSignTx *msg); // // not const because we mutate transaction + +// nem +void fsm_msgNEMGetAddress(NEMGetAddress *msg); // not const because we mutate msg->network +void fsm_msgNEMSignTx(NEMSignTx *msg); // not const because we mutate msg->network +void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); // not const because we mutate msg->payload + +// stellar +void fsm_msgStellarGetAddress(const StellarGetAddress *msg); +void fsm_msgStellarSignTx(const StellarSignTx *msg); +void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg); +void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg); +void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg); +void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg); +void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg); +void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg); +void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg); +void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg); +void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg); +void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg); +void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg); + #endif diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 8c810205bd..d6ff406adf 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -void fsm_msgGetPublicKey(GetPublicKey *msg) +void fsm_msgGetPublicKey(const GetPublicKey *msg) { RESP_INIT(PublicKey); @@ -81,7 +81,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg) layoutHome(); } -void fsm_msgSignTx(SignTx *msg) +void fsm_msgSignTx(const SignTx *msg) { CHECK_INITIALIZED @@ -181,7 +181,7 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) return false; } -void fsm_msgGetAddress(GetAddress *msg) +void fsm_msgGetAddress(const GetAddress *msg) { RESP_INIT(Address); @@ -242,7 +242,7 @@ void fsm_msgGetAddress(GetAddress *msg) layoutHome(); } -void fsm_msgSignMessage(SignMessage *msg) +void fsm_msgSignMessage(const SignMessage *msg) { // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings")); @@ -282,7 +282,7 @@ void fsm_msgSignMessage(SignMessage *msg) layoutHome(); } -void fsm_msgVerifyMessage(VerifyMessage *msg) +void fsm_msgVerifyMessage(const VerifyMessage *msg) { CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided")); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index e9795c79f6..a9889de583 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -void fsm_msgInitialize(Initialize *msg) +void fsm_msgInitialize(const Initialize *msg) { recovery_abort(); signing_abort(); @@ -37,7 +37,7 @@ void fsm_msgInitialize(Initialize *msg) fsm_msgGetFeatures(0); } -void fsm_msgGetFeatures(GetFeatures *msg) +void fsm_msgGetFeatures(const GetFeatures *msg) { (void)msg; RESP_INIT(Features); @@ -74,7 +74,7 @@ void fsm_msgGetFeatures(GetFeatures *msg) msg_write(MessageType_MessageType_Features, resp); } -void fsm_msgPing(Ping *msg) +void fsm_msgPing(const Ping *msg) { RESP_INIT(Success); @@ -106,7 +106,7 @@ void fsm_msgPing(Ping *msg) layoutHome(); } -void fsm_msgChangePin(ChangePin *msg) +void fsm_msgChangePin(const ChangePin *msg) { bool removal = msg->has_remove && msg->remove; if (removal) { @@ -145,7 +145,7 @@ void fsm_msgChangePin(ChangePin *msg) layoutHome(); } -void fsm_msgWipeDevice(WipeDevice *msg) +void fsm_msgWipeDevice(const WipeDevice *msg) { (void)msg; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); @@ -161,7 +161,7 @@ void fsm_msgWipeDevice(WipeDevice *msg) layoutHome(); } -void fsm_msgGetEntropy(GetEntropy *msg) +void fsm_msgGetEntropy(const GetEntropy *msg) { #if !DEBUG_RNG layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); @@ -182,7 +182,7 @@ void fsm_msgGetEntropy(GetEntropy *msg) layoutHome(); } -void fsm_msgLoadDevice(LoadDevice *msg) +void fsm_msgLoadDevice(const LoadDevice *msg) { CHECK_NOT_INITIALIZED @@ -206,7 +206,7 @@ void fsm_msgLoadDevice(LoadDevice *msg) layoutHome(); } -void fsm_msgResetDevice(ResetDevice *msg) +void fsm_msgResetDevice(const ResetDevice *msg) { CHECK_NOT_INITIALIZED @@ -224,7 +224,7 @@ void fsm_msgResetDevice(ResetDevice *msg) ); } -void fsm_msgEntropyAck(EntropyAck *msg) +void fsm_msgEntropyAck(const EntropyAck *msg) { if (msg->has_entropy) { reset_entropy(msg->entropy.bytes, msg->entropy.size); @@ -233,7 +233,7 @@ void fsm_msgEntropyAck(EntropyAck *msg) } } -void fsm_msgBackupDevice(BackupDevice *msg) +void fsm_msgBackupDevice(const BackupDevice *msg) { CHECK_INITIALIZED @@ -243,7 +243,7 @@ void fsm_msgBackupDevice(BackupDevice *msg) reset_backup(true); } -void fsm_msgCancel(Cancel *msg) +void fsm_msgCancel(const Cancel *msg) { (void)msg; recovery_abort(); @@ -252,7 +252,7 @@ void fsm_msgCancel(Cancel *msg) fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } -void fsm_msgClearSession(ClearSession *msg) +void fsm_msgClearSession(const ClearSession *msg) { (void)msg; session_clear(true); // clear PIN as well @@ -260,7 +260,7 @@ void fsm_msgClearSession(ClearSession *msg) fsm_sendSuccess(_("Session cleared")); } -void fsm_msgApplySettings(ApplySettings *msg) +void fsm_msgApplySettings(const ApplySettings *msg) { CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, _("No setting provided")); @@ -329,7 +329,7 @@ void fsm_msgApplySettings(ApplySettings *msg) layoutHome(); } -void fsm_msgApplyFlags(ApplyFlags *msg) +void fsm_msgApplyFlags(const ApplyFlags *msg) { if (msg->has_flags) { storage_applyFlags(msg->flags); @@ -337,7 +337,7 @@ void fsm_msgApplyFlags(ApplyFlags *msg) fsm_sendSuccess(_("Flags applied")); } -void fsm_msgRecoveryDevice(RecoveryDevice *msg) +void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { const bool dry_run = msg->has_dry_run ? msg->dry_run : false; if (dry_run) { @@ -370,12 +370,12 @@ void fsm_msgRecoveryDevice(RecoveryDevice *msg) ); } -void fsm_msgWordAck(WordAck *msg) +void fsm_msgWordAck(const WordAck *msg) { recovery_word(msg->word); } -void fsm_msgSetU2FCounter(SetU2FCounter *msg) +void fsm_msgSetU2FCounter(const SetU2FCounter *msg) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index 2d3ddc059e..006cbc09fa 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -65,7 +65,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) layoutHome(); } -void fsm_msgSignIdentity(SignIdentity *msg) +void fsm_msgSignIdentity(const SignIdentity *msg) { RESP_INIT(SignedIdentity); @@ -141,7 +141,7 @@ void fsm_msgSignIdentity(SignIdentity *msg) layoutHome(); } -void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) +void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) { RESP_INIT(ECDHSessionKey); @@ -189,98 +189,7 @@ void fsm_msgGetECDHSessionKey(GetECDHSessionKey *msg) layoutHome(); } -/* ECIES disabled -void fsm_msgEncryptMessage(EncryptMessage *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_pubkey, _("No public key provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - CHECK_PARAM(msg->pubkey.size == 33, _("Invalid public key provided")); - curve_point pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 1, _("Invalid public key provided")); - - bool display_only = msg->has_display_only && msg->display_only; - bool signing = msg->address_n_count > 0; - RESP_INIT(EncryptedMessage); - const HDNode *node = 0; - uint8_t address_raw[MAX_ADDR_RAW_SIZE]; - if (signing) { - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - - CHECK_PIN - - node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_get_address_raw(node, coin->address_type, address_raw); - } - layoutEncryptMessage(msg->message.bytes, msg->message.size, signing); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutProgressSwipe(_("Encrypting"), 0); - if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error encrypting message")); - layoutHome(); - return; - } - resp->has_nonce = true; - resp->has_message = true; - resp->has_hmac = true; - msg_write(MessageType_MessageType_EncryptedMessage, resp); - layoutHome(); -} - -void fsm_msgDecryptMessage(DecryptMessage *msg) -{ - CHECK_INITIALIZED - - CHECK_PARAM(msg->has_nonce, _("No nonce provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); - CHECK_PARAM(msg->has_hmac, _("No message hmac provided")); - - CHECK_PARAM(msg->nonce.size == 33, _("Invalid nonce key provided")); - curve_point nonce_pubkey; - CHECK_PARAM(ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 1, _("Invalid nonce provided")); - - CHECK_PIN - - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - - layoutProgressSwipe(_("Decrypting"), 0); - RESP_INIT(DecryptedMessage); - bool display_only = false; - bool signing = false; - uint8_t address_raw[MAX_ADDR_RAW_SIZE]; - if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - if (signing) { - base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); - } - layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - if (display_only) { - resp->has_address = false; - resp->has_message = false; - memset(resp->address, 0, sizeof(resp->address)); - memset(&(resp->message), 0, sizeof(resp->message)); - } else { - resp->has_address = signing; - resp->has_message = true; - } - msg_write(MessageType_MessageType_DecryptedMessage, resp); - layoutHome(); -} -*/ - -void fsm_msgCosiCommit(CosiCommit *msg) +void fsm_msgCosiCommit(const CosiCommit *msg) { RESP_INIT(CosiCommitment); @@ -318,7 +227,7 @@ void fsm_msgCosiCommit(CosiCommit *msg) layoutHome(); } -void fsm_msgCosiSign(CosiSign *msg) +void fsm_msgCosiSign(const CosiSign *msg) { RESP_INIT(CosiSignature); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index ad52e8e373..29302bd4e1 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -19,7 +19,7 @@ #if DEBUG_LINK -void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) +void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) { (void)msg; @@ -68,12 +68,12 @@ void fsm_msgDebugLinkGetState(DebugLinkGetState *msg) msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } -void fsm_msgDebugLinkStop(DebugLinkStop *msg) +void fsm_msgDebugLinkStop(const DebugLinkStop *msg) { (void)msg; } -void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) +void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) { RESP_INIT(DebugLinkMemory); @@ -86,7 +86,7 @@ void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg) msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); } -void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) +void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) { uint32_t length = msg->memory.size; if (msg->flash) { @@ -106,7 +106,7 @@ void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg) } } -void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg) +void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) { svc_flash_unlock(); svc_flash_erase_sector(msg->sector); diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 6571d7035f..c3270da0e1 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -29,12 +29,12 @@ void fsm_msgEthereumSignTx(EthereumSignTx *msg) ethereum_signing_init(msg, node); } -void fsm_msgEthereumTxAck(EthereumTxAck *msg) +void fsm_msgEthereumTxAck(const EthereumTxAck *msg) { ethereum_signing_txack(msg); } -void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) +void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) { RESP_INIT(EthereumAddress); @@ -75,7 +75,7 @@ void fsm_msgEthereumGetAddress(EthereumGetAddress *msg) layoutHome(); } -void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) +void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) { RESP_INIT(EthereumMessageSignature); @@ -97,7 +97,7 @@ void fsm_msgEthereumSignMessage(EthereumSignMessage *msg) layoutHome(); } -void fsm_msgEthereumVerifyMessage(EthereumVerifyMessage *msg) +void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) { CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided")); diff --git a/firmware/fsm_msg_lisk.h b/firmware/fsm_msg_lisk.h index 60649cb4dd..e3ad8963be 100644 --- a/firmware/fsm_msg_lisk.h +++ b/firmware/fsm_msg_lisk.h @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -void fsm_msgLiskGetAddress(LiskGetAddress *msg) +void fsm_msgLiskGetAddress(const LiskGetAddress *msg) { CHECK_INITIALIZED @@ -43,7 +43,7 @@ void fsm_msgLiskGetAddress(LiskGetAddress *msg) layoutHome(); } -void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg) +void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) { CHECK_INITIALIZED @@ -75,7 +75,7 @@ void fsm_msgLiskGetPublicKey(LiskGetPublicKey *msg) layoutHome(); } -void fsm_msgLiskSignMessage(LiskSignMessage *msg) +void fsm_msgLiskSignMessage(const LiskSignMessage *msg) { CHECK_INITIALIZED @@ -95,7 +95,7 @@ void fsm_msgLiskSignMessage(LiskSignMessage *msg) layoutHome(); } -void fsm_msgLiskVerifyMessage(LiskVerifyMessage *msg) +void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) { if (lisk_verify_message(msg)) { char address[MAX_LISK_ADDRESS_SIZE]; diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index 4e967ae32d..e05d14dd8b 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -void fsm_msgStellarGetAddress(StellarGetAddress *msg) +void fsm_msgStellarGetAddress(const StellarGetAddress *msg) { RESP_INIT(StellarAddress); @@ -55,49 +55,7 @@ void fsm_msgStellarGetAddress(StellarGetAddress *msg) layoutHome(); } -// void fsm_msgStellarGetPublicKey(StellarGetPublicKey *msg) -// { -// RESP_INIT(StellarPublicKey); - -// CHECK_INITIALIZED - -// CHECK_PIN - -// HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); -// if (!node) { -// fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); -// return; -// } - -// if (msg->has_show_display && msg->show_display) { -// char hex[32 * 2 + 1]; -// data2hex(node->public_key + 1, 32, hex); -// const char **str_pubkey_rows = split_message((const uint8_t *)hex, 32 * 2, 16); -// layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), -// str_pubkey_rows[0], -// str_pubkey_rows[1], -// str_pubkey_rows[2], -// str_pubkey_rows[3], -// NULL, NULL -// ); -// if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { -// fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); -// layoutHome(); -// return; -// } -// } - -// // Read public key and write it to the response -// resp->has_public_key = true; -// resp->public_key.size = 32; -// memcpy(resp->public_key.bytes, node->public_key + 1, 32); - -// msg_write(MessageType_MessageType_StellarPublicKey, resp); - -// layoutHome(); -// } - -void fsm_msgStellarSignTx(StellarSignTx *msg) +void fsm_msgStellarSignTx(const StellarSignTx *msg) { CHECK_INITIALIZED CHECK_PIN @@ -113,7 +71,7 @@ void fsm_msgStellarSignTx(StellarSignTx *msg) msg_write(MessageType_MessageType_StellarTxOpRequest, resp); } -void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) +void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) { if (!stellar_confirmCreateAccountOp(msg)) return; @@ -132,7 +90,7 @@ void fsm_msgStellarCreateAccountOp(StellarCreateAccountOp *msg) } } -void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) +void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) { // This will display additional dialogs to the user if (!stellar_confirmPaymentOp(msg)) return; @@ -153,7 +111,7 @@ void fsm_msgStellarPaymentOp(StellarPaymentOp *msg) } } -void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) +void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) { if (!stellar_confirmPathPaymentOp(msg)) return; @@ -172,7 +130,7 @@ void fsm_msgStellarPathPaymentOp(StellarPathPaymentOp *msg) } } -void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) +void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) { if (!stellar_confirmManageOfferOp(msg)) return; @@ -191,7 +149,7 @@ void fsm_msgStellarManageOfferOp(StellarManageOfferOp *msg) } } -void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) { if (!stellar_confirmCreatePassiveOfferOp(msg)) return; @@ -210,7 +168,7 @@ void fsm_msgStellarCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) } } -void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) +void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) { if (!stellar_confirmSetOptionsOp(msg)) return; @@ -229,7 +187,7 @@ void fsm_msgStellarSetOptionsOp(StellarSetOptionsOp *msg) } } -void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) +void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) { if (!stellar_confirmChangeTrustOp(msg)) return; @@ -248,7 +206,7 @@ void fsm_msgStellarChangeTrustOp(StellarChangeTrustOp *msg) } } -void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) +void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) { if (!stellar_confirmAllowTrustOp(msg)) return; @@ -267,7 +225,7 @@ void fsm_msgStellarAllowTrustOp(StellarAllowTrustOp *msg) } } -void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) +void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) { if (!stellar_confirmAccountMergeOp(msg)) return; @@ -286,7 +244,7 @@ void fsm_msgStellarAccountMergeOp(StellarAccountMergeOp *msg) } } -void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) +void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) { if (!stellar_confirmManageDataOp(msg)) return; @@ -305,7 +263,7 @@ void fsm_msgStellarManageDataOp(StellarManageDataOp *msg) } } -void fsm_msgStellarBumpSequenceOp(StellarBumpSequenceOp *msg) +void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) { if (!stellar_confirmBumpSequenceOp(msg)) return; diff --git a/firmware/lisk.c b/firmware/lisk.c index 3bc7777aee..c40d73ff3b 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -46,7 +46,7 @@ void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[ sha256_Raw(hash, 32, hash); } -void lisk_sign_message(const HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp) +void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp) { layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { @@ -72,7 +72,7 @@ void lisk_sign_message(const HDNode *node, LiskSignMessage *msg, LiskMessageSign resp->public_key.size = 32; } -bool lisk_verify_message(LiskVerifyMessage *msg) +bool lisk_verify_message(const LiskVerifyMessage *msg) { uint8_t hash[32]; lisk_message_hash(msg->message.bytes, msg->message.size, hash); diff --git a/firmware/lisk.h b/firmware/lisk.h index 0c571db707..bac931eff2 100644 --- a/firmware/lisk.h +++ b/firmware/lisk.h @@ -26,8 +26,8 @@ #define MAX_LISK_ADDRESS_SIZE 23 -void lisk_sign_message(const HDNode *node, LiskSignMessage *msg, LiskMessageSignature *resp); -bool lisk_verify_message(LiskVerifyMessage *msg); +void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp); +bool lisk_verify_message(const LiskVerifyMessage *msg); void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); // Helpers diff --git a/firmware/signing.c b/firmware/signing.c index ddf3c7557a..ceb2b5171d 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -544,7 +544,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) #define MIN(a,b) (((a)<(b))?(a):(b)) -static bool signing_check_input(TxInputType *txinput) { +static bool signing_check_input(const TxInputType *txinput) { /* compute multisig fingerprint */ /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ if (txinput->has_multisig && !multisig_fp_mismatch) { diff --git a/firmware/stellar.c b/firmware/stellar.c index ff3f6fc621..77bb0649b5 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -52,7 +52,7 @@ static StellarTransaction stellar_activeTx; /* * Starts the signing process and parses the transaction header */ -void stellar_signingInit(StellarSignTx *msg) +void stellar_signingInit(const StellarSignTx *msg) { memset(&stellar_activeTx, 0, sizeof(StellarTransaction)); stellar_signing = true; @@ -155,7 +155,7 @@ void stellar_signingInit(StellarSignTx *msg) } } -bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) +bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account) { if (!has_source_account) { stellar_hashupdate_bool(false); @@ -188,7 +188,7 @@ bool stellar_confirmSourceAccount(bool has_source_account, char *str_account) return true; } -bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) +bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) { if (!stellar_signing) return false; @@ -239,7 +239,7 @@ bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg) return true; } -bool stellar_confirmPaymentOp(StellarPaymentOp *msg) +bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) { if (!stellar_signing) return false; @@ -300,7 +300,7 @@ bool stellar_confirmPaymentOp(StellarPaymentOp *msg) return true; } -bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) +bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg) { if (!stellar_signing) return false; @@ -400,7 +400,7 @@ bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg) return true; } -bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) +bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg) { if (!stellar_signing) return false; @@ -490,7 +490,7 @@ bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg) return true; } -bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) +bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) { if (!stellar_signing) return false; @@ -568,7 +568,7 @@ bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg) return true; } -bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) +bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) { if (!stellar_signing) return false; @@ -892,7 +892,7 @@ bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg) return true; } -bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) +bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) { if (!stellar_signing) return false; @@ -960,7 +960,7 @@ bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg) return true; } -bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) +bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) { if (!stellar_signing) return false; @@ -1036,7 +1036,7 @@ bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg) return true; } -bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) +bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) { if (!stellar_signing) return false; @@ -1077,7 +1077,7 @@ bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg) return true; } -bool stellar_confirmManageDataOp(StellarManageDataOp *msg) +bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) { if (!stellar_signing) return false; @@ -1151,7 +1151,7 @@ bool stellar_confirmManageDataOp(StellarManageDataOp *msg) return true; } -bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg) +bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) { if (!stellar_signing) return false; @@ -1312,7 +1312,7 @@ void stellar_format_uint64(uint64_t number, char *out, size_t outlen) * Breaks a 56 character address into 3 lines of lengths 16, 20, 20 * This is to allow a small label to be prepended to the first line */ -const char **stellar_lineBreakAddress(uint8_t *addrbytes) +const char **stellar_lineBreakAddress(const uint8_t *addrbytes) { char str_fulladdr[56+1]; static char rows[3][20+1]; @@ -1339,7 +1339,7 @@ const char **stellar_lineBreakAddress(uint8_t *addrbytes) * MOBI (G123456789000) * ALPHA12EXAMP (G0987) */ -void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len) +void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len) { char str_asset_code[12 + 1]; // truncated asset issuer, final length depends on length of asset code @@ -1383,7 +1383,7 @@ void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t l } } -size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen) +size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen) { // version + key bytes + checksum uint8_t keylen = 1 + 32 + 2; @@ -1446,7 +1446,7 @@ bool stellar_validateAddress(const char *str_address) /** * Converts a string address (G...) to the 32-byte raw address */ -bool stellar_getAddressBytes(char* str_address, uint8_t *out_bytes) +bool stellar_getAddressBytes(const char* str_address, uint8_t *out_bytes) { uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; @@ -1497,7 +1497,7 @@ uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) * * All paths must be hardened */ -HDNode *stellar_deriveNode(uint32_t *address_n, size_t address_n_count) +HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; const char *curve = "ed25519"; @@ -1597,7 +1597,7 @@ void stellar_hashupdate_address(uint8_t *address_bytes) * so if "TEST" is the asset code then the hashed value needs to be 4 bytes and not include the null * at the end of the string */ -void stellar_hashupdate_asset(StellarAssetType *asset) +void stellar_hashupdate_asset(const StellarAssetType *asset) { stellar_hashupdate_uint32(asset->type); @@ -1629,7 +1629,7 @@ void stellar_hashupdate_asset(StellarAssetType *asset) } } -void stellar_hashupdate_bytes(uint8_t *data, size_t len) +void stellar_hashupdate_bytes(const uint8_t *data, size_t len) { sha256_Update(&(stellar_activeTx.sha256_ctx), data, len); } @@ -1637,7 +1637,7 @@ void stellar_hashupdate_bytes(uint8_t *data, size_t len) /* * Displays a summary of the overall transaction */ -void stellar_layoutTransactionSummary(StellarSignTx *msg) +void stellar_layoutTransactionSummary(const StellarSignTx *msg) { char str_lines[5][32]; memset(str_lines, 0, sizeof(str_lines)); diff --git a/firmware/stellar.h b/firmware/stellar.h index af1349988a..17b6df06fb 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -53,39 +53,39 @@ typedef struct { } StellarTransaction; // Signing process -void stellar_signingInit(StellarSignTx *tx); +void stellar_signingInit(const StellarSignTx *tx); void stellar_signingAbort(const char *reason); -bool stellar_confirmSourceAccount(bool has_source_account, char *str_account); -bool stellar_confirmCreateAccountOp(StellarCreateAccountOp *msg); -bool stellar_confirmPaymentOp(StellarPaymentOp *msg); -bool stellar_confirmPathPaymentOp(StellarPathPaymentOp *msg); -bool stellar_confirmManageOfferOp(StellarManageOfferOp *msg); -bool stellar_confirmCreatePassiveOfferOp(StellarCreatePassiveOfferOp *msg); -bool stellar_confirmSetOptionsOp(StellarSetOptionsOp *msg); -bool stellar_confirmChangeTrustOp(StellarChangeTrustOp *msg); -bool stellar_confirmAllowTrustOp(StellarAllowTrustOp *msg); -bool stellar_confirmAccountMergeOp(StellarAccountMergeOp *msg); -bool stellar_confirmManageDataOp(StellarManageDataOp *msg); -bool stellar_confirmBumpSequenceOp(StellarBumpSequenceOp *msg); +bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account); +bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg); +bool stellar_confirmPaymentOp(const StellarPaymentOp *msg); +bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg); +bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg); +bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg); +bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg); +bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg); +bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg); +bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg); +bool stellar_confirmManageDataOp(const StellarManageDataOp *msg); +bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg); // Layout void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); -void stellar_layoutTransactionSummary(StellarSignTx *msg); +void stellar_layoutTransactionSummary(const StellarSignTx *msg); void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); // Helpers -HDNode *stellar_deriveNode(uint32_t *address_n, size_t address_n_count); +HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); -size_t stellar_publicAddressAsStr(uint8_t *bytes, char *out, size_t outlen); -const char **stellar_lineBreakAddress(uint8_t *addrbytes); +size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen); +const char **stellar_lineBreakAddress(const uint8_t *addrbytes); void stellar_hashupdate_uint32(uint32_t value); void stellar_hashupdate_uint64(uint64_t value); void stellar_hashupdate_bool(bool value); void stellar_hashupdate_string(uint8_t *data, size_t len); void stellar_hashupdate_address(uint8_t *address_bytes); -void stellar_hashupdate_asset(StellarAssetType *asset); -void stellar_hashupdate_bytes(uint8_t *data, size_t len); +void stellar_hashupdate_asset(const StellarAssetType *asset); +void stellar_hashupdate_bytes(const uint8_t *data, size_t len); void stellar_fillSignedTx(StellarSignedTx *resp); bool stellar_allOperationsConfirmed(void); @@ -94,11 +94,11 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature); void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen); void stellar_format_stroops(uint64_t number, char *out, size_t outlen); -void stellar_format_asset(StellarAssetType *asset, char *str_formatted, size_t len); +void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len); void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); bool stellar_validateAddress(const char *str_address); -bool stellar_getAddressBytes(char* str_address, uint8_t *out_bytes); +bool stellar_getAddressBytes(const char* str_address, uint8_t *out_bytes); uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); #endif diff --git a/firmware/storage.c b/firmware/storage.c index 95b7d2ba42..5533185c90 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -422,7 +422,7 @@ void storage_dumpNode(HDNodeType *node) { } #endif -void storage_loadDevice(LoadDevice *msg) +void storage_loadDevice(const LoadDevice *msg) { session_clear(true); diff --git a/firmware/storage.h b/firmware/storage.h index 6924f9b4f5..1f325b8c47 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -83,7 +83,7 @@ void storage_clear_update(void); void storage_update(void); void session_clear(bool clear_pin); -void storage_loadDevice(LoadDevice *msg); +void storage_loadDevice(const LoadDevice *msg); const uint8_t *storage_getSeed(bool usePassphrase); From 79f0db555f6984f653c64c757791cd4b8d8ab421 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 14 Sep 2018 15:06:03 +0200 Subject: [PATCH 0977/1154] make: whitespace nitpick in mako non-verbose output --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 1790be53ec..c8095160ce 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -118,7 +118,7 @@ CFLAGS += -DUSE_NEM=1 CFLAGS += -DUSE_MONERO=0 %:: %.mako defs - @printf " MAKO $@\n" + @printf " MAKO $@\n" $(Q)$(PYTHON) ../vendor/trezor-common/tools/cointool.py render $@.mako bl_data.h: bl_data.py ../bootloader/bootloader.bin From 8fb6beb314771c8055ee33462e1501d4185dafb8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Sep 2018 18:45:50 +0200 Subject: [PATCH 0978/1154] layout: refactor split_message_hex, use it where possible --- firmware/layout2.c | 66 +++++++++++++++++++++++++++++++++------------- firmware/layout2.h | 1 + firmware/lisk.c | 4 +-- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index ae371e0a2c..7b62a44236 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -179,6 +179,22 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) return ret; } +const char **split_message_hex(const uint8_t *msg, uint32_t len) +{ + char hex[32 * 2 + 1]; + memset(hex, 0, sizeof(hex)); + uint32_t size = len; + if (len > 32) { + size = 32; + } + data2hex(msg, size, hex); + if (len > 32) { + hex[63] = '.'; + hex[62] = '.'; + } + return split_message((const uint8_t *)hex, size * 2, 16); +} + void *layoutLast = layoutHome; void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) @@ -310,10 +326,7 @@ void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) { const char **str; if (!is_valid_ascii(data, size)) { - char hex[65]; - memset(hex, 0, sizeof(hex)); - data2hex(data, (size > 32) ? 32 : size, hex); - str = split_message((const uint8_t *)hex, size * 2, 16); + str = split_message_hex(data, size); } else { str = split_message(data, size, 20); } @@ -367,10 +380,34 @@ void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) void layoutSignMessage(const uint8_t *msg, uint32_t len) { - const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - _("Sign message?"), - str[0], str[1], str[2], str[3], NULL, NULL); + const char **str; + if (!is_valid_ascii(msg, len)) { + str = split_message_hex(msg, len); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Sign binary message?"), + str[0], str[1], str[2], str[3], NULL, NULL); + } else { + str = split_message(msg, len, 20); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Sign message?"), + str[0], str[1], str[2], str[3], NULL, NULL); + } +} + +void layoutVerifyMessage(const uint8_t *msg, uint32_t len) +{ + const char **str; + if (!is_valid_ascii(msg, len)) { + str = split_message_hex(msg, len); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Verified binary message"), + str[0], str[1], str[2], str[3], NULL, NULL); + } else { + str = split_message(msg, len, 20); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Verified message"), + str[0], str[1], str[2], str[3], NULL, NULL); + } } void layoutVerifyAddress(const CoinInfo *coin, const char *address) @@ -378,14 +415,6 @@ void layoutVerifyAddress(const CoinInfo *coin, const char *address) render_address_dialog(coin, address, _("Confirm address?"), _("Message signed by:"), 0); } -void layoutVerifyMessage(const uint8_t *msg, uint32_t len) -{ - const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), - _("Verified message"), - str[0], str[1], str[2], str[3], NULL, NULL); -} - void layoutCipherKeyValue(bool encrypt, const char *key) { const char **str = split_message((const uint8_t *)key, strlen(key), 16); @@ -530,7 +559,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno void layoutPublicKey(const uint8_t *pubkey) { - char hex[32 * 2 + 1], desc[16]; + char desc[16]; strlcpy(desc, "Public Key: 00", sizeof(desc)); if (pubkey[0] == 1) { /* ed25519 public key */ @@ -538,8 +567,7 @@ void layoutPublicKey(const uint8_t *pubkey) } else { data2hex(pubkey, 1, desc + 12); } - data2hex(pubkey + 1, 32, hex); - const char **str = split_message((const uint8_t *)hex, 32 * 2, 16); + const char **str = split_message_hex(pubkey + 1, 32 * 2); layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0], str[1], str[2], str[3], NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index 84e96fc95c..283922a7ac 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -72,6 +72,7 @@ void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); +const char **split_message_hex(const uint8_t *msg, uint32_t len); bool is_valid_ascii(const uint8_t *data, uint32_t size); #endif diff --git a/firmware/lisk.c b/firmware/lisk.c index c40d73ff3b..d47d005cd7 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -258,9 +258,7 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) // Layouts void layoutLiskPublicKey(const uint8_t *pubkey) { - char hex[32 * 2 + 1]; - data2hex(pubkey, 32, hex); - const char **str = split_message((const uint8_t *)hex, 32 * 2, 16); + const char **str = split_message_hex(pubkey, 32); layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, _("Public Key:"), str[0], str[1], str[2], str[3], NULL); } From 2a1e4c7ab6545b3dfab9d6c8a1926fc2ae9914ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20B=C3=ADlek?= Date: Thu, 20 Sep 2018 00:44:35 +0700 Subject: [PATCH 0979/1154] build: Use pipenv in docker build (#412) --- Dockerfile | 3 ++- script/fullbuild | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b5a3b7c3f4..4384a0908f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_V # use zipfile module to extract files world-readable RUN python3 -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc -RUN pip3 install "protobuf==${PROTOBUF_VERSION}" ecdsa +RUN pip3 install pipenv + RUN ln -s python3 /usr/bin/python diff --git a/script/fullbuild b/script/fullbuild index 99c7dd9e71..b9731b1148 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -3,6 +3,10 @@ # script/build: Build the TREZOR firmware in a clean working tree. # +# this needs to be there, otherwise python click installer vomits an error +export LC_ALL=C.UTF-8 +export LANG=C.UTF-8 + set -eu cd "$(dirname "$0")/.." @@ -34,7 +38,7 @@ worktree_setup() { worktree_build() { local path="$1" - ( cd "$path" && script/cibuild ) + ( cd "$path" && pipenv install && pipenv run script/cibuild ) } worktree_copy() { From 307b3a742bf3d96a6a1d79b9b9abd8d7191b8809 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Sep 2018 20:30:00 +0200 Subject: [PATCH 0980/1154] fix Docker build --- Dockerfile | 9 +++++---- firmware/protob/Makefile | 2 +- vendor/trezor-common | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4384a0908f..4b59b619ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,10 +11,11 @@ RUN apt-get update && \ ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" +ENV PYTHON=python3 + # use zipfile module to extract files world-readable -RUN python3 -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc +RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc -RUN pip3 install pipenv +ENV WORKON_HOME=/tmp/.venvs - -RUN ln -s python3 /usr/bin/python +RUN $PYTHON -m pip install pipenv diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 4b372fe5bb..0cf8453c18 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/vendor/trezor-common b/vendor/trezor-common index 5d472e8a11..f60b722638 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 5d472e8a116c2c9cf6c1a6d0e1de0a1465377d91 +Subproject commit f60b722638116a878d88b9f9393f311f8b45834e From bf266f0fd9db73ac71c1356eccbb0eb59dad36e9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Sep 2018 20:43:57 +0200 Subject: [PATCH 0981/1154] fix fullbuild script --- script/fullbuild | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/fullbuild b/script/fullbuild index b9731b1148..520271fdc9 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -85,12 +85,12 @@ main() { "$FIRMWARE_FILENAME" \ "v*")" - printf "\n\n"; script/fingerprint \ + printf "\n\n"; $PYTHON script/fingerprint \ "$bootloader_path" \ --max-size 32768 \ --double - printf "\n\n"; script/fingerprint \ + printf "\n\n"; $PYTHON script/fingerprint \ "$firmware_path" \ --offset 256 \ --max-size 491520 From 9afaeff36ff891ab9dbe48b0f514a273975f8cd0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 20 Sep 2018 13:52:22 +0200 Subject: [PATCH 0982/1154] firmware: fix typo in unfinished_backup --- firmware/fsm_msg_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index a9889de583..979acd813f 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -67,7 +67,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); - resp->unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); + resp->has_unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); From 86118986bc5129fc40d67b92eb52c71aedd493c6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 28 Sep 2018 10:41:30 +0200 Subject: [PATCH 0983/1154] lisk: remove unnecessary allocation --- firmware/lisk.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/firmware/lisk.c b/firmware/lisk.c index d47d005cd7..0a91f1f60f 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -87,10 +87,8 @@ static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) // For CastVotes transactions, recipientId should be equal to transaction creator address. if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) { - char address[MAX_LISK_ADDRESS_SIZE]; - lisk_get_address_from_public_key(&node->public_key[1], address); - memcpy(msg->transaction.recipient_id, address, sizeof(address)); msg->transaction.has_recipient_id = true; + lisk_get_address_from_public_key(&node->public_key[1], msg->transaction.recipient_id); } } From 98dedc7baa7916dc158cfa47a949014c214e3f59 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 28 Sep 2018 20:48:30 +0200 Subject: [PATCH 0984/1154] nix: add shell.nix --- shell.nix | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 shell.nix diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000..e09b2131d9 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +with import {}; + +let + myPython = python36.withPackages(p: [p.trezor p.Mako p.munch]); +in + stdenv.mkDerivation { + name = "trezor-mcu-dev"; + buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image ]; + } From fe009959919f5bd442a53a50fdfcbebcc7197371 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 30 Sep 2018 15:40:45 +0200 Subject: [PATCH 0985/1154] use env where possible --- bootloader/firmware_sign.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index a14bfaf6dc..1eca474988 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import argparse import hashlib From fcb6b1713cef41d494a40ea975253115da519911 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 Oct 2018 15:13:32 +0200 Subject: [PATCH 0986/1154] nix: use gcc-arm-embedded-7 package in shell.nix --- shell.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.nix b/shell.nix index e09b2131d9..8dc128a369 100644 --- a/shell.nix +++ b/shell.nix @@ -5,5 +5,5 @@ let in stdenv.mkDerivation { name = "trezor-mcu-dev"; - buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image ]; + buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded-7 pkgconfig SDL2 SDL2_image ]; } From 4a0f0259d131f3f2681ad7540f4fe797e89429ff Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 Oct 2018 17:19:37 +0200 Subject: [PATCH 0987/1154] firmware: introduce seedless setup (aka no_backup) --- firmware/fsm_msg_common.h | 4 +++- firmware/layout2.c | 4 ++++ firmware/reset.c | 13 ++++++++++--- firmware/reset.h | 2 +- firmware/storage.c | 20 ++++++++++++++++++++ firmware/storage.h | 4 ++++ vendor/trezor-common | 2 +- 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 979acd813f..14618ccc2c 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -68,6 +68,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); resp->has_unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); + resp->has_no_backup = true; resp->no_backup = storage_noBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); @@ -220,7 +221,8 @@ void fsm_msgResetDevice(const ResetDevice *msg) msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, - msg->has_skip_backup ? msg->skip_backup : false + msg->has_skip_backup ? msg->skip_backup : false, + msg->has_no_backup ? msg->no_backup : false ); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 7b62a44236..bc9aefe154 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -250,6 +250,10 @@ void layoutHome(void) oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD); } else + if (storage_noBackup()) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(0, "NO BACKUP!", FONT_STANDARD); + } if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); diff --git a/firmware/reset.c b/firmware/reset.c index 2f350e8de8..542f815cb1 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -34,13 +34,15 @@ static uint32_t strength; static uint8_t int_entropy[32]; static bool awaiting_entropy = false; static bool skip_backup = false; +static bool no_backup = false; -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup) +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup) { if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; skip_backup = _skip_backup; + no_backup = _no_backup; random_buffer(int_entropy, 32); @@ -88,12 +90,17 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); sha256_Final(&ctx, int_entropy); - storage_setNeedsBackup(true); + if (no_backup) { + storage_setNoBackup(true); + } else + if (skip_backup) { + storage_setNeedsBackup(true); + } storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); memset(int_entropy, 0, 32); awaiting_entropy = false; - if (skip_backup) { + if (skip_backup || no_backup) { storage_update(); fsm_sendSuccess(_("Device successfully initialized")); layoutHome(); diff --git a/firmware/reset.h b/firmware/reset.h index a4c54c5a9b..f4638ac36f 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -23,7 +23,7 @@ #include #include -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool skip_backup); +void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); void reset_backup(bool separated); uint32_t reset_get_int_entropy(uint8_t *entropy); diff --git a/firmware/storage.c b/firmware/storage.c index 5533185c90..d088dcded5 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -344,6 +344,14 @@ static void storage_commit_locked(bool update) storageUpdate.has_needs_backup = storageRom->has_needs_backup; storageUpdate.needs_backup = storageRom->needs_backup; } + if (!storageUpdate.has_unfinished_backup) { + storageUpdate.has_unfinished_backup = storageRom->has_unfinished_backup; + storageUpdate.unfinished_backup = storageRom->unfinished_backup; + } + if (!storageUpdate.has_no_backup) { + storageUpdate.has_no_backup = storageRom->has_no_backup; + storageUpdate.no_backup = storageRom->no_backup; + } if (!storageUpdate.has_flags) { storageUpdate.has_flags = storageRom->has_flags; storageUpdate.flags = storageRom->flags; @@ -844,6 +852,18 @@ void storage_setUnfinishedBackup(bool unfinished_backup) storageUpdate.unfinished_backup = unfinished_backup; } +bool storage_noBackup(void) +{ + return storageUpdate.has_no_backup ? storageUpdate.no_backup + : storageRom->has_no_backup && storageRom->no_backup; +} + +void storage_setNoBackup(bool no_backup) +{ + storageUpdate.has_no_backup = true; + storageUpdate.no_backup = no_backup; +} + void storage_applyFlags(uint32_t flags) { if ((storageRom->flags | flags) == storageRom->flags) { diff --git a/firmware/storage.h b/firmware/storage.h index 1f325b8c47..16f690591c 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -73,6 +73,7 @@ typedef struct _Storage { STORAGE_NODE (u2froot) STORAGE_BOOL (unfinished_backup) STORAGE_UINT32 (auto_lock_delay_ms) + STORAGE_BOOL (no_backup) } Storage; extern Storage storageUpdate; @@ -142,6 +143,9 @@ void storage_setNeedsBackup(bool needs_backup); bool storage_unfinishedBackup(void); void storage_setUnfinishedBackup(bool unfinished_backup); +bool storage_noBackup(void); +void storage_setNoBackup(bool no_backup); + void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); diff --git a/vendor/trezor-common b/vendor/trezor-common index f60b722638..41e4a84b5b 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit f60b722638116a878d88b9f9393f311f8b45834e +Subproject commit 41e4a84b5b01d03e980f84fab29c8f0b0ec948f5 From 9749cb070b83b5376bbf7e547259ad8e2a3a9d7b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 Oct 2018 17:30:37 +0200 Subject: [PATCH 0988/1154] storage: setNoBackup does not have to have parameter --- firmware/reset.c | 2 +- firmware/storage.c | 4 ++-- firmware/storage.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/reset.c b/firmware/reset.c index 542f815cb1..293f4a90fb 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -91,7 +91,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Update(&ctx, ext_entropy, len); sha256_Final(&ctx, int_entropy); if (no_backup) { - storage_setNoBackup(true); + storage_setNoBackup(); } else if (skip_backup) { storage_setNeedsBackup(true); diff --git a/firmware/storage.c b/firmware/storage.c index d088dcded5..df4a7de2cc 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -858,10 +858,10 @@ bool storage_noBackup(void) : storageRom->has_no_backup && storageRom->no_backup; } -void storage_setNoBackup(bool no_backup) +void storage_setNoBackup(void) { storageUpdate.has_no_backup = true; - storageUpdate.no_backup = no_backup; + storageUpdate.no_backup = true; } void storage_applyFlags(uint32_t flags) diff --git a/firmware/storage.h b/firmware/storage.h index 16f690591c..572b55eddb 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -144,7 +144,7 @@ bool storage_unfinishedBackup(void); void storage_setUnfinishedBackup(bool unfinished_backup); bool storage_noBackup(void); -void storage_setNoBackup(bool no_backup); +void storage_setNoBackup(void); void storage_applyFlags(uint32_t flags); uint32_t storage_getFlags(void); From cb9182166e8179b3b450f1512c7343ffd24e0f1a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 4 Oct 2018 18:36:36 +0200 Subject: [PATCH 0989/1154] reset: fix setting of needs_backup flag --- firmware/layout2.c | 8 ++++---- firmware/reset.c | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index bc9aefe154..bc56f17851 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -246,14 +246,14 @@ void layoutHome(void) oledDrawBitmap(40, 0, &bmp_logo64); } } + if (storage_noBackup()) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(0, "NO BACKUP!", FONT_STANDARD); + } else if (storage_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD); } else - if (storage_noBackup()) { - oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "NO BACKUP!", FONT_STANDARD); - } if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); diff --git a/firmware/reset.c b/firmware/reset.c index 293f4a90fb..59b9701601 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -92,8 +92,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Final(&ctx, int_entropy); if (no_backup) { storage_setNoBackup(); - } else - if (skip_backup) { + } else { storage_setNeedsBackup(true); } storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); From 3a4660ede28a19706cd856cf2f14afff04522ee3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 8 Oct 2018 15:37:53 +0200 Subject: [PATCH 0990/1154] reset: don't show internal entropy when no_backup is set --- firmware/reset.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/firmware/reset.c b/firmware/reset.c index 59b9701601..e17167eecf 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -44,6 +44,12 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect skip_backup = _skip_backup; no_backup = _no_backup; + if (display_random && no_backup) { + fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when no_backup is used"); + layoutHome(); + return; + } + random_buffer(int_entropy, 32); char ent_str[4][17]; From 7ab36d57abe20a7b2c746e187f5f95378280ef87 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Oct 2018 14:19:59 +0200 Subject: [PATCH 0991/1154] docker: quick fix of Dockerfiles --- Dockerfile | 6 +++++- Dockerfile.emulator | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4b59b619ec..8617eaa191 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,8 @@ FROM debian:9 RUN apt-get update && \ apt-get install -y \ - build-essential curl unzip git python3 python3-pip gcc-arm-none-eabi libnewlib-arm-none-eabi + build-essential curl unzip git python3 python3-pip \ + gcc-arm-none-eabi libnewlib-arm-none-eabi ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" @@ -16,6 +17,9 @@ ENV PYTHON=python3 # use zipfile module to extract files world-readable RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + ENV WORKON_HOME=/tmp/.venvs RUN $PYTHON -m pip install pipenv diff --git a/Dockerfile.emulator b/Dockerfile.emulator index b1488055e8..18090c25bf 100644 --- a/Dockerfile.emulator +++ b/Dockerfile.emulator @@ -11,7 +11,15 @@ RUN apt-get update && \ ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -RUN unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d /usr -RUN pip3 install "protobuf==${PROTOBUF_VERSION}" ecdsa -RUN ln -s python3 /usr/bin/python +ENV PYTHON=python3 + +# use zipfile module to extract files world-readable +RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +ENV WORKON_HOME=/tmp/.venvs + +RUN $PYTHON -m pip install "protobuf==${PROTOBUF_VERSION}" ecdsa click trezor mako munch From b0e879b30e4e5c3f061f6ec5b12612d6e4b1e55e Mon Sep 17 00:00:00 2001 From: matejcik Date: Thu, 11 Oct 2018 14:58:22 +0200 Subject: [PATCH 0992/1154] docker: update build scripts and instructions to fix Docker emulator (#419) fixes #417 --- Dockerfile | 18 ++++++++---- README.md | 41 +++++++++++++++++++-------- build-emulator.sh | 19 ------------- build.sh | 14 ++++++++-- script/fullbuild | 70 ++++++++++++++++++++++++++++++++++------------- 5 files changed, 103 insertions(+), 59 deletions(-) delete mode 100755 build-emulator.sh diff --git a/Dockerfile b/Dockerfile index 8617eaa191..71bedcbbb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,22 +4,28 @@ FROM debian:9 # install build tools and dependencies +ARG EMULATOR=0 +ENV EMULATOR=$EMULATOR + RUN apt-get update && \ - apt-get install -y \ - build-essential curl unzip git python3 python3-pip \ - gcc-arm-none-eabi libnewlib-arm-none-eabi + apt-get install -y build-essential curl git python3 python3-pip + +RUN if [ "$EMULATOR" = 1 ]; then \ + apt-get install -y libsdl2-dev libsdl2-image-dev; \ + else \ + apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi; \ + fi ENV PROTOBUF_VERSION=3.4.0 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" ENV PYTHON=python3 +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 # use zipfile module to extract files world-readable RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc -ENV LC_ALL=C.UTF-8 -ENV LANG=C.UTF-8 - ENV WORKON_HOME=/tmp/.venvs RUN $PYTHON -m pip install pipenv diff --git a/README.md b/README.md index 75b0a110d4..0b8435ff59 100644 --- a/README.md +++ b/README.md @@ -4,23 +4,40 @@ https://trezor.io/ -## How to build the TREZOR bootloader and firmware? +## How to build the TREZOR bootloader, firmware and emulator -1. [Install Docker](https://docs.docker.com/engine/installation/) -2. `git clone https://github.com/trezor/trezor-mcu.git` -3. `cd trezor-mcu` -4. `./build.sh BOOTLOADER_TAG FIRMWARE_TAG` (where BOOTLOADER_TAG is bl1.5.0 and FIRMWARE_TAG is v1.7.0 for example, if left blank the script builds latest commit in master branch) +Ensure that you have Docker installed. You can follow [Docker's installation instructions](https://docs.docker.com/engine/installation/). -This creates the files `build/bootloader-BOOTLOADER_TAG.bin` and `build/trezor-FIRMWARE_TAG.bin` and prints their fingerprints and sizes at the end of the build log. +Clone this repository: +```sh +git clone https://github.com/trezor/trezor-mcu.git` +cd trezor-mcu +``` -## How to build TREZOR emulator for Linux? +Use the `build.sh` command to build the images. -1. [Install Docker](https://docs.docker.com/engine/installation/) -2. `git clone https://github.com/trezor/trezor-mcu.git` -3. `cd trezor-mcu` -4. `./build-emulator.sh TAG` (where TAG is v1.5.0 for example, if left blank the script builds latest commit in master branch) +* to build bootloader 1.6.0 and firmware 1.7.0: + ```sh + ./build.sh bl1.6.0 v1.7.0 + ``` +* to build latest firmware from master: + ```sh + ./build.sh + ``` +* to build the emulator from master: + ```sh + ./build.sh EMU + ``` +* to build the emulator for version 1.7.0: + ```sh + ./build.sh EMU v1.7.0 + ``` -This creates binary file `build/trezor-emulator-TAG`, which can be run and works as a trezor emulator. (Use `TREZOR_OLED_SCALE` env. variable to make screen bigger.) +Build results are stored in the `build/` directory. File `bootloader-.bin` represents +the bootloader, `trezor-.bin` is the firmware image, and `trezor-emulator-.elf` +is the emulator executable. + +You can use `TREZOR_OLED_SCALE` environment variable to make emulator screen bigger. ## How to get fingerprint of firmware signed and distributed by SatoshiLabs? diff --git a/build-emulator.sh b/build-emulator.sh deleted file mode 100755 index 40d5d28d46..0000000000 --- a/build-emulator.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -e - -IMAGE=trezor-mcu-build-emulator64 -TAG=${1:-master} -ELFFILE=build/trezor-emulator64-$TAG - -docker build -f Dockerfile.emulator -t $IMAGE . -docker run -t -v $(pwd)/build:/build:z $IMAGE /bin/sh -c "\ - git clone https://github.com/trezor/trezor-mcu && \ - cd trezor-mcu && \ - git checkout $TAG && \ - git submodule update --init && \ - make -C vendor/nanopb/generator/proto && \ - make -C firmware/protob && \ - EMULATOR=1 make && \ - EMULATOR=1 make -C emulator && \ - EMULATOR=1 make -C firmware && \ - cp firmware/trezor.elf /$ELFFILE" diff --git a/build.sh b/build.sh index 81dc2a8dc5..6afb96c5da 100755 --- a/build.sh +++ b/build.sh @@ -1,11 +1,19 @@ #!/bin/bash set -e -IMAGE=trezor-mcu-build - BOOTLOADER_COMMIT=${1:-HEAD} FIRMWARE_COMMIT=${2:-HEAD} -docker build -t "$IMAGE" . +if [ "$BOOTLOADER_COMMIT" = "EMU" ]; then + export EMULATOR=1 +fi + +if [ "$EMULATOR" = 1 ]; then + IMAGE=trezor-mcu-emulator +else + IMAGE=trezor-mcu-build +fi + +docker build -t "$IMAGE" --build-arg EMULATOR=$EMULATOR . docker run -it -v $(pwd):/src:z --user="$(stat -c "%u:%g" .)" "$IMAGE" \ /src/script/fullbuild "$BOOTLOADER_COMMIT" "$FIRMWARE_COMMIT" diff --git a/script/fullbuild b/script/fullbuild index 520271fdc9..044ab94e63 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -22,6 +22,10 @@ readonly FIRMWARE_DIR="$BUILD_DIR/firmware" readonly FIRMWARE_FILENAME="firmware/trezor.bin" readonly FIRMWARE_PATH="$FIRMWARE_DIR/$FIRMWARE_FILENAME" +readonly EMULATOR_DIR="$FIRMWARE_DIR" +readonly EMULATOR_FILENAME="firmware/trezor-emulator.elf" +readonly EMULATOR_PATH="$EMULATOR_DIR/firmware/trezor.elf" + worktree_setup() { local path="$1" local commit="$2" @@ -38,7 +42,21 @@ worktree_setup() { worktree_build() { local path="$1" - ( cd "$path" && pipenv install && pipenv run script/cibuild ) + if [ -e "$path/Pipfile" ]; then + pushd $path + if ! pipenv install; then + # older tags can fail because they don't have protobuf in Pipfile + pipenv run pip install "protobuf==3.4.0" + pipenv install + fi + pipenv run script/cibuild + popd + else + # even older tags don't have Pipfile! + # use current one + pipenv install + ( cd "$path" && pipenv run script/cibuild ) + fi } worktree_copy() { @@ -67,28 +85,42 @@ main() { local firmware_commit="$2" script/bootstrap - - worktree_setup "$BOOTLOADER_DIR" "$bootloader_commit" - worktree_build "$BOOTLOADER_DIR" - - local bootloader_path="$(worktree_copy \ - "$BOOTLOADER_DIR" \ - "$BOOTLOADER_FILENAME" \ - "bl*")" - worktree_setup "$FIRMWARE_DIR" "$firmware_commit" - cp "$BOOTLOADER_PATH" "$FIRMWARE_DIR/$BOOTLOADER_FILENAME" + + if [ "$EMULATOR" != 1 ]; then + worktree_setup "$BOOTLOADER_DIR" "$bootloader_commit" + worktree_build "$BOOTLOADER_DIR" + + cp "$BOOTLOADER_PATH" "$FIRMWARE_DIR/$BOOTLOADER_FILENAME" + fi + worktree_build "$FIRMWARE_DIR" - local firmware_path="$(worktree_copy \ - "$FIRMWARE_DIR" \ - "$FIRMWARE_FILENAME" \ - "v*")" + if [ "$EMULATOR" = 1 ]; then + cp "$EMULATOR_PATH" "$EMULATOR_DIR/$EMULATOR_FILENAME" + local firmware_path="$(worktree_copy \ + "$EMULATOR_DIR" \ + "$EMULATOR_FILENAME" \ + "v*")" + chmod +x "$firmware_path" - printf "\n\n"; $PYTHON script/fingerprint \ - "$bootloader_path" \ - --max-size 32768 \ - --double + else + + local firmware_path="$(worktree_copy \ + "$FIRMWARE_DIR" \ + "$FIRMWARE_FILENAME" \ + "v*")" + + local bootloader_path="$(worktree_copy \ + "$BOOTLOADER_DIR" \ + "$BOOTLOADER_FILENAME" \ + "bl*")" + + printf "\n\n"; $PYTHON script/fingerprint \ + "$bootloader_path" \ + --max-size 32768 \ + --double + fi printf "\n\n"; $PYTHON script/fingerprint \ "$firmware_path" \ From 96cf9e9065f4cfbd45504ebe75d2593cb7347029 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 11 Oct 2018 15:24:40 +0200 Subject: [PATCH 0993/1154] reset: don't show internal entropy when skip_backup is set --- firmware/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index e17167eecf..c68e7e8245 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -44,7 +44,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect skip_backup = _skip_backup; no_backup = _no_backup; - if (display_random && no_backup) { + if (display_random && (skip_backup || no_backup)) { fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when no_backup is used"); layoutHome(); return; From 9730471a734ff800e455340a4b735edec79e8b9c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 11 Oct 2018 15:27:03 +0200 Subject: [PATCH 0994/1154] reset: wording --- firmware/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index c68e7e8245..95323060bb 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -45,7 +45,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect no_backup = _no_backup; if (display_random && (skip_backup || no_backup)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when no_backup is used"); + fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when backup is skipped"); layoutHome(); return; } From 555a650eb8bcea352c934ae8d0becd3de80dd58c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 12 Oct 2018 14:03:23 +0200 Subject: [PATCH 0995/1154] build: remove unnecessary Dockerfile.emulator --- Dockerfile.emulator | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 Dockerfile.emulator diff --git a/Dockerfile.emulator b/Dockerfile.emulator deleted file mode 100644 index 18090c25bf..0000000000 --- a/Dockerfile.emulator +++ /dev/null @@ -1,25 +0,0 @@ -# initialize from the image - -FROM debian:9 - -# install build tools and dependencies - -RUN apt-get update && \ - apt-get install -y \ - build-essential curl unzip git python3 python3-pip \ - libsdl2-dev libsdl2-image-dev - -ENV PROTOBUF_VERSION=3.4.0 -RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - -ENV PYTHON=python3 - -# use zipfile module to extract files world-readable -RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc - -ENV LC_ALL=C.UTF-8 -ENV LANG=C.UTF-8 - -ENV WORKON_HOME=/tmp/.venvs - -RUN $PYTHON -m pip install "protobuf==${PROTOBUF_VERSION}" ecdsa click trezor mako munch From 4f9284d572e74ca82570a919d53925ba9b220692 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 15 Oct 2018 18:07:16 +0200 Subject: [PATCH 0996/1154] firmware: drop version_group_id from coin definition, use externally provided one --- firmware/coin_info.c.mako | 1 - firmware/coins.h | 1 - firmware/signing.c | 16 +++++++++------- vendor/trezor-common | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/firmware/coin_info.c.mako b/firmware/coin_info.c.mako index 80ba716ff3..5b76886c33 100644 --- a/firmware/coin_info.c.mako +++ b/firmware/coin_info.c.mako @@ -41,7 +41,6 @@ const CoinInfo coins[COINS_COUNT] = { .xpub_magic_segwit_p2sh = ${hex(c.xpub_magic_segwit_p2sh)}, .xpub_magic_segwit_native = ${hex(c.xpub_magic_segwit_native)}, .fork_id = ${c_int(c.fork_id)}, - .version_group_id = ${hex(c.version_group_id)}, .bech32_prefix = ${c_str(c.bech32_prefix)}, .cashaddr_prefix = ${c_str(c.cashaddr_prefix)}, .coin_type = (${c_int(c.slip44)} | 0x80000000), diff --git a/firmware/coins.h b/firmware/coins.h index b313c6c8d8..96ed77a05c 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -44,7 +44,6 @@ typedef struct _CoinInfo { uint32_t xpub_magic_segwit_p2sh; uint32_t xpub_magic_segwit_native; uint32_t fork_id; - uint32_t version_group_id; const char *bech32_prefix; const char *cashaddr_prefix; uint32_t coin_type; diff --git a/firmware/signing.c b/firmware/signing.c index ceb2b5171d..5247be62c0 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -66,6 +66,7 @@ static uint32_t version = 1; static uint32_t lock_time = 0; static uint32_t expiry = 0; static bool overwintered = false; +static uint32_t version_group_id = 0; static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; @@ -482,6 +483,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) lock_time = msg->lock_time; expiry = msg->expiry; overwintered = msg->has_overwintered && msg->overwintered; + version_group_id = msg->version_group_id; uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); if (coin->decred) { @@ -511,13 +513,13 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) multisig_fp_mismatch = false; next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); if (coin->decred) { to.version |= (DECRED_SERIALIZE_FULL << 16); to.is_decred = true; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); ti.is_decred = true; } @@ -769,7 +771,7 @@ static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { hasher_Reset(&hasher_preimage); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); - hasher_Update(&hasher_preimage, (const uint8_t *)&coin->version_group_id, 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs @@ -1046,7 +1048,7 @@ void signing_txack(TransactionType *tx) signing_abort(); return; } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered, version_group_id); if (coin->decred) { tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); tp.is_decred = true; @@ -1129,7 +1131,7 @@ void signing_txack(TransactionType *tx) case STAGE_REQUEST_4_INPUT: progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); hasher_Reset(&hasher_check); } // check prevouts and script type @@ -1328,12 +1330,12 @@ void signing_txack(TransactionType *tx) progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); if (idx1 == 0) { // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); to.is_decred = true; } // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, coin->version_group_id); + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); ti.is_decred = true; if (!compile_input_script_sig(&tx->inputs[0])) { diff --git a/vendor/trezor-common b/vendor/trezor-common index 41e4a84b5b..ea0262266d 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 41e4a84b5b01d03e980f84fab29c8f0b0ec948f5 +Subproject commit ea0262266d9c42315617e9abbcf0b539c373ebc6 From 71e52e352027143a054b8317daadce97fd96104e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 16 Oct 2018 11:36:28 +0200 Subject: [PATCH 0997/1154] firmware: use preimage hasher for Zcash Sapling --- firmware/signing.c | 57 +++++++++++++++++++++++++++++++++++++------- vendor/trezor-crypto | 2 +- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 5247be62c0..2326af0a3b 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -55,7 +55,7 @@ static TxRequest resp; static TxInputType input; static TxOutputBinType bin_output; static TxStruct to, tp, ti; -static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check, hasher_preimage; +static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; @@ -529,13 +529,11 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) hasher_Init(&hasher_prevouts, HASHER_OVERWINTER_PREVOUTS); hasher_Init(&hasher_sequence, HASHER_OVERWINTER_SEQUENCE); hasher_Init(&hasher_outputs, HASHER_OVERWINTER_OUTPUTS); - hasher_Init(&hasher_preimage, HASHER_OVERWINTER_PREIMAGE); hasher_Init(&hasher_check, coin->curve->hasher_sign); } else { hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); hasher_Init(&hasher_sequence, coin->curve->hasher_sign); hasher_Init(&hasher_outputs, coin->curve->hasher_sign); - hasher_Init(&hasher_preimage, coin->curve->hasher_sign); hasher_Init(&hasher_check, coin->curve->hasher_sign); } @@ -752,7 +750,8 @@ static void phase1_request_next_output(void) { static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - hasher_Reset(&hasher_preimage); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence @@ -768,7 +767,8 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - hasher_Reset(&hasher_preimage); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, HASHER_OVERWINTER_PREIMAGE); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId @@ -789,9 +789,39 @@ static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { hasher_Final(&hasher_preimage, hash); } +static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { + uint32_t hash_type = signing_hash_type(); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, HASHER_SAPLING_PREIMAGE); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 7. hashShieldedSpends + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 8. hashShieldedOutputs + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 9. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 10. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); // 11. valueBalance + hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 12. nHashType + + tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 13b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 13c. value + tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence + + hasher_Final(&hasher_preimage, hash); +} + static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); - hasher_Reset(&hasher_preimage); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); hasher_Update(&hasher_preimage, hash_prefix, 32); hasher_Update(&hasher_preimage, hash_witness, 32); @@ -972,7 +1002,7 @@ void signing_txack(TransactionType *tx) if (coin->force_bip143 || overwintered) { if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("BIP/ZIP 143 input without amount")); + fsm_sendFailure(FailureType_Failure_DataError, _("Expected input with amount")); signing_abort(); return; } @@ -1237,7 +1267,18 @@ void signing_txack(TransactionType *tx) uint8_t hash[32]; if (overwintered) { - signing_hash_zip143(&tx->inputs[0], hash); + switch (version) { + case 3: + signing_hash_zip143(&tx->inputs[0], hash); + break; + case 4: + signing_hash_zip243(&tx->inputs[0], hash); + break; + default: + fsm_sendFailure(FailureType_Failure_DataError, _("Unsupported version for overwintered transaction")); + signing_abort(); + return; + } } else { signing_hash_bip143(&tx->inputs[0], hash); } diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index f9523f97df..a938a1c901 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit f9523f97df2c965835001d551738bbe1b93b53df +Subproject commit a938a1c9019969ec8b63713e9402a932e8e0d9a8 From ab9ea4bb54a6700ff819b832002964719fb64f83 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 17 Oct 2018 16:57:25 +0200 Subject: [PATCH 0998/1154] firmware: fix Zcash ZIP243 signing --- firmware/transaction.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/firmware/transaction.c b/firmware/transaction.c index d84b2ac64c..f5b9fb5b77 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -612,9 +612,19 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { memcpy(out, &(tx->lock_time), 4); if (tx->overwintered) { - memcpy(out + 4, &(tx->expiry), 4); - out[8] = 0x00; // nJoinSplit - return 9; + if (tx->version == 3) { + memcpy(out + 4, &(tx->expiry), 4); + out[8] = 0x00; // nJoinSplit + return 9; + } else + if (tx->version == 4) { + memcpy(out + 4, &(tx->expiry), 4); + memset(out + 8, 0, 8); // valueBalance + out[16] = 0x00; // nShieldedSpend + out[17] = 0x00; // nShieldedOutput + out[18] = 0x00; // nJoinSplit + return 19; + } } if (tx->is_decred) { memcpy(out + 4, &(tx->expiry), 4); From 29b2a66783f8efcd5cc9f17e455ad4729780cf03 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Oct 2018 14:46:44 +0200 Subject: [PATCH 0999/1154] firmware: update changelog --- firmware/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index d612bd7e0f..b602da5684 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,8 @@ +Version 1.7.1 [unreleased] +* Add support for Lisk +* Add support for Zcash Sapling hardfork +* Implement seedless setup + Version 1.7.0 [unreleased] * Stable release, optional update * Switch from HID to WebUSB From f55bcbab31bd2805f463c3fce1e74b72a6757a94 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Oct 2018 14:47:38 +0200 Subject: [PATCH 1000/1154] lisk: check recipient_id length --- firmware/lisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/lisk.c b/firmware/lisk.c index 0a91f1f60f..efc8721108 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -222,7 +222,7 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) } uint64_t recipient_id = 0; - if (msg->transaction.has_recipient_id) { + if (msg->transaction.has_recipient_id && msg->transaction.recipient_id[0] != 0) { // parse integer from lisk address ("123L" -> 123) for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) { if (msg->transaction.recipient_id[i] < '0' || msg->transaction.recipient_id[i] > '9') { From d26f7e8a80591106e93a6f8f767d265288f3441e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Oct 2018 15:28:03 +0200 Subject: [PATCH 1001/1154] stellar: fix number of operations data type --- firmware/stellar.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/stellar.h b/firmware/stellar.h index 17b6df06fb..eca6c22b34 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -44,9 +44,9 @@ typedef struct { uint8_t network_type; // Total number of operations expected - uint8_t num_operations; + uint32_t num_operations; // Number that have been confirmed by the user - uint8_t confirmed_operations; + uint32_t confirmed_operations; // sha256 context that will eventually be signed SHA256_CTX sha256_ctx; From ae077971ece2cb2bc75e1fcc5d6f7ec37faf2af1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Oct 2018 15:50:06 +0200 Subject: [PATCH 1002/1154] nem: check for invalid network id --- firmware/nem2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/nem2.c b/firmware/nem2.c index 216791a56f..cad737032f 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -33,7 +33,7 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { common->network = NEM_NETWORK_MAINNET; } - if (nem_network_name(common->network) == NULL) { + if (common->network > 0xFF || nem_network_name(common->network) == NULL) { return inner ? _("Invalid NEM network in inner transaction") : _("Invalid NEM network"); } From d1256e3831e89279eca6320b0b105262a872b17f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 19 Oct 2018 16:10:14 +0200 Subject: [PATCH 1003/1154] ethereum: refactor into rlp_calculate_number_length --- firmware/ethereum.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index ee58c0b4f6..fa6b3256fb 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -159,6 +159,24 @@ static int rlp_calculate_length(int length, uint8_t firstbyte) } } +static int rlp_calculate_number_length(uint32_t number) +{ + if (number <= 0x7f) { + return 1; + } + else if (number <= 0xff) { + return 2; + } + else if (number <= 0xffff) { + return 3; + } + else if (number <= 0xffffff) { + return 4; + } else { + return 5; + } +} + static void send_request_chunk(void) { int progress = 1000 - (data_total > 1000000 @@ -549,11 +567,10 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); if (tx_type) { - rlp_length += rlp_calculate_length(1, tx_type); + rlp_length += rlp_calculate_number_length(tx_type); } if (chain_id) { - int length = chain_id < 0x100 ? 1: chain_id < 0x10000 ? 2: chain_id < 0x1000000 ? 3 : 4; - rlp_length += rlp_calculate_length(length, chain_id); + rlp_length += rlp_calculate_number_length(chain_id); rlp_length += rlp_calculate_length(0, 0); rlp_length += rlp_calculate_length(0, 0); } From 14efc70f8228fbfa0945a572dbd982c31a5aac29 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 22 Oct 2018 14:10:35 +0200 Subject: [PATCH 1004/1154] reset: add confirm dialog --- firmware/fsm_msg_common.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 14618ccc2c..badd39d292 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -213,6 +213,13 @@ void fsm_msgResetDevice(const ResetDevice *msg) CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + reset_init( msg->has_display_random && msg->display_random, msg->has_strength ? msg->strength : 128, From 3f1d7b09f19a4ea13997a7d1895c7e9713e7abb2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 22 Oct 2018 14:39:49 +0200 Subject: [PATCH 1005/1154] reset/recovery: refactor last commit --- firmware/fsm_msg_common.h | 16 ---------------- firmware/recovery.c | 9 +++++++++ firmware/reset.c | 7 +++++++ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index badd39d292..218102f7b1 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -213,13 +213,6 @@ void fsm_msgResetDevice(const ResetDevice *msg) CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - reset_init( msg->has_display_random && msg->display_random, msg->has_strength ? msg->strength : 128, @@ -357,15 +350,6 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg) CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); - if (!dry_run) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, diff --git a/firmware/recovery.c b/firmware/recovery.c index 703fb07185..b0d8c27c98 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -456,6 +456,15 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr enforce_wordlist = _enforce_wordlist; dry_run = _dry_run; + if (!dry_run) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (!dry_run) { if (pin_protection && !protectChangePin()) { fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); diff --git a/firmware/reset.c b/firmware/reset.c index 95323060bb..2840bfd852 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -50,6 +50,13 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect return; } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + random_buffer(int_entropy, 32); char ent_str[4][17]; From 8e6369e1ba8e7c59a061f804b392893961d6f77b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 22 Oct 2018 15:15:15 +0200 Subject: [PATCH 1006/1154] layout: treat address as accounts for EthereumGetAddress dialogs --- firmware/fsm.c | 4 ++-- firmware/fsm_msg_coin.h | 2 +- firmware/fsm_msg_ethereum.h | 2 +- firmware/fsm_msg_lisk.h | 2 +- firmware/fsm_msg_nem.h | 2 +- firmware/layout2.c | 10 +++++----- firmware/layout2.h | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/firmware/fsm.c b/firmware/fsm.c index bc249de1b7..2e379e56b1 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -222,7 +222,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } -static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, size_t prefixlen, const uint32_t *address_n, size_t address_n_count) +static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, size_t prefixlen, const uint32_t *address_n, size_t address_n_count, bool address_is_account) { bool qrcode = false; for (;;) { @@ -230,7 +230,7 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore if (prefixlen && !qrcode) { display_addr += prefixlen; } - layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count); + layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count, address_is_account); if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { return true; } diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index d6ff406adf..7b559d5c30 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -232,7 +232,7 @@ void fsm_msgGetAddress(const GetAddress *msg) bool is_cashaddr = coin->cashaddr_prefix != NULL; bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; - if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count, false)) { return; } } diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index c3270da0e1..7f67de088e 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -66,7 +66,7 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) char address[43] = { '0', 'x' }; ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, chain_id); - if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { return; } } diff --git a/firmware/fsm_msg_lisk.h b/firmware/fsm_msg_lisk.h index e3ad8963be..c8c37540ee 100644 --- a/firmware/fsm_msg_lisk.h +++ b/firmware/fsm_msg_lisk.h @@ -33,7 +33,7 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg) lisk_get_address_from_public_key(&node->public_key[1], resp->address); if (msg->has_show_display && msg->show_display) { - if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count, false)) { return; } } diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h index 878b6829b5..04c3a63d88 100644 --- a/firmware/fsm_msg_nem.h +++ b/firmware/fsm_msg_nem.h @@ -42,7 +42,7 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) strlcpy(desc, network, sizeof(desc)); strlcat(desc, ":", sizeof(desc)); - if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count)) { + if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count, false)) { return; } } diff --git a/firmware/layout2.c b/firmware/layout2.c index bc56f17851..e18416ef08 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -55,7 +55,7 @@ static const char *slip44_extras(uint32_t coin_type) #define BIP32_MAX_LAST_ELEMENT 1000000 -static const char *address_n_str(const uint32_t *address_n, size_t address_n_count) +static const char *address_n_str(const uint32_t *address_n, size_t address_n_count, bool address_is_account) { if (address_n_count > 8) { return _("Unknown long path"); @@ -96,7 +96,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou abbr = slip44_extras(address_n[1]); } } - uint32_t accnum = (address_n[2] & 0x7fffffff) + 1; + const uint32_t accnum = address_is_account ? ((address_n[4] & 0x7fffffff) + 1) : (address_n[2] & 0x7fffffff) + 1; if (abbr && accnum < 100) { memset(path, 0, sizeof(path)); strlcpy(path, abbr, sizeof(path)); @@ -312,7 +312,7 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); strlcat(str_out, " to", sizeof(str_out)); const char *address = out->address; - const char *extra_line = (out->address_n_count > 0) ? address_n_str(out->address_n, out->address_n_count) : 0; + const char *extra_line = (out->address_n_count > 0) ? address_n_str(out->address_n, out->address_n_count, false) : 0; render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); } @@ -496,7 +496,7 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count) +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account) { if (layoutLast != layoutAddress) { layoutSwipe(); @@ -550,7 +550,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno for (int i = 0; i < 4; i++) { oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); } - oledDrawString(0, 42, address_n_str(address_n, address_n_count), FONT_STANDARD); + oledDrawString(0, 42, address_n_str(address_n, address_n_count, address_is_account), FONT_STANDARD); } if (!qrcode) { diff --git a/firmware/layout2.h b/firmware/layout2.h index 283922a7ac..cfeec1e1b9 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -54,7 +54,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutResetWord(const char *word, int pass, int word_pos, bool last); -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count); +void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); From e1700c2ce12dd652784dd995ee4b0ff43a096f7a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 22 Oct 2018 15:17:57 +0200 Subject: [PATCH 1007/1154] layout: use "address" instead of "account" for EthereumGetAddress --- firmware/layout2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index e18416ef08..d50ef78c84 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -109,7 +109,11 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou if (native_segwit) { strlcat(path, " segwit", sizeof(path)); } - strlcat(path, " account #", sizeof(path)); + if (address_is_account) { + strlcat(path, " address #", sizeof(path)); + } else { + strlcat(path, " account #", sizeof(path)); + } char acc[3]; memset(acc, 0, sizeof(acc)); if (accnum < 10) { From e650ac47e21fb619ba5eadd1a7a932493cb37cac Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 11:10:34 +0200 Subject: [PATCH 1008/1154] add .dockerignore --- .dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..50f751212c --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +_attic/ From 781d4c24c15334680ae2fadbb244fa98cd9f6025 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 17:48:45 +0200 Subject: [PATCH 1009/1154] layout: don't split short addresses in layoutAddress --- firmware/layout2.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index d50ef78c84..ef78519a51 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -546,13 +546,17 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno } } } else { - uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; - const char **str = split_message((const uint8_t *)address, addrlen, rowlen); if (desc) { oledDrawString(0, 0 * 9, desc, FONT_STANDARD); } - for (int i = 0; i < 4; i++) { - oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); + if (addrlen > 10) { // don't split short addresses + uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; + const char **str = split_message((const uint8_t *)address, addrlen, rowlen); + for (int i = 0; i < 4; i++) { + oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); + } + } else { + oledDrawString(0, (0 + 1) * 9 + 4, address, FONT_FIXED); } oledDrawString(0, 42, address_n_str(address_n, address_n_count, address_is_account), FONT_STANDARD); } From 9226589604e78ab3d9f9f90f31bf838e359f34f8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Oct 2018 13:38:10 +0200 Subject: [PATCH 1010/1154] bump version to 1.7.1 --- firmware/trezor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index 20fcfc481e..d0bc3493a3 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -24,7 +24,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 7 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) From 5cbeb970c97a52995928b332fd7f3194bfd5d350 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Tue, 4 Sep 2018 15:06:57 +0200 Subject: [PATCH 1011/1154] signing: copy content of root HDNode in signing_init Instead of just storing a pointer, store the content, in case they later get overwritten. --- firmware/signing.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 2326af0a3b..1574f679e9 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -28,11 +28,12 @@ #include "secp256k1.h" #include "gettext.h" #include "messages.pb.h" +#include "memzero.h" static uint32_t inputs_count; static uint32_t outputs_count; static const CoinInfo *coin; -static const HDNode *root; +static CONFIDENTIAL HDNode root; static CONFIDENTIAL HDNode node; static bool signing = false; enum { @@ -457,7 +458,7 @@ bool compile_input_script_sig(TxInputType *tinput) return false; } } - memcpy(&node, root, sizeof(HDNode)); + memcpy(&node, &root, sizeof(HDNode)); if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count, NULL) == 0) { // Failed to derive private key return false; @@ -478,7 +479,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) inputs_count = msg->inputs_count; outputs_count = msg->outputs_count; coin = _coin; - root = _root; + memcpy(&root, _root, sizeof(HDNode)); version = msg->version; lock_time = msg->lock_time; expiry = msg->expiry; @@ -659,7 +660,7 @@ static bool signing_check_output(TxOutputType *txoutput) { return false; } spending += txoutput->amount; - int co = compile_output(coin, root, txoutput, &bin_output, !is_change); + int co = compile_output(coin, &root, txoutput, &bin_output, !is_change); if (!is_change) { layoutProgress(_("Signing transaction"), progress); } @@ -1207,7 +1208,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_4_OUTPUT: progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); - if (compile_output(coin, root, tx->outputs, &bin_output, false) <= 0) { + if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; @@ -1330,7 +1331,7 @@ void signing_txack(TransactionType *tx) return; case STAGE_REQUEST_5_OUTPUT: - if (compile_output(coin, root, tx->outputs, &bin_output,false) <= 0) { + if (compile_output(coin, &root, tx->outputs, &bin_output,false) <= 0) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); signing_abort(); return; @@ -1428,4 +1429,6 @@ void signing_abort(void) layoutHome(); signing = false; } + memzero(&root, sizeof(root)); + memzero(&node, sizeof(node)); } From cc630a1ebb71e6297785e23ef820e72d29240aa5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 14:15:26 +0200 Subject: [PATCH 1012/1154] stellar: check return value for stellar_deriveNode --- firmware/fsm_msg_stellar.h | 8 ++++++-- firmware/stellar.c | 26 ++++++++++++++++---------- firmware/stellar.h | 8 ++++---- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index e05d14dd8b..52188b3627 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -25,7 +25,7 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg) CHECK_PIN - HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); if (!node) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); return; @@ -60,7 +60,11 @@ void fsm_msgStellarSignTx(const StellarSignTx *msg) CHECK_INITIALIZED CHECK_PIN - stellar_signingInit(msg); + if (!stellar_signingInit(msg)) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + layoutHome(); + return; + } // Confirm transaction basics stellar_layoutTransactionSummary(msg); diff --git a/firmware/stellar.c b/firmware/stellar.c index 77bb0649b5..5819e9b181 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -52,7 +52,7 @@ static StellarTransaction stellar_activeTx; /* * Starts the signing process and parses the transaction header */ -void stellar_signingInit(const StellarSignTx *msg) +bool stellar_signingInit(const StellarSignTx *msg) { memset(&stellar_activeTx, 0, sizeof(StellarTransaction)); stellar_signing = true; @@ -78,10 +78,9 @@ void stellar_signingInit(const StellarSignTx *msg) stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); // Public key comes from deriving the specified account path - HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); if (!node) { - // TODO: bail on error - return; + return false; } memcpy(&(stellar_activeTx.signing_pubkey), node->public_key + 1, sizeof(stellar_activeTx.signing_pubkey)); @@ -153,6 +152,8 @@ void stellar_signingInit(const StellarSignTx *msg) else { stellar_activeTx.network_type = 3; } + + return true; } bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account) @@ -1229,7 +1230,12 @@ bool stellar_allOperationsConfirmed() */ void stellar_getSignatureForActiveTx(uint8_t *out_signature) { - HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); + const HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); + if (!node) { + // return empty signature when we can't derive node + memset(out_signature, 0, 64); + return; + } // Signature is the ed25519 detached signature of the sha256 of all the bytes // that have been read so far @@ -1497,7 +1503,7 @@ uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) * * All paths must be hardened */ -HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count) +const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; const char *curve = "ed25519"; @@ -1564,7 +1570,7 @@ void stellar_hashupdate_bool(bool value) } } -void stellar_hashupdate_string(uint8_t *data, size_t len) +void stellar_hashupdate_string(const uint8_t *data, size_t len) { // Hash the length of the string stellar_hashupdate_uint32((uint32_t)len); @@ -1583,7 +1589,7 @@ void stellar_hashupdate_string(uint8_t *data, size_t len) } } -void stellar_hashupdate_address(uint8_t *address_bytes) +void stellar_hashupdate_address(const uint8_t *address_bytes) { // First 4 bytes of an address are the type. There's only one type (0) stellar_hashupdate_uint32(0); @@ -1799,9 +1805,9 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha int offset_y = 1; int line_height = 9; - HDNode *node = stellar_deriveNode(address_n, address_n_count); + const HDNode *node = stellar_deriveNode(address_n, address_n_count); if (!node) { - // TODO: bail on error + // abort on error return; } diff --git a/firmware/stellar.h b/firmware/stellar.h index eca6c22b34..3c5e34411a 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -53,7 +53,7 @@ typedef struct { } StellarTransaction; // Signing process -void stellar_signingInit(const StellarSignTx *tx); +bool stellar_signingInit(const StellarSignTx *tx); void stellar_signingAbort(const char *reason); bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account); bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg); @@ -74,7 +74,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg); void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); // Helpers -HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); +const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen); const char **stellar_lineBreakAddress(const uint8_t *addrbytes); @@ -82,8 +82,8 @@ const char **stellar_lineBreakAddress(const uint8_t *addrbytes); void stellar_hashupdate_uint32(uint32_t value); void stellar_hashupdate_uint64(uint64_t value); void stellar_hashupdate_bool(bool value); -void stellar_hashupdate_string(uint8_t *data, size_t len); -void stellar_hashupdate_address(uint8_t *address_bytes); +void stellar_hashupdate_string(const uint8_t *data, size_t len); +void stellar_hashupdate_address(const uint8_t *address_bytes); void stellar_hashupdate_asset(const StellarAssetType *asset); void stellar_hashupdate_bytes(const uint8_t *data, size_t len); From 1e602998c7d03f22f9497f47aa3015551993fba5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 23 Oct 2018 15:25:19 +0200 Subject: [PATCH 1013/1154] stellar: rework number formatting to not use double --- firmware/stellar.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index 5819e9b181..81fcfdc204 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -448,7 +448,7 @@ bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg) char str_buying[32]; char str_buying_asset[32]; - char str_price[17]; + char str_price[32]; stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); @@ -528,7 +528,7 @@ bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) char str_buying[32]; char str_buying_asset[32]; - char str_price[17]; + char str_price[32]; stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); @@ -1273,27 +1273,32 @@ void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, s { memset(out, 0, outlen); - // early exist for invalid denominator + // early exit for invalid denominator if (denominator == 0) { strlcpy(out, _("[Invalid Price]"), outlen); return; } - int scale = 0; - double dbl_value = (double)numerator / (double)denominator; + // early exit for zero + if (numerator == 0) { + strlcpy(out, "0", outlen); + return; + } - // Multiply by 10 until the value is larger than the largest possible offer size - // Largest possible offer size is UINT32_MAX (4294967296) - while (dbl_value < UINT32_MAX) { - dbl_value *= (double)10; + int scale = 0; + uint64_t value = numerator; + while (value < (UINT64_MAX / 10)) { + value *= 10; + scale++; + } + value /= denominator; + while (value < (UINT64_MAX / 10)) { + value *= 10; scale++; } - // Cast back to an integer - uint64_t scaled_value = (uint64_t) dbl_value; - // Format with bn_format_uint64 - bn_format_uint64(scaled_value, NULL, NULL, scale, 0, false, out, outlen); + bn_format_uint64(value, NULL, NULL, scale, 0, false, out, outlen); } /* From 4ef8acb1233a80a3522eee3974bf91811cf11aca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Oct 2018 13:41:06 +0200 Subject: [PATCH 1014/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index a938a1c901..5c6b472883 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit a938a1c9019969ec8b63713e9402a932e8e0d9a8 +Subproject commit 5c6b47288323a6cafe331304d2708a3c2a45f4b0 From db6ef4d1399b9f9a5001a485a74c41e6b0fef898 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Oct 2018 13:58:17 +0200 Subject: [PATCH 1015/1154] adjust message sizes --- firmware/messages.h | 6 +++--- memory.ld | 2 +- memory_app_1.0.0.ld | 2 +- memory_app_fastflash.ld | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/firmware/messages.h b/firmware/messages.h index 030af0e698..26c843ac3e 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -24,9 +24,9 @@ #include #include "trezor.h" -#define MSG_IN_SIZE (12*1024) +#define MSG_IN_SIZE (11 * 1024) -#define MSG_OUT_SIZE (12*1024) +#define MSG_OUT_SIZE (11 * 1024) #define msg_read(buf, len) msg_read_common('n', (buf), (len)) #define msg_write(id, ptr) msg_write_common('n', (id), (ptr)) @@ -34,7 +34,7 @@ const uint8_t *msg_out_data(void); #if DEBUG_LINK -#define MSG_DEBUG_OUT_SIZE (4*1024) +#define MSG_DEBUG_OUT_SIZE (4 * 1024) #define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) #define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) diff --git a/memory.ld b/memory.ld index 0bdd40b1ea..12855c2c8b 100644 --- a/memory.ld +++ b/memory.ld @@ -10,7 +10,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); } >ram } diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index cad296aaf6..897f6603ff 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -10,7 +10,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); } >ram } diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index 9e00a54820..a5d554e23a 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -11,7 +11,7 @@ SECTIONS { .confidential (NOLOAD) : { *(confidential) - ASSERT ((SIZEOF(.confidential) <= 33K), "Error: Confidential section too big!"); + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); } >ram } From c346b11bef49945258ff1293c88ea83415e14bcb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Oct 2018 14:07:32 +0200 Subject: [PATCH 1016/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index ea0262266d..b8acf0034a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit ea0262266d9c42315617e9abbcf0b539c373ebc6 +Subproject commit b8acf0034a7442c327bc2ff261830c894de6b75e From 327aaa99213bc8d079f971bccf6d99c1e7e5b246 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 24 Oct 2018 20:31:15 +0200 Subject: [PATCH 1017/1154] firmware: add new bootloader to whitelist --- firmware/bl_check.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 0cb90098a8..805c8e0c78 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -38,10 +38,11 @@ int known_bootloader(int r, const uint8_t *hash) { // note to those verifying these values: bootloader versions above this comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions below are padded with 0x00. // for more info, refer to "make -C bootloader align" and "firmware/bl_data.py". if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 - if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 - if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 - if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 - if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 + if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 shipped with fw 1.6.1 + if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 shipped with fw 1.6.2 + if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 shipped with fw 1.6.3 + if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 + if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 return 0; } From 83f1906cad648c560cd560577317046606398630 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 25 Oct 2018 11:57:56 +0200 Subject: [PATCH 1018/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 5c6b472883..2bbbc3e155 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 5c6b47288323a6cafe331304d2708a3c2a45f4b0 +Subproject commit 2bbbc3e15573294c6dd0273d2a8542ba42507eb0 From 1d63c7edc2963a624cb1e0139ad70c0cda0f2519 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 30 Oct 2018 18:13:11 +0100 Subject: [PATCH 1019/1154] bootloader: convert firmware_sign.py to python3 --- bootloader/firmware_sign.py | 142 ++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 1eca474988..2b3a2c17ef 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -1,9 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function + import argparse import hashlib import struct -import binascii + import ecdsa try: @@ -14,130 +15,161 @@ except: SLOTS = 3 pubkeys = { - 1: '04d571b7f148c5e4232c3814f777d8faeaf1a84216c78d569b71041ffc768a5b2d810fc3bb134dd026b57e65005275aedef43e155f48fc11a32ec790a93312bd58', - 2: '0463279c0c0866e50c05c799d32bd6bab0188b6de06536d1109d2ed9ce76cb335c490e55aee10cc901215132e853097d5432eda06b792073bd7740c94ce4516cb1', - 3: '0443aedbb6f7e71c563f8ed2ef64ec9981482519e7ef4f4aa98b27854e8c49126d4956d300ab45fdc34cd26bc8710de0a31dbdf6de7435fd0b492be70ac75fde58', - 4: '04877c39fd7c62237e038235e9c075dab261630f78eeb8edb92487159fffedfdf6046c6f8b881fa407c4a4ce6c28de0b19c1f4e29f1fcbc5a58ffd1432a3e0938a', - 5: '047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45', + 1: "04d571b7f148c5e4232c3814f777d8faeaf1a84216c78d569b71041ffc768a5b2d810fc3bb134dd026b57e65005275aedef43e155f48fc11a32ec790a93312bd58", + 2: "0463279c0c0866e50c05c799d32bd6bab0188b6de06536d1109d2ed9ce76cb335c490e55aee10cc901215132e853097d5432eda06b792073bd7740c94ce4516cb1", + 3: "0443aedbb6f7e71c563f8ed2ef64ec9981482519e7ef4f4aa98b27854e8c49126d4956d300ab45fdc34cd26bc8710de0a31dbdf6de7435fd0b492be70ac75fde58", + 4: "04877c39fd7c62237e038235e9c075dab261630f78eeb8edb92487159fffedfdf6046c6f8b881fa407c4a4ce6c28de0b19c1f4e29f1fcbc5a58ffd1432a3e0938a", + 5: "047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45", } -INDEXES_START = len('TRZR') + struct.calcsize(' SLOTS: raise Exception("Invalid slot") if is_pem: print("Paste ECDSA private key in PEM format and press Enter:") print("(blank private key removes the signature on given index)") - pem_key = '' + pem_key = "" while True: key = raw_input() pem_key += key + "\n" - if key == '': + if key == "": break - if pem_key.strip() == '': + if pem_key.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, '\x00' * 64) + return modify(data, slot, 0, "\x00" * 64) key = ecdsa.SigningKey.from_pem(pem_key) else: print("Paste SECEXP (in hex) and press Enter:") print("(blank private key removes the signature on given index)") secexp = raw_input() - if secexp.strip() == '': + if secexp.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, '\x00' * 64) - key = ecdsa.SigningKey.from_secret_exponent(secexp = int(secexp, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256) + return modify(data, slot, 0, "\x00" * 64) + key = ecdsa.SigningKey.from_secret_exponent( + secexp=int(secexp, 16), + curve=ecdsa.curves.SECP256k1, + hashfunc=hashlib.sha256, + ) - to_sign = prepare(data)[256:] # without meta + to_sign = prepare(data)[256:] # without meta # Locate proper index of current signing key - pubkey = b'04' + binascii.hexlify(key.get_verifying_key().to_string()) + pubkey = "04" + key.get_verifying_key().to_string().hex() index = None for i, pk in pubkeys.items(): if pk == pubkey: @@ -151,34 +183,35 @@ def sign(data, is_pem): return modify(data, slot, index, signature) + def main(args): if args.generate: key = ecdsa.SigningKey.generate( - curve=ecdsa.curves.SECP256k1, - hashfunc=hashlib.sha256) + curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256 + ) print("PRIVATE KEY (SECEXP):") - print(binascii.hexlify(key.to_string())) + print(key.to_string().hex()) print() print("PRIVATE KEY (PEM):") print(key.to_pem()) print("PUBLIC KEY:") - print('04' + binascii.hexlify(key.get_verifying_key().to_string())) + print("04" + key.get_verifying_key().to_string().hex()) return if not args.path: raise Exception("-f/--file is required") - data = open(args.path, 'rb').read() + data = open(args.path, "rb").read() assert len(data) % 4 == 0 - if data[:4] != b'TRZR': + if data[:4] != b"TRZR": print("Metadata has been added...") data = prepare(data) - if data[:4] != b'TRZR': + if data[:4] != b"TRZR": raise Exception("Firmware header expected") print("Firmware size %d bytes" % len(data)) @@ -189,10 +222,11 @@ def main(args): data = sign(data, args.pem) check_signatures(data) - fp = open(args.path, 'wb') + fp = open(args.path, "wb") fp.write(data) fp.close() -if __name__ == '__main__': + +if __name__ == "__main__": args = parse_args() main(args) From 0688fe6008550cdda9b780240773009bc2948d90 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Nov 2018 16:11:31 +0100 Subject: [PATCH 1020/1154] update changelog --- firmware/ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index b602da5684..a41096262f 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,9 +1,9 @@ -Version 1.7.1 [unreleased] +Version 1.7.1 * Add support for Lisk * Add support for Zcash Sapling hardfork * Implement seedless setup -Version 1.7.0 [unreleased] +Version 1.7.0 * Stable release, optional update * Switch from HID to WebUSB * Add support for Stellar From f0eb7629bc1ec4af427abe122410ac86665f220b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Nov 2018 21:43:13 +0100 Subject: [PATCH 1021/1154] layout: NO BACKUP => SEEDLESS --- firmware/layout2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index ef78519a51..111ccb9ec4 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -252,7 +252,7 @@ void layoutHome(void) } if (storage_noBackup()) { oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "NO BACKUP!", FONT_STANDARD); + oledDrawStringCenter(0, "SEEDLESS", FONT_STANDARD); } else if (storage_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); From 1a0ac272584a4e726c420b3fa1276a9de18a01cb Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 6 Nov 2018 16:44:32 +0100 Subject: [PATCH 1022/1154] readme: update Python instructions (fixes #426) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0b8435ff59..bb443372e3 100644 --- a/README.md +++ b/README.md @@ -58,17 +58,17 @@ Step 3 should produce the same sha256 fingerprint like your local build (for the If you want to build device firmware, make sure you have the [GNU ARM Embedded toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) installed. +You will also need Python 3.5 or later and [pipenv](https://pipenv.readthedocs.io/en/latest/install/). * If you want to build the emulator instead of the firmware, run `export EMULATOR=1 TREZOR_TRANSPORT_V1=1` * If you want to build with the debug link, run `export DEBUG_LINK=1`. Use this if you want to run the device tests. * When you change these variables, use `script/setup` to clean the repository 1. To initialize the repository, run `script/setup` -2. To build the firmware or emulator, run `script/cibuild` +2. To initialize a Python environment, run `pipenv install` +3. To build the firmware or emulator, run `pipenv run script/cibuild` If you are building device firmware, the firmware will be in `firmware/trezor.bin`. You can launch the emulator using `firmware/trezor.elf`. To use `trezorctl` with the emulator, use -`trezorctl -t udp` (for example, `trezorctl -t udp get_features`). - -If `trezorctl -t udp` appears to hang, make sure you have run `export TREZOR_TRANSPORT_V1=1`. +`trezorctl -p udp` (for example, `trezorctl -p udp get_features`). From 0f2ec166090c20cf2ff63959706b6fe72aa40cfc Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 12 Nov 2018 14:17:00 +0100 Subject: [PATCH 1023/1154] vendor: update trezor-common bump fw version to 1.7.2 --- firmware/trezor.h | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/trezor.h b/firmware/trezor.h index d0bc3493a3..f9d28a13c7 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -24,7 +24,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 7 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/vendor/trezor-common b/vendor/trezor-common index b8acf0034a..8c53177626 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit b8acf0034a7442c327bc2ff261830c894de6b75e +Subproject commit 8c53177626349e801757b0a1452a50ed72c51f27 From 9cd261c81a1b94cead04af6d09c68284d0e37851 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Nov 2018 16:50:10 +0100 Subject: [PATCH 1024/1154] layout: parse and show OMNI transactions --- firmware/layout2.c | 44 +++++++++++++++++++++++++++++++++++++++++- firmware/layout2.h | 2 +- firmware/transaction.c | 6 +++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 111ccb9ec4..dbc36c7bb3 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -320,7 +320,49 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); } -bool is_valid_ascii(const uint8_t *data, uint32_t size) +void layoutConfirmOmni(const uint8_t *data, uint32_t size) +{ + const char *desc; + char str_out[32]; + const uint32_t tx_type = *(const uint32_t *)(data + 4); + if (tx_type == 0x00000000 && size == 20) { // OMNI simple send + desc = _("Simple send of "); + const uint32_t currency = *(const uint32_t *)(data + 8); + const char *suffix = "UNKN"; + switch (currency) { + case 1: + suffix = "OMNI"; + break; + case 2: + suffix = "tOMNI"; + break; + case 3: + suffix = "MAID"; + break; + case 31: + suffix = "USDT"; + break; + } + const uint64_t amount = *(const uint64_t *)(data + 12); + bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); + } else { + desc = _("Unknown transaction"); + str_out[0] = 0; + } + layoutDialogSwipe(&bmp_icon_question, + _("Cancel"), + _("Confirm"), + NULL, + _("Confirm OMNI Transaction:"), + NULL, + desc, + NULL, + str_out, + NULL + ); +} + +static bool is_valid_ascii(const uint8_t *data, uint32_t size) { for (uint32_t i = 0; i < size; i++) { if (data[i] < ' ' || data[i] > '~') { diff --git a/firmware/layout2.h b/firmware/layout2.h index cfeec1e1b9..954832bdf9 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -44,6 +44,7 @@ void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); void layoutHome(void); void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); +void layoutConfirmOmni(const uint8_t *data, uint32_t size); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); @@ -73,6 +74,5 @@ void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, con const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); const char **split_message_hex(const uint8_t *msg, uint32_t len); -bool is_valid_ascii(const uint8_t *data, uint32_t size); #endif diff --git a/firmware/transaction.c b/firmware/transaction.c index f5b9fb5b77..e7d9e91c60 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -200,7 +200,11 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T return 0; // failed to compile output } if (needs_confirm) { - layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); + if (in->op_return_data.size >= 8 && memcmp(in->op_return_data.bytes, "omni", 4) == 0) { // OMNI transaction + layoutConfirmOmni(in->op_return_data.bytes, in->op_return_data.size); + } else { + layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); + } if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { return -1; // user aborted } From ca24156eb5d49adc38476e4fd856ded51f60af99 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 13 Nov 2018 16:51:26 +0100 Subject: [PATCH 1025/1154] changelog: update --- firmware/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index a41096262f..c47c9f29d9 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,4 +1,9 @@ +Version 1.7.2 [unreleased] +* Stable release, optional update +* Add support for OMNI layer: OMNI/MAID/USDT + Version 1.7.1 +* Stable release, optional update * Add support for Lisk * Add support for Zcash Sapling hardfork * Implement seedless setup From b1725e7264aae72b0ad3c6f4e829f7fc48629a46 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 15 Nov 2018 13:43:08 +0100 Subject: [PATCH 1026/1154] fsm: return xpub for multisig --- firmware/fsm_msg_coin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 7b559d5c30..3357ade4ba 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -63,7 +63,7 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) } resp->has_xpub = true; - if (coin->xpub_magic && script_type == InputScriptType_SPENDADDRESS) { + if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) { hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); } else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { From b51f995da747a0630ae6eb298a0d0be3b5e05b08 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 4 Dec 2018 10:04:16 +0100 Subject: [PATCH 1027/1154] stellar: typo in failure message --- firmware/stellar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/stellar.c b/firmware/stellar.c index 81fcfdc204..0b6cdb4fe4 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -204,7 +204,7 @@ bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) // Validate new account and convert to bytes uint8_t new_account_bytes[STELLAR_KEY_SIZE]; if (!stellar_getAddressBytes(msg->new_account, new_account_bytes)) { - stellar_signingAbort(_("Invalid destination account")); + stellar_signingAbort(_("Invalid new account address")); return false; } From d576df427e8556aeb4fa7b7a28f7decc907ade66 Mon Sep 17 00:00:00 2001 From: Karel Bilek Date: Fri, 26 Oct 2018 16:27:37 +0700 Subject: [PATCH 1028/1154] emulator: make buildable on macOS --- emulator/strl.c | 3 +++ emulator/strl.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/emulator/strl.c b/emulator/strl.c index 6c87be9320..26668b80a3 100644 --- a/emulator/strl.c +++ b/emulator/strl.c @@ -22,6 +22,7 @@ #include +#if (!defined __APPLE__) && (!defined HAVE_STRLCPY) size_t strlcpy(char *dst, const char *src, size_t size) { size_t ret = strlen(src); @@ -39,3 +40,5 @@ size_t strlcat(char *dst, const char *src, size_t size) { return n + strlcpy(&dst[n], src, size - n); } + +#endif diff --git a/emulator/strl.h b/emulator/strl.h index 8b44e0454e..c43fd4c72e 100644 --- a/emulator/strl.h +++ b/emulator/strl.h @@ -22,7 +22,9 @@ #include +#if (!defined __APPLE__) && (!defined HAVE_STRLCPY) size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size); +#endif #endif From 0cf5ef837f321a01fb02a3a62b0879a84134d369 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 10 Dec 2018 18:46:05 +0100 Subject: [PATCH 1029/1154] reset: add link to ToS to reset_device --- firmware/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index 2840bfd852..ff7819d45d 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -50,7 +50,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect return; } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, NULL, NULL, NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, _("By continuing you"), _("agree to trezor.io/tos"), NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); From fa3481e37d528794adb3b234855c23300782ad92 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 12 Dec 2018 17:37:08 +0100 Subject: [PATCH 1030/1154] firmware/storage: cache PIN after set --- firmware/storage.c | 12 +++++++----- firmware/storage.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/firmware/storage.c b/firmware/storage.c index df4a7de2cc..71ae1ebbbb 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -246,7 +246,7 @@ void session_clear(bool clear_pin) sessionPassphraseCached = false; memzero(&sessionPassphrase, sizeof(sessionPassphrase)); if (clear_pin) { - sessionPinCached = false; + session_uncachePin(); } } @@ -290,9 +290,6 @@ static void storage_commit_locked(bool update) sessionSeedCached = false; sessionPassphraseCached = false; } - if (storageUpdate.has_pin) { - sessionPinCached = false; - } storageUpdate.version = STORAGE_VERSION; if (!storageUpdate.has_node && !storageUpdate.has_mnemonic) { @@ -678,7 +675,7 @@ void storage_setPin(const char *pin) { storageUpdate.has_pin = true; strlcpy(storageUpdate.pin, pin, sizeof(storageUpdate.pin)); - sessionPinCached = false; + session_cachePin(); } const char *storage_getPin(void) @@ -729,6 +726,11 @@ void session_cachePin(void) sessionPinCached = true; } +void session_uncachePin(void) +{ + sessionPinCached = false; +} + bool session_isPinCached(void) { return sessionPinCached; diff --git a/firmware/storage.h b/firmware/storage.h index 572b55eddb..3004e89901 100644 --- a/firmware/storage.h +++ b/firmware/storage.h @@ -122,6 +122,7 @@ bool storage_hasPin(void); const char *storage_getPin(void); void storage_setPin(const char *pin); void session_cachePin(void); +void session_uncachePin(void); bool session_isPinCached(void); void storage_clearPinArea(void); void storage_resetPinFails(uint32_t flash_pinfails); From 14b6044cb8ba78d63977c92b80d51f493afa3286 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 13 Dec 2018 12:32:30 +0100 Subject: [PATCH 1031/1154] storage: add false to pinCached explicitly --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 71ae1ebbbb..8cdfb4770c 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -107,7 +107,7 @@ static bool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t CONFIDENTIAL sessionSeed[64]; -static bool sessionPinCached; +static bool sessionPinCached = false; static bool sessionPassphraseCached; static char CONFIDENTIAL sessionPassphrase[51]; From 0fb6732fb20bf8e2e5a766bf50025510b4470e90 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Dec 2018 13:55:58 +0100 Subject: [PATCH 1032/1154] storage: add false to passphraseCached explicitly --- firmware/storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index 8cdfb4770c..e366cce05d 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -109,7 +109,7 @@ static uint8_t CONFIDENTIAL sessionSeed[64]; static bool sessionPinCached = false; -static bool sessionPassphraseCached; +static bool sessionPassphraseCached = false; static char CONFIDENTIAL sessionPassphrase[51]; #define STORAGE_VERSION 9 From d34faccc7772eb67e157346a2d1f6c3b019f182b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Dec 2018 16:12:28 +0100 Subject: [PATCH 1033/1154] storage: bump version to 10, add no_backup field --- firmware/storage.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firmware/storage.c b/firmware/storage.c index e366cce05d..956334c0b9 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -112,7 +112,7 @@ static bool sessionPinCached = false; static bool sessionPassphraseCached = false; static char CONFIDENTIAL sessionPassphrase[51]; -#define STORAGE_VERSION 9 +#define STORAGE_VERSION 10 void storage_show_error(void) { @@ -146,6 +146,7 @@ bool storage_from_flash(void) // version 7: since 1.5.1 // version 8: since 1.5.2 // version 9: since 1.6.1 + // version 10: since 1.7.2 if (version > STORAGE_VERSION) { // downgrade -> clear storage return false; @@ -175,6 +176,9 @@ bool storage_from_flash(void) } else if (version <= 9) { // added u2froot, unfinished_backup and auto_lock_delay_ms old_storage_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); + } else if (version <= 10) { + // added no_backup + old_storage_size = OLD_STORAGE_SIZE(no_backup); } // erase newly added fields From da5b0a2894ea831da6f2f6a102c2d7b4793f609d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Dec 2018 17:45:58 +0100 Subject: [PATCH 1034/1154] vendor: update trezor-common/trezor-crypto disable Ethereum{Get,}PublicKey message for now --- firmware/protob/Makefile | 2 +- vendor/trezor-common | 2 +- vendor/trezor-crypto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 0cf8453c18..6fc525caee 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron -e EthereumGetPublicKey -e EthereumPublicKey > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/vendor/trezor-common b/vendor/trezor-common index 8c53177626..7edcd671df 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 8c53177626349e801757b0a1452a50ed72c51f27 +Subproject commit 7edcd671df137fc8e59938e97ea4d5c4c78d10ea diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 2bbbc3e155..c5227fdb96 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 2bbbc3e15573294c6dd0273d2a8542ba42507eb0 +Subproject commit c5227fdb969520de41664bfa4b66e74e718d72c4 From 6d6e5a16963416508c237e935c4d3ba436f9afa6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 17 Dec 2018 23:17:02 +0100 Subject: [PATCH 1035/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 7edcd671df..482a8e37f0 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 7edcd671df137fc8e59938e97ea4d5c4c78d10ea +Subproject commit 482a8e37f0f627bfefc720ed0bd8a8c4a93cdbe3 From 0b26c529ec49daf584f322f3ef959c79694c8cf5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Dec 2018 13:10:07 +0100 Subject: [PATCH 1036/1154] u2f: replace U2F header with newer ones Fix U2F constants, add more checks. --- firmware/u2f.c | 18 +++- firmware/u2f/u2f.h | 168 ++++++++++++++++--------------------- firmware/u2f/u2f_hid.h | 184 +++++++++++++++++++---------------------- 3 files changed, 170 insertions(+), 200 deletions(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 33a5f1c1d0..18ef2797b1 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -42,7 +42,7 @@ // About 1/2 Second according to values used in protect.c #define U2F_TIMEOUT (800000/2) -#define U2F_OUT_PKT_BUFFER_LEN 128 +#define U2F_OUT_PKT_BUFFER_LEN 130 // Initialise without a cid static uint32_t cid = 0; @@ -100,8 +100,13 @@ uint32_t next_cid(void) return cid; } +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html#message--and-packet-structure +// states the following: +// With a packet size of 64 bytes (max for full-speed devices), this means that +// the maximum message payload length is 64 - 7 + 128 * (64 - 5) = 7609 bytes. +#define U2F_MAXIMUM_PAYLOAD_LENGTH 7609 typedef struct { - uint8_t buf[57+127*59]; + uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH]; uint8_t *buf_ptr; uint32_t len; uint8_t seq; @@ -282,7 +287,7 @@ void u2fhid_init(const U2FHID_FRAME *in) { const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; U2FHID_FRAME f; - U2FHID_INIT_RESP resp; + U2FHID_INIT_RESP resp = {0}; debugLog(0, "", "u2fhid_init"); @@ -295,7 +300,7 @@ void u2fhid_init(const U2FHID_FRAME *in) f.cid = in->cid; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; - f.init.bcntl = U2FHID_INIT_RESP_SIZE; + f.init.bcntl = sizeof(resp); memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; @@ -363,6 +368,11 @@ void u2fhid_msg(const APDU *a, uint32_t len) void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) { + if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { + debugLog(0, "", "send_u2fhid_msg failed"); + return; + } + U2FHID_FRAME f; uint8_t *p = (uint8_t *)data; uint32_t l = len; diff --git a/firmware/u2f/u2f.h b/firmware/u2f/u2f.h index 62979a3160..b067713963 100644 --- a/firmware/u2f/u2f.h +++ b/firmware/u2f/u2f.h @@ -1,143 +1,113 @@ -/* - Copyright (C) 2013-2015 Yubico AB - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, see . -*/ - -// Common U2F raw message format header. -// 2014-08-14 J Ehrensvard, Yubico, Inc. +/** + * Copyright FIDO Alliance, 2017 + * + * Licensed under CC-BY: + * https://creativecommons.org/licenses/by/4.0/legalcode + * + * Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com + */ #ifndef __U2F_H_INCLUDED__ #define __U2F_H_INCLUDED__ -#ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +#ifdef _MSC_VER // Windows +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else #include #endif #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif // General constants -#define U2F_EC_KEY_SIZE 32 // EC key size in bytes -#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point -#define U2F_MAX_KH_SIZE 128 // Max size of key handle -#define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate -#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature -#define U2F_CTR_SIZE 4 // Size of counter field -#define U2F_APPID_SIZE 32 // Size of application id -#define U2F_CHAL_SIZE 32 // Size of challenge +#define U2F_EC_KEY_SIZE 32 // EC key size in bytes +#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point +#define U2F_MAX_KH_SIZE 128 // Max size of key handle +#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate +#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature +#define U2F_CTR_SIZE 4 // Size of counter field +#define U2F_APPID_SIZE 32 // Size of application id +#define U2F_CHAL_SIZE 32 // Size of challenge #define ENC_SIZE(x) ((x + 7) & 0xfff8) // EC (uncompressed) point -#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format +#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format - typedef struct - { - uint8_t pointFormat; // Point type - uint8_t x[U2F_EC_KEY_SIZE]; // X-value - uint8_t y[U2F_EC_KEY_SIZE]; // Y-value - } U2F_EC_POINT; +typedef struct __attribute__((packed)) { + uint8_t pointFormat; // Point type + uint8_t x[U2F_EC_KEY_SIZE]; // X-value + uint8_t y[U2F_EC_KEY_SIZE]; // Y-value +} U2F_EC_POINT; // U2F native commands -#define U2F_REGISTER 0x01 // Registration command -#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command -#define U2F_VERSION 0x03 // Read version string command +#define U2F_REGISTER 0x01 // Registration command +#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command +#define U2F_VERSION 0x03 // Read version string command -#define U2F_VENDOR_FIRST 0x40 // First vendor defined command -#define U2F_VENDOR_LAST 0x7f // Last vendor defined command +#define U2F_VENDOR_FIRST 0x40 // First vendor defined command +#define U2F_VENDOR_LAST 0xbf // Last vendor defined command // U2F_CMD_REGISTER command defines -#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier -#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier +#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier +#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier - typedef struct - { - uint8_t chal[U2F_CHAL_SIZE]; // Challenge - uint8_t appId[U2F_APPID_SIZE]; // Application id - } U2F_REGISTER_REQ; +typedef struct __attribute__((packed)) { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id +} U2F_REGISTER_REQ; - typedef struct - { - uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) - U2F_EC_POINT pubKey; // Generated public key - uint8_t keyHandleLen; // Length of key handle - uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle - U2F_MAX_ATT_CERT_SIZE + // Attestation certificate - U2F_MAX_EC_SIG_SIZE]; // Registration signature - } U2F_REGISTER_RESP; +typedef struct __attribute__((packed)) { + uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) + U2F_EC_POINT pubKey; // Generated public key + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandleCertSig[ + U2F_MAX_KH_SIZE + // Key handle + U2F_MAX_ATT_CERT_SIZE + // Attestation certificate + U2F_MAX_EC_SIG_SIZE]; // Registration signature +} U2F_REGISTER_RESP; // U2F_CMD_AUTHENTICATE command defines // Authentication control byte -#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign -#define U2F_AUTH_CHECK_ONLY 0x07 // Check only -#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set +#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign +#define U2F_AUTH_CHECK_ONLY 0x07 // Check only +#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set - typedef struct - { - uint8_t chal[U2F_CHAL_SIZE]; // Challenge - uint8_t appId[U2F_APPID_SIZE]; // Application id - uint8_t keyHandleLen; // Length of key handle - uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle - } U2F_AUTHENTICATE_REQ; +typedef struct __attribute__((packed)) { + uint8_t chal[U2F_CHAL_SIZE]; // Challenge + uint8_t appId[U2F_APPID_SIZE]; // Application id + uint8_t keyHandleLen; // Length of key handle + uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle +} U2F_AUTHENTICATE_REQ; - typedef struct - { - uint8_t flags; // U2F_AUTH_FLAG_ values - uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) - uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature - } U2F_AUTHENTICATE_RESP; - -// Common raw message format (ISO7816-4:2005 mapping) - - typedef struct - { - uint8_t cla; // Class - reserved - uint8_t ins; // U2F instruction - uint8_t p1; // U2F parameter 1 - uint8_t p2; // U2F parameter 2 - uint8_t lc1; // Length field, set to zero - uint8_t lc2; // Length field, MSB - uint8_t lc3; // Length field, LSB - uint8_t data[1]; // Data field - } U2F_MSG; +typedef struct __attribute__((packed)) { + uint8_t flags; // U2F_AUTH_FLAG_ values + uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) + uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature +} U2F_AUTHENTICATE_RESP; // Command status responses -#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR -#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH -#define U2F_SW_DATA_INVALID 0x6984 // SW_WRONG_DATA -#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED -#define U2F_SW_WRONG_DATA 0x6a80 // SW_WRONG_DATA -#define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED -#define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED +#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR +#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH +#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA +#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED +#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED +#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED +#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00 // SW_CLA_NOT_SUPPORTED #ifdef __cplusplus } #endif -#endif // __U2F_H_INCLUDED__ +#endif // __U2F_H_INCLUDED__ diff --git a/firmware/u2f/u2f_hid.h b/firmware/u2f/u2f_hid.h index 326a3fc223..f29059da21 100644 --- a/firmware/u2f/u2f_hid.h +++ b/firmware/u2f/u2f_hid.h @@ -1,142 +1,132 @@ -/* - Copyright (C) 2013-2015 Yubico AB - - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, see . -*/ - -// Common U2F HID transport header. -// 2014-08-21 J Ehrensvard, Yubico, Inc. +/** + * Copyright FIDO Alliance, 2017 + * + * Licensed under CC-BY: + * https://creativecommons.org/licenses/by/4.0/legalcode + * + * Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com + */ #ifndef __U2FHID_H_INCLUDED__ #define __U2FHID_H_INCLUDED__ -#ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; +#ifdef _MSC_VER // Windows +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; typedef unsigned long int uint64_t; #else #include #endif #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif -// Size of HID reports +// Size of HID reports -#define HID_RPT_SIZE 64 // Default size of raw HID report +#define HID_RPT_SIZE 64 // Default size of raw HID report // Frame layout - command- and continuation frames -#define CID_BROADCAST 0xffffffff // Broadcast channel id +#define CID_BROADCAST 0xffffffff // Broadcast channel id -#define TYPE_MASK 0x80 // Frame type mask -#define TYPE_INIT 0x80 // Initial frame identifier -#define TYPE_CONT 0x00 // Continuation frame identifier +#define TYPE_MASK 0x80 // Frame type mask +#define TYPE_INIT 0x80 // Initial frame identifier +#define TYPE_CONT 0x00 // Continuation frame identifier - typedef struct - { - uint32_t cid; // Channel identifier - union - { - uint8_t type; // Frame type - b7 defines type - struct - { - uint8_t cmd; // Command - b7 set - uint8_t bcnth; // Message byte count - high part - uint8_t bcntl; // Message byte count - low part - uint8_t data[HID_RPT_SIZE - 7]; // Data payload - } init; - struct - { - uint8_t seq; // Sequence number - b7 cleared - uint8_t data[HID_RPT_SIZE - 5]; // Data payload - } cont; - }; - } U2FHID_FRAME; +typedef struct __attribute__((packed)) { + uint32_t cid; // Channel identifier + union __attribute__((packed)) { + uint8_t type; // Frame type - b7 defines type + struct __attribute__((packed)) { + uint8_t cmd; // Command - b7 set + uint8_t bcnth; // Message byte count - high part + uint8_t bcntl; // Message byte count - low part + uint8_t data[HID_RPT_SIZE - 7]; // Data payload + } init; + struct __attribute__((packed)) { + uint8_t seq; // Sequence number - b7 cleared + uint8_t data[HID_RPT_SIZE - 5]; // Data payload + } cont; + }; +} U2FHID_FRAME; #define FRAME_TYPE(f) ((f).type & TYPE_MASK) #define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) -#define MSG_LEN(f) (((f).init.bcnth << 8) + (f).init.bcntl) +#define MSG_LEN(f) ((f).init.bcnth*256 + (f).init.bcntl) #define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) // HID usage- and usage-page definitions -#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page -#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection -#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report -#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report +#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page +#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection +#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report +#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report -// General constants +// General constants -#define U2FHID_IF_VERSION 2 // Current interface implementation version -#define U2FHID_FRAME_TIMEOUT 500 // Default frame timeout in ms -#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms +#define U2FHID_IF_VERSION 2 // Current interface implementation version +#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms // U2FHID native commands -#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only -#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame -#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command -#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization -#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink -#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response +#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only +#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame +#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command +#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization +#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink +#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command +#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response -#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command -#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command +#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command +#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command // U2FHID_INIT command defines -#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge -#define CAPFLAG_WINK 0x01 // Device supports WINK command -#define CAPFLAG_LOCK 0x02 // Device supports LOCK command +#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge +#define CAPFLAG_WINK 0x01 // Device supports WINK command +#define CAPFLAG_LOCK 0x02 // Device supports LOCK command - typedef struct - { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce - } U2FHID_INIT_REQ; +typedef struct __attribute__((packed)) { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce +} U2FHID_INIT_REQ; - typedef struct - { - uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce - uint32_t cid; // Channel identifier - uint8_t versionInterface; // Interface version - uint8_t versionMajor; // Major version number - uint8_t versionMinor; // Minor version number - uint8_t versionBuild; // Build version number - uint8_t capFlags; // Capabilities flags - } U2FHID_INIT_RESP; +typedef struct __attribute__((packed)) { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint32_t cid; // Channel identifier + uint8_t versionInterface; // Interface version + uint8_t versionMajor; // Major version number + uint8_t versionMinor; // Minor version number + uint8_t versionBuild; // Build version number + uint8_t capFlags; // Capabilities flags +} U2FHID_INIT_RESP; -#define U2FHID_INIT_RESP_SIZE 17 +// U2FHID_SYNC command defines + +typedef struct __attribute__((packed)) { + uint8_t nonce; // Client application nonce +} U2FHID_SYNC_REQ; + +typedef struct __attribute__((packed)) { + uint8_t nonce; // Client application nonce +} U2FHID_SYNC_RESP; // Low-level error codes. Return as negatives. -#define ERR_NONE 0x00 // No error -#define ERR_INVALID_CMD 0x01 // Invalid command -#define ERR_INVALID_PAR 0x02 // Invalid parameter -#define ERR_INVALID_LEN 0x03 // Invalid message length -#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing -#define ERR_MSG_TIMEOUT 0x05 // Message has timed out -#define ERR_CHANNEL_BUSY 0x06 // Channel busy -#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock -#define ERR_INVALID_CID 0x0b // Command not allowed on this cid -#define ERR_OTHER 0x7f // Other unspecified error +#define ERR_NONE 0x00 // No error +#define ERR_INVALID_CMD 0x01 // Invalid command +#define ERR_INVALID_PAR 0x02 // Invalid parameter +#define ERR_INVALID_LEN 0x03 // Invalid message length +#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing +#define ERR_MSG_TIMEOUT 0x05 // Message has timed out +#define ERR_CHANNEL_BUSY 0x06 // Channel busy +#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock +#define ERR_INVALID_CID 0x0b // Message on CID 0 +#define ERR_OTHER 0x7f // Other unspecified error #ifdef __cplusplus } #endif -#endif // __U2FHID_H_INCLUDED__ +#endif // __U2FHID_H_INCLUDED__ From 666b9701d2ad447a039c68693956ff0d66e1be62 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 18 Dec 2018 11:50:28 +0100 Subject: [PATCH 1037/1154] firmware: update changelog --- firmware/ChangeLog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index c47c9f29d9..25d20af551 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,6 +1,8 @@ -Version 1.7.2 [unreleased] +Version 1.7.2 * Stable release, optional update * Add support for OMNI layer: OMNI/MAID/USDT +* U2F fixes +* Don't ask for PIN if it has been just set Version 1.7.1 * Stable release, optional update From cd112497a5ea0e8a32219b78d1ef5d88e957d6d0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 18 Dec 2018 14:49:31 +0100 Subject: [PATCH 1038/1154] u2f: fix gcc/clang warning --- firmware/u2f.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/u2f.c b/firmware/u2f.c index 18ef2797b1..2b25bdd6eb 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -287,7 +287,9 @@ void u2fhid_init(const U2FHID_FRAME *in) { const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; U2FHID_FRAME f; - U2FHID_INIT_RESP resp = {0}; + U2FHID_INIT_RESP resp; + + memset(&resp, 0, sizeof(resp)); debugLog(0, "", "u2fhid_init"); From 2b40fdcdd1f9dc9f6e2dea6ef30bc81b74d5ce75 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Dec 2018 17:42:33 +0100 Subject: [PATCH 1039/1154] bootloader: use fixed serial number (instead of empty one) --- bootloader/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 9c6231713d..7298d95e78 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -118,7 +118,7 @@ static const struct usb_config_descriptor config = { static const char *usb_strings[] = { "SatoshiLabs", "TREZOR", - "", // empty serial + "000000000000000000000000", }; enum { From 4d502bb5de2e3b6bf98e7ea41cc273cef7b0799b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Dec 2018 17:45:08 +0100 Subject: [PATCH 1040/1154] bump versions --- bootloader/bootloader.h | 4 ++-- firmware/trezor.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 8f9f873516..c7f214f080 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -22,14 +22,14 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 6 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" #define VERSION_MINOR_CHAR "\x06" -#define VERSION_PATCH_CHAR "\x00" +#define VERSION_PATCH_CHAR "\x01" #include #include "memory.h" diff --git a/firmware/trezor.h b/firmware/trezor.h index f9d28a13c7..dc3d471cb1 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -24,7 +24,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 7 -#define VERSION_PATCH 2 +#define VERSION_PATCH 3 #define STR(X) #X #define VERSTR(X) STR(X) From a819a1c41becc659d00028ecaebd44c5c32b903d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Dec 2018 18:02:42 +0100 Subject: [PATCH 1041/1154] firmware: add new bl hash to whitelist --- firmware/bl_check.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 805c8e0c78..92c0a76e14 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -42,7 +42,8 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 shipped with fw 1.6.2 if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 shipped with fw 1.6.3 if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 - if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 + if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 + if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 return 0; } From f641e798f91a15c3b09e8dc6a163195dd56f86d2 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 19 Dec 2018 18:04:23 +0100 Subject: [PATCH 1042/1154] script: fix maximum file size --- script/fullbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/fullbuild b/script/fullbuild index 044ab94e63..f8ddb87424 100755 --- a/script/fullbuild +++ b/script/fullbuild @@ -125,7 +125,7 @@ main() { printf "\n\n"; $PYTHON script/fingerprint \ "$firmware_path" \ --offset 256 \ - --max-size 491520 + --max-size 983296 # 256 + 64*1024 + 3*128*1024 + 4*128*1024 } main "$@" From 8adb269e27e28cf2f6118b1557233d52d4e39271 Mon Sep 17 00:00:00 2001 From: OliverBenT <37402943+OliverBenT@users.noreply.github.com> Date: Sun, 23 Dec 2018 21:45:42 +0100 Subject: [PATCH 1043/1154] changelog: update, add 1.7.3 --- firmware/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 25d20af551..e754d1c171 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,7 @@ +Version 1.7.3 +* Stable release, optional update +* Fix USB issue on some Windows 10 installations + Version 1.7.2 * Stable release, optional update * Add support for OMNI layer: OMNI/MAID/USDT From e86d39ef2da4668c057a441d35488c9f901c7b92 Mon Sep 17 00:00:00 2001 From: Reproducibility Matters Date: Wed, 9 Jan 2019 12:41:21 +0100 Subject: [PATCH 1044/1154] Add sha256sum check to protobuf binaries in Dockerfile (#445) The docker build fails if the hash is incorrect. --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 71bedcbbb6..585343fa88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,9 @@ RUN if [ "$EMULATOR" = 1 ]; then \ fi ENV PROTOBUF_VERSION=3.4.0 +ENV PROTOBUF_HASH=e4b51de1b75813e62d6ecdde582efa798586e09b5beaebfb866ae7c9eaadace4 RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" +RUN echo "${PROTOBUF_HASH} protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" | sha256sum -c ENV PYTHON=python3 ENV LC_ALL=C.UTF-8 From 7dce7bd92d65726e08e0311f9821f6cc966b44a1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Jan 2019 12:37:49 +0100 Subject: [PATCH 1045/1154] nix: drop ver from gcc in shell.nix --- shell.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.nix b/shell.nix index 8dc128a369..e09b2131d9 100644 --- a/shell.nix +++ b/shell.nix @@ -5,5 +5,5 @@ let in stdenv.mkDerivation { name = "trezor-mcu-dev"; - buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded-7 pkgconfig SDL2 SDL2_image ]; + buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image ]; } From 93106a49686a29093fb8580bc7aa2130a441bdc4 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Mon, 14 Jan 2019 15:07:03 +0100 Subject: [PATCH 1046/1154] vendor: trezor-common update --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index 482a8e37f0..78e232cf30 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 482a8e37f0f627bfefc720ed0bd8a8c4a93cdbe3 +Subproject commit 78e232cf30d5d30ec1c7f06a740bbc990cc648e9 From 0d4efce5a7aa83e23894fcfe75d2ddd1984d6d6d Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Mon, 14 Jan 2019 16:27:59 +0100 Subject: [PATCH 1047/1154] eth: get public key --- firmware/fsm.h | 1 + firmware/fsm_msg_ethereum.h | 46 +++++++++++++++++++++++ firmware/protob/Makefile | 2 +- firmware/protob/messages-ethereum.options | 2 + firmware/protob/messages_map.py | 3 +- 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/firmware/fsm.h b/firmware/fsm.h index 75de088c51..0b07d1e1f6 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -91,6 +91,7 @@ void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg); // ethereum void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg); +void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg); void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction void fsm_msgEthereumTxAck(const EthereumTxAck *msg); void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg); diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 7f67de088e..e6cbc452b1 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -17,6 +17,52 @@ * along with this library. If not, see . */ +void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) +{ + RESP_INIT(EthereumPublicKey); + + CHECK_INITIALIZED + + CHECK_PIN + + const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); // we use Bitcoin-like format for ETH + + const char *curve = coin->curve_name; + uint32_t fingerprint; + HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); + + if (msg->has_show_display && msg->show_display) { + layoutPublicKey(node->public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + resp->node.depth = node->depth; + resp->node.fingerprint = fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } + resp->has_xpub = true; + + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); + + msg_write(MessageType_MessageType_EthereumPublicKey, resp); + layoutHome(); +} + void fsm_msgEthereumSignTx(EthereumSignTx *msg) { CHECK_INITIALIZED diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 6fc525caee..0cf8453c18 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron -e EthereumGetPublicKey -e EthereumPublicKey > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/protob/messages-ethereum.options b/firmware/protob/messages-ethereum.options index c32f6813ed..07b148c97b 100644 --- a/firmware/protob/messages-ethereum.options +++ b/firmware/protob/messages-ethereum.options @@ -22,5 +22,7 @@ EthereumMessageSignature.address max_size:20 EthereumMessageSignature.signature max_size:65 EthereumGetAddress.address_n max_count:8 +EthereumGetPublicKey.address_n max_count:8 EthereumAddress.address max_size:20 +EthereumPublicKey.xpub max_size:113 diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index ef98014954..f5ab67d274 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -49,8 +49,7 @@ def handle_message(message, extension): ) -print("\t// This file is automatically generated" - "by messages_map.py -- DO NOT EDIT!") +print("\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!") messages = defaultdict(list) From cf0b5d669b2b9e67c745f3b84045302f312870cd Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Mon, 14 Jan 2019 16:29:06 +0100 Subject: [PATCH 1048/1154] eth: don't check for ed25519 in get public key --- firmware/fsm_msg_ethereum.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index e6cbc452b1..0d490fe084 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -51,10 +51,6 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->node.public_key.bytes[0] = 0; - } resp->has_xpub = true; hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); From cbba5f28ae69dfb9f6ef853502d80048234c97e5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 14 Jan 2019 17:15:55 +0100 Subject: [PATCH 1049/1154] ethereum: nitpick in GetPublicKey --- firmware/fsm_msg_ethereum.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 0d490fe084..1ae7efa800 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -25,7 +25,9 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) CHECK_PIN - const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); // we use Bitcoin-like format for ETH + // we use Bitcoin-like format for ETH + const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); + if (!coin) return; const char *curve = coin->curve_name; uint32_t fingerprint; From f684f4ad243abfed03c53946a85493e03d272ec7 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Wed, 16 Jan 2019 13:23:44 +0100 Subject: [PATCH 1050/1154] docs: contributing file --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..d885604ed5 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contribute to Trezor MCU + +Please read the general instructions you can find on our [wiki](https://wiki.trezor.io/Developers_guide:Contributing). + +If you are working on a new feature, you probably want to contribute this to the [trezor-core](https://github.com/trezor/trezor-core) repository instead. From 66a8d1834855325e76a283b2d4fd76721213f9d6 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 16:49:04 +0100 Subject: [PATCH 1051/1154] bootloader: remove obsoleted self-test --- bootloader/usb.c | 89 ------------------------------------------------ 1 file changed, 89 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 7298d95e78..2930c48c25 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -240,15 +240,6 @@ static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) , 64) != 64) {} } -static void erase_metadata_sectors(void) -{ - flash_unlock(); - for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_lock(); -} - static void backup_metadata(uint8_t *backup) { memcpy(backup, FLASH_PTR(FLASH_META_START), FLASH_META_LEN); @@ -332,86 +323,6 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } return; } - if (msg_id == 0x0020) { // SelfTest message (id 32) - - // USB TEST - layoutProgress("TESTING USB ...", 0); - bool status_usb = (buf[9] == 0x0a) && (buf[10] == 53) && (0 == memcmp(buf + 11, "\x00\xFF\x55\xAA\x66\x99\x33\xCC" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!" "\x00\xFF\x55\xAA\x66\x99\x33\xCC", 53)); - - // RNG TEST - layoutProgress("TESTING RNG ...", 250); - uint32_t cnt[256]; - memset(cnt, 0, sizeof(cnt)); - for (int i = 0; i < (256 * 2000); i++) { - uint32_t r = random32(); - cnt[r & 0xFF]++; - cnt[(r >> 8) & 0xFF]++; - cnt[(r >> 16) & 0xFF]++; - cnt[(r >> 24) & 0xFF]++; - } - bool status_rng = true; - for (int i = 0; i < 256; i++) { - status_rng = status_rng && (cnt[i] >= 7600) && (cnt[i] <= 8400); - } - - // CPU TEST - layoutProgress("TESTING CPU ...", 500); - // privkey : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - // pubkey : 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd - // 5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235 - // digest : c84a4cc264100070c8be2acf4072efaadaedfef3d6209c0fe26387e6b1262bbf - // sig: : f7869c679bbed1817052affd0264ccc6486795f6d06d0c187651b8f3863670c8 - // 2ccf89be32a53eb65ea7c007859783d46717986fead0833ec60c5729cdc4a9ee - bool status_cpu = (0 == ecdsa_verify_digest(&secp256k1, - (const uint8_t *)"\x04\xa3\x4b\x99\xf2\x2c\x79\x0c\x4e\x36\xb2\xb3\xc2\xc3\x5a\x36\xdb\x06\x22\x6e\x41\xc6\x92\xfc\x82\xb8\xb5\x6a\xc1\xc5\x40\xc5\xbd\x5b\x8d\xec\x52\x35\xa0\xfa\x87\x22\x47\x6c\x77\x09\xc0\x25\x59\xe3\xaa\x73\xaa\x03\x91\x8b\xa2\xd4\x92\xee\xa7\x5a\xbe\xa2\x35", - (const uint8_t *)"\xf7\x86\x9c\x67\x9b\xbe\xd1\x81\x70\x52\xaf\xfd\x02\x64\xcc\xc6\x48\x67\x95\xf6\xd0\x6d\x0c\x18\x76\x51\xb8\xf3\x86\x36\x70\xc8\x2c\xcf\x89\xbe\x32\xa5\x3e\xb6\x5e\xa7\xc0\x07\x85\x97\x83\xd4\x67\x17\x98\x6f\xea\xd0\x83\x3e\xc6\x0c\x57\x29\xcd\xc4\xa9\xee", - (const uint8_t *)"\xc8\x4a\x4c\xc2\x64\x10\x00\x70\xc8\xbe\x2a\xcf\x40\x72\xef\xaa\xda\xed\xfe\xf3\xd6\x20\x9c\x0f\xe2\x63\x87\xe6\xb1\x26\x2b\xbf")); - - // FLASH TEST - layoutProgress("TESTING FLASH ...", 750); - - // backup metadata - backup_metadata(meta_backup); - - // write test pattern - erase_metadata_sectors(); - flash_unlock(); - for (int i = 0; i < FLASH_META_LEN / 4; i++) { - flash_program_word(FLASH_META_START + i * 4, 0x3C695A0F); - } - flash_lock(); - - // compute hash of written test pattern - uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_META_START), FLASH_META_LEN, hash); - - // restore metadata from backup - erase_metadata_sectors(); - restore_metadata(meta_backup); - memzero(meta_backup, sizeof(meta_backup)); - - // compare against known hash computed via the following Python3 script: - // hashlib.sha256(binascii.unhexlify('0F5A693C' * 8192)).hexdigest() - bool status_flash = (0 == memcmp(hash, "\xa6\xc2\x25\xa4\x76\xa1\xde\x76\x09\xe0\xb0\x07\xf8\xe2\x5a\xec\x1d\x75\x8d\x5c\x36\xc8\x4a\x6b\x75\x4e\xd5\x3d\xe6\x99\x97\x64", 32)); - - bool status_all = status_usb && status_rng && status_cpu && status_flash; - - if (status_all) { - send_msg_success(dev); - } else { - send_msg_failure(dev); - } - layoutDialog(status_all ? &bmp_icon_info : &bmp_icon_error, - NULL, NULL, NULL, - status_usb ? "Test USB ... OK" : "Test USB ... Failed", - status_rng ? "Test RNG ... OK" : "Test RNG ... Failed", - status_cpu ? "Test CPU ... OK" : "Test CPU ... Failed", - status_flash ? "Test FLASH ... OK" : "Test FLASH ... Failed", - NULL, - NULL - ); - return; - } } if (flash_state == STATE_OPEN) { From 79779f4da64e82016fee6124363e3ed979747863 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 17:00:01 +0100 Subject: [PATCH 1052/1154] replace all usage of memset(_, 0, _) with memzero --- firmware/ethereum.c | 10 +++---- firmware/fsm.c | 3 ++- firmware/fsm_msg_debug.h | 2 +- firmware/layout2.c | 9 ++++--- firmware/messages.c | 3 ++- firmware/nem2.c | 3 ++- firmware/protect.c | 6 ++--- firmware/recovery.c | 2 +- firmware/reset.c | 5 ++-- firmware/signing.c | 6 ++--- firmware/stellar.c | 58 ++++++++++++++++++++-------------------- firmware/storage.c | 6 ++--- firmware/transaction.c | 5 ++-- firmware/u2f.c | 16 +++++------ oled.c | 3 ++- vendor/trezor-crypto | 2 +- 16 files changed, 73 insertions(+), 66 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index fa6b3256fb..29168d5740 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -276,7 +276,7 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui { bignum256 val; uint8_t pad_val[32]; - memset(pad_val, 0, sizeof(pad_val)); + memzero(pad_val, sizeof(pad_val)); memcpy(pad_val + (32 - value_len), value, value_len); bn_read_be(pad_val, &val); @@ -377,18 +377,18 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, char tx_value[32]; char gas_value[32]; - memset(pad_val, 0, sizeof(pad_val)); + memzero(pad_val, sizeof(pad_val)); memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); bn_read_be(pad_val, &val); - memset(pad_val, 0, sizeof(pad_val)); + memzero(pad_val, sizeof(pad_val)); memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); bn_read_be(pad_val, &gas); bn_multiply(&val, &gas, &secp256k1.prime); ethereumFormatAmount(&gas, NULL, gas_value, sizeof(gas_value)); - memset(pad_val, 0, sizeof(pad_val)); + memzero(pad_val, sizeof(pad_val)); memcpy(pad_val + (32 - value_len), value, value_len); bn_read_be(pad_val, &val); @@ -450,7 +450,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) ethereum_signing = true; sha3_256_Init(&keccak_ctx); - memset(&msg_tx_request, 0, sizeof(EthereumTxRequest)); + memzero(&msg_tx_request, sizeof(EthereumTxRequest)); /* set fields to 0, to avoid conditions later */ if (!msg->has_value) msg->value.size = 0; diff --git a/firmware/fsm.c b/firmware/fsm.c index 2e379e56b1..50fd0fc45c 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -58,6 +58,7 @@ #include "messages.pb.h" #include "stellar.h" #include "lisk.h" +#include "memzero.h" // message methods @@ -66,7 +67,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); #define RESP_INIT(TYPE) \ TYPE *resp = (TYPE *) (void *) msg_resp; \ _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ - memset(resp, 0, sizeof(TYPE)); + memzero(resp, sizeof(TYPE)); #define CHECK_INITIALIZED \ if (!storage_isInitialized()) { \ diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 29302bd4e1..2ac38d4727 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -26,7 +26,7 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) // Do not use RESP_INIT because it clears msg_resp, but another message // might be being handled DebugLinkState resp; - memset(&resp, 0, sizeof(resp)); + memzero(&resp, sizeof(resp)); resp.has_layout = true; resp.layout.size = OLED_BUFSIZE; diff --git a/firmware/layout2.c b/firmware/layout2.c index dbc36c7bb3..14f334f572 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -33,6 +33,7 @@ #include "secp256k1.h" #include "nem2.h" #include "gettext.h" +#include "memzero.h" #define BITCOIN_DIVISIBILITY (8) @@ -98,7 +99,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou } const uint32_t accnum = address_is_account ? ((address_n[4] & 0x7fffffff) + 1) : (address_n[2] & 0x7fffffff) + 1; if (abbr && accnum < 100) { - memset(path, 0, sizeof(path)); + memzero(path, sizeof(path)); strlcpy(path, abbr, sizeof(path)); // TODO: how to name accounts? // currently we have "legacy account", "account" and "segwit account" @@ -115,7 +116,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou strlcat(path, " account #", sizeof(path)); } char acc[3]; - memset(acc, 0, sizeof(acc)); + memzero(acc, sizeof(acc)); if (accnum < 10) { acc[0] = '0' + accnum; } else { @@ -163,7 +164,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) if (rowlen > 32) { rowlen = 32; } - memset(str, 0, sizeof(str)); + memzero(str, sizeof(str)); strlcpy(str[0], (char *)msg, rowlen + 1); if (len > rowlen) { strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); @@ -186,7 +187,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) const char **split_message_hex(const uint8_t *msg, uint32_t len) { char hex[32 * 2 + 1]; - memset(hex, 0, sizeof(hex)); + memzero(hex, sizeof(hex)); uint32_t size = len; if (len > 32) { size = 32; diff --git a/firmware/messages.c b/firmware/messages.c index 3d4500240f..28ac098776 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -25,6 +25,7 @@ #include "fsm.h" #include "util.h" #include "gettext.h" +#include "memzero.h" #include "pb_decode.h" #include "pb_encode.h" @@ -220,7 +221,7 @@ enum { void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) { static CONFIDENTIAL uint8_t msg_data[MSG_IN_SIZE]; - memset(msg_data, 0, sizeof(msg_data)); + memzero(msg_data, sizeof(msg_data)); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); bool status = pb_decode(&stream, fields, msg_data); if (status) { diff --git a/firmware/nem2.c b/firmware/nem2.c index cad737032f..65c3cf77bd 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -26,6 +26,7 @@ #include "protect.h" #include "rng.h" #include "secp256k1.h" +#include "memzero.h" const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { if (!common->has_network) { @@ -733,7 +734,7 @@ size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { size_t actual_count = 0; bool skip[mosaics_count]; - memset(skip, 0, sizeof(skip)); + memzero(skip, sizeof(skip)); // Merge duplicates for (size_t i = 0; i < mosaics_count; i++) { diff --git a/firmware/protect.c b/firmware/protect.c index cbce28acde..4a1d12c7ed 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -47,7 +47,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) bool debug_decided = false; #endif - memset(&resp, 0, sizeof(ButtonRequest)); + memzero(&resp, sizeof(ButtonRequest)); resp.has_code = true; resp.code = type; usbTiny(1); @@ -114,7 +114,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) const char *requestPin(PinMatrixRequestType type, const char *text) { PinMatrixRequest resp; - memset(&resp, 0, sizeof(PinMatrixRequest)); + memzero(&resp, sizeof(PinMatrixRequest)); resp.has_type = true; resp.type = type; usbTiny(1); @@ -247,7 +247,7 @@ bool protectPassphrase(void) } PassphraseRequest resp; - memset(&resp, 0, sizeof(PassphraseRequest)); + memzero(&resp, sizeof(PassphraseRequest)); usbTiny(1); msg_write(MessageType_MessageType_PassphraseRequest, &resp); diff --git a/firmware/recovery.c b/firmware/recovery.c index b0d8c27c98..f67af3bcdc 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -141,7 +141,7 @@ static void format_number(char *dest, int number) { */ static void recovery_request(void) { WordRequest resp; - memset(&resp, 0, sizeof(WordRequest)); + memzero(&resp, sizeof(WordRequest)); resp.has_type = true; resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 diff --git a/firmware/reset.c b/firmware/reset.c index ff7819d45d..f5e16ad31d 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -29,6 +29,7 @@ #include "util.h" #include "gettext.h" #include "messages.pb.h" +#include "memzero.h" static uint32_t strength; static uint8_t int_entropy[32]; @@ -87,7 +88,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect storage_update(); EntropyRequest resp; - memset(&resp, 0, sizeof(EntropyRequest)); + memzero(&resp, sizeof(EntropyRequest)); msg_write(MessageType_MessageType_EntropyRequest, &resp); awaiting_entropy = true; } @@ -109,7 +110,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) storage_setNeedsBackup(true); } storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); - memset(int_entropy, 0, 32); + memzero(int_entropy, 32); awaiting_entropy = false; if (skip_backup || no_backup) { diff --git a/firmware/signing.c b/firmware/signing.c index 1574f679e9..37895258c2 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -500,8 +500,8 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) spending = 0; change_spend = 0; authorized_amount = 0; - memset(&input, 0, sizeof(TxInputType)); - memset(&resp, 0, sizeof(TxRequest)); + memzero(&input, sizeof(TxInputType)); + memzero(&resp, sizeof(TxRequest)); signing = true; progress = 0; @@ -978,7 +978,7 @@ void signing_txack(TransactionType *tx) update_ctr = 0; } - memset(&resp, 0, sizeof(TxRequest)); + memzero(&resp, sizeof(TxRequest)); switch (signing_stage) { case STAGE_REQUEST_1_INPUT: diff --git a/firmware/stellar.c b/firmware/stellar.c index 0b6cdb4fe4..dc6b88f903 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -54,7 +54,7 @@ static StellarTransaction stellar_activeTx; */ bool stellar_signingInit(const StellarSignTx *msg) { - memset(&stellar_activeTx, 0, sizeof(StellarTransaction)); + memzero(&stellar_activeTx, sizeof(StellarTransaction)); stellar_signing = true; // Initialize signing context sha256_Init(&(stellar_activeTx.sha256_ctx)); @@ -267,7 +267,7 @@ bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) strlcat(str_to, str_addr_rows[0], sizeof(str_to)); char str_asset_row[32]; - memset(str_asset_row, 0, sizeof(str_asset_row)); + memzero(str_asset_row, sizeof(str_asset_row)); stellar_format_asset(&(msg->asset), str_asset_row, sizeof(str_asset_row)); char str_pay_amount[32]; @@ -585,7 +585,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) char str_title[32]; char rows[4][32]; int row_idx = 0; - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); // Inflation destination stellar_hashupdate_bool(msg->has_inflation_destination_account); @@ -643,7 +643,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) stellar_signingAbort(_("User canceled")); return false; } - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); row_idx = 0; // Hash flags @@ -677,7 +677,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) stellar_signingAbort(_("User canceled")); return false; } - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); row_idx = 0; // Hash flags @@ -750,7 +750,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) stellar_signingAbort(_("User canceled")); return false; } - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); row_idx = 0; } @@ -780,7 +780,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) stellar_signingAbort(_("User canceled")); return false; } - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); row_idx = 0; stellar_hashupdate_string((unsigned char*)&(msg->home_domain), strnlen(msg->home_domain, 32)); @@ -876,7 +876,7 @@ bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) stellar_signingAbort(_("User canceled")); return false; } - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); row_idx = 0; } @@ -1019,13 +1019,13 @@ bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) // asset code if (msg->asset_type == 1) { char code4[4+1]; - memset(code4, 0, sizeof(code4)); + memzero(code4, sizeof(code4)); strlcpy(code4, msg->asset_code, sizeof(code4)); stellar_hashupdate_bytes((uint8_t *)code4, 4); } if (msg->asset_type == 2) { char code12[12+1]; - memset(code12, 0, sizeof(code12)); + memzero(code12, sizeof(code12)); strlcpy(code12, msg->asset_code, sizeof(code12)); stellar_hashupdate_bytes((uint8_t *)code12, 12); } @@ -1233,7 +1233,7 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature) const HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); if (!node) { // return empty signature when we can't derive node - memset(out_signature, 0, 64); + memzero(out_signature, 64); return; } @@ -1271,7 +1271,7 @@ void stellar_format_stroops(uint64_t number, char *out, size_t outlen) */ void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen) { - memset(out, 0, outlen); + memzero(out, outlen); // early exit for invalid denominator if (denominator == 0) { @@ -1328,7 +1328,7 @@ const char **stellar_lineBreakAddress(const uint8_t *addrbytes) char str_fulladdr[56+1]; static char rows[3][20+1]; - memset(rows, 0, sizeof(rows)); + memzero(rows, sizeof(rows)); // get full address string stellar_publicAddressAsStr(addrbytes, str_fulladdr, sizeof(str_fulladdr)); @@ -1356,9 +1356,9 @@ void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, si // truncated asset issuer, final length depends on length of asset code char str_asset_issuer_trunc[13 + 1]; - memset(str_formatted, 0, len); - memset(str_asset_code, 0, sizeof(str_asset_code)); - memset(str_asset_issuer_trunc, 0, sizeof(str_asset_issuer_trunc)); + memzero(str_formatted, len); + memzero(str_asset_code, sizeof(str_asset_code)); + memzero(str_asset_issuer_trunc, sizeof(str_asset_issuer_trunc)); // Validate issuer account for non-native assets if (asset->type != 0 && !stellar_validateAddress(asset->issuer)) { @@ -1621,8 +1621,8 @@ void stellar_hashupdate_asset(const StellarAssetType *asset) // 4-character asset code if (asset->type == 1) { - char code4[4+1]; - memset(code4, 0, sizeof(code4)); + char code4[4 + 1]; + memzero(code4, sizeof(code4)); strlcpy(code4, asset->code, sizeof(code4)); stellar_hashupdate_bytes((uint8_t *)code4, 4); @@ -1631,8 +1631,8 @@ void stellar_hashupdate_asset(const StellarAssetType *asset) // 12-character asset code if (asset->type == 2) { - char code12[12+1]; - memset(code12, 0, sizeof(code12)); + char code12[12 + 1]; + memzero(code12, sizeof(code12)); strlcpy(code12, asset->code, sizeof(code12)); stellar_hashupdate_bytes((uint8_t *)code12, 12); @@ -1651,7 +1651,7 @@ void stellar_hashupdate_bytes(const uint8_t *data, size_t len) void stellar_layoutTransactionSummary(const StellarSignTx *msg) { char str_lines[5][32]; - memset(str_lines, 0, sizeof(str_lines)); + memzero(str_lines, sizeof(str_lines)); char str_fee[12]; char str_num_ops[12]; @@ -1693,7 +1693,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) } // Reset lines for displaying memo - memset(str_lines, 0, sizeof(str_lines)); + memzero(str_lines, sizeof(str_lines)); // Memo: none if (msg->memo_type == 0) { @@ -1747,7 +1747,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) } // Verify timebounds, if present - memset(str_lines, 0, sizeof(str_lines)); + memzero(str_lines, sizeof(str_lines)); // Timebound: lower if (msg->timebounds_start || msg->timebounds_end) { @@ -1767,7 +1767,7 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) } // Reset for timebound_max - memset(str_timebound, 0, sizeof(str_timebound)); + memzero(str_timebound, sizeof(str_timebound)); timebound = (time_t)msg->timebounds_end; strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); @@ -1817,22 +1817,22 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha } char str_pubaddr_truncated[12]; // G???? + null - memset(str_pubaddr_truncated, 0, sizeof(str_pubaddr_truncated)); + memzero(str_pubaddr_truncated, sizeof(str_pubaddr_truncated)); layoutLast = layoutDialogSwipe; layoutSwipe(); oledClear(); // Load up public address - char str_pubaddr[56+1]; - memset(str_pubaddr, 0, sizeof(str_pubaddr)); + char str_pubaddr[56 + 1]; + memzero(str_pubaddr, sizeof(str_pubaddr)); stellar_publicAddressAsStr(node->public_key + 1, str_pubaddr, sizeof(str_pubaddr)); memcpy(str_pubaddr_truncated, str_pubaddr, sizeof(str_pubaddr_truncated) - 1); // Header // Ends up as: Signing with GABCDEFGHIJKL char str_header[32]; - memset(str_header, 0, sizeof(str_header)); + memzero(str_header, sizeof(str_header)); strlcpy(str_header, _("Signing with "), sizeof(str_header)); strlcat(str_header, str_pubaddr_truncated, sizeof(str_header)); @@ -1896,7 +1896,7 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5) { char str_warning[16]; - memset(str_warning, 0, sizeof(str_warning)); + memzero(str_warning, sizeof(str_warning)); if (stellar_activeTx.network_type == 2) { // Warning: testnet diff --git a/firmware/storage.c b/firmware/storage.c index 956334c0b9..6e7f66db32 100644 --- a/firmware/storage.c +++ b/firmware/storage.c @@ -446,13 +446,13 @@ void storage_loadDevice(const LoadDevice *msg) storageUpdate.has_mnemonic = false; storage_setNode(&(msg->node)); sessionSeedCached = false; - memset(&sessionSeed, 0, sizeof(sessionSeed)); + memzero(&sessionSeed, sizeof(sessionSeed)); } else if (msg->has_mnemonic) { storageUpdate.has_mnemonic = true; storageUpdate.has_node = false; strlcpy(storageUpdate.mnemonic, msg->mnemonic, sizeof(storageUpdate.mnemonic)); sessionSeedCached = false; - memset(&sessionSeed, 0, sizeof(sessionSeed)); + memzero(&sessionSeed, sizeof(sessionSeed)); } if (msg->has_language) { @@ -508,7 +508,7 @@ void storage_setHomescreen(const uint8_t *data, uint32_t size) memcpy(storageUpdate.homescreen.bytes, data, size); storageUpdate.homescreen.size = size; } else { - memset(storageUpdate.homescreen.bytes, 0, sizeof(storageUpdate.homescreen.bytes)); + memzero(storageUpdate.homescreen.bytes, sizeof(storageUpdate.homescreen.bytes)); storageUpdate.homescreen.size = 0; } } diff --git a/firmware/transaction.c b/firmware/transaction.c index e7d9e91c60..f4a0845c6b 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -32,6 +32,7 @@ #include "messages.pb.h" #include "segwit_addr.h" #include "cash_addr.h" +#include "memzero.h" #define SEGWIT_VERSION_0 0 @@ -188,7 +189,7 @@ bool compute_address(const CoinInfo *coin, int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) { - memset(out, 0, sizeof(TxOutputBinType)); + memzero(out, sizeof(TxOutputBinType)); out->amount = in->amount; out->decred_script_version = in->decred_script_version; uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; @@ -623,7 +624,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) } else if (tx->version == 4) { memcpy(out + 4, &(tx->expiry), 4); - memset(out + 8, 0, 8); // valueBalance + memzero(out + 8, 8); // valueBalance out[16] = 0x00; // nShieldedSpend out[17] = 0x00; // nShieldedOutput out[18] = 0x00; // nJoinSplit diff --git a/firmware/u2f.c b/firmware/u2f.c index 2b25bdd6eb..456ca3f147 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -33,6 +33,7 @@ #include "hmac.h" #include "util.h" #include "gettext.h" +#include "memzero.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" @@ -276,7 +277,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len) dialog_timeout = U2F_TIMEOUT; U2FHID_FRAME f; - memset(&f, 0, sizeof(f)); + memzero(&f, sizeof(f)); f.cid = cid; f.init.cmd = U2FHID_WINK; f.init.bcntl = 0; @@ -288,8 +289,7 @@ void u2fhid_init(const U2FHID_FRAME *in) const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; U2FHID_FRAME f; U2FHID_INIT_RESP resp; - - memset(&resp, 0, sizeof(resp)); + memzero(&resp, sizeof(resp)); debugLog(0, "", "u2fhid_init"); @@ -298,7 +298,7 @@ void u2fhid_init(const U2FHID_FRAME *in) return; } - memset(&f, 0, sizeof(f)); + memzero(&f, sizeof(f)); f.cid = in->cid; f.init.cmd = U2FHID_INIT; f.init.bcnth = 0; @@ -383,7 +383,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // debugLog(0, "", "send_u2fhid_msg"); - memset(&f, 0, sizeof(f)); + memzero(&f, sizeof(f)); f.cid = cid; f.init.cmd = cmd; f.init.bcnth = len >> 8; @@ -399,7 +399,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) // Cont packet(s) for (; l > 0; l -= psz, p += psz) { // debugLog(0, "", "send_u2fhid_msg con"); - memset(&f.cont.data, 0, sizeof(f.cont.data)); + memzero(&f.cont.data, sizeof(f.cont.data)); f.cont.seq = seq++; psz = MIN(sizeof(f.cont.data), l); memcpy(f.cont.data, p, psz); @@ -416,7 +416,7 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err) { U2FHID_FRAME f; - memset(&f, 0, sizeof(f)); + memzero(&f, sizeof(f)); f.cid = fcid; f.init.cmd = U2FHID_ERROR; f.init.bcntl = 1; @@ -592,7 +592,7 @@ void u2f_register(const APDU *a) if (last_req_state == REG_PASS) { uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; - memset(data, 0, sizeof(data)); + memzero(data, sizeof(data)); resp->registerId = U2F_REGISTER_ID; resp->keyHandleLen = KEY_HANDLE_LEN; diff --git a/oled.c b/oled.c index 54a15b643c..77f30d526e 100644 --- a/oled.c +++ b/oled.c @@ -24,6 +24,7 @@ #include "oled.h" #include "util.h" +#include "memzero.h" #define OLED_SETCONTRAST 0x81 #define OLED_DISPLAYALLON_RESUME 0xA4 @@ -177,7 +178,7 @@ void oledInit() */ void oledClear() { - memset(_oledbuffer, 0, sizeof(_oledbuffer)); + memzero(_oledbuffer, sizeof(_oledbuffer)); } void oledInvertDebugLink() diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index c5227fdb96..c316e775a2 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit c5227fdb969520de41664bfa4b66e74e718d72c4 +Subproject commit c316e775a2152db255ace96b6b65ac0f20525ec0 From 3b5fe1125391cb9b8cfb7e6d298ac06a528099e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 23 Jan 2019 18:38:30 +0100 Subject: [PATCH 1053/1154] reset: use mnemonic_clear --- firmware/reset.c | 1 + vendor/trezor-crypto | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index f5e16ad31d..afdadab1c9 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -110,6 +110,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) storage_setNeedsBackup(true); } storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); + mnemonic_clear(); memzero(int_entropy, 32); awaiting_entropy = false; diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index c316e775a2..d1c52401e4 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit c316e775a2152db255ace96b6b65ac0f20525ec0 +Subproject commit d1c52401e4c76c74a10455682ace0655b7aa644c From afc17a23d54dea37e5fe1df0b50276b3b6a89553 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 10 Jan 2019 12:39:20 +0100 Subject: [PATCH 1054/1154] update Dockerfile and .travis.yml to be more similar to trezor-core --- .travis.yml | 30 ++++++++++++++++----------- Dockerfile | 58 ++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 18b4412626..39adb5429c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,21 +5,20 @@ language: c addons: apt: sources: - - deadsnakes + - deadsnakes packages: - - build-essential - - gcc-arm-none-eabi - - gcc-multilib - - libnewlib-arm-none-eabi - - python3.6 - - python3.6-venv - - python3.6-dev + - build-essential + - python3.6 + - python3.6-dev + - python3.6-venv env: global: - MAKEFLAGS=-j2 - PYTHON=python3.6 - PROTOBUF_VERSION=3.4.0 + - TOOLCHAIN_SHORTVER=8-2018q4 + - TOOLCHAIN_LONGVER=gcc-arm-none-eabi-8-2018-q4-major matrix: - DEBUG_LINK=0 - DEBUG_LINK=1 @@ -35,14 +34,21 @@ matrix: compiler: clang script: pipenv run ./script/cibuild && pipenv run script/test -install: - - curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" - - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc - - export PATH="$(pwd)/protoc/bin:$PATH" +before_install: - $PYTHON -m ensurepip --user - $PYTHON -m pip install --user pipenv + +install: + - wget "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" + - unzip "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" -d protoc + - export PATH="$(pwd)/protoc/bin:$PATH" - pipenv install +before_script: + - test "$EMULATOR" = "1" || wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/$TOOLCHAIN_SHORTVER/$TOOLCHAIN_LONGVER-linux.tar.bz2 + - test "$EMULATOR" = "1" || tar xfj $TOOLCHAIN_LONGVER-linux.tar.bz2 + - test "$EMULATOR" = "1" || export PATH=$PWD/$TOOLCHAIN_LONGVER/bin:$PATH + script: - pipenv run script/cibuild - pipenv run make -C bootloader diff --git a/Dockerfile b/Dockerfile index 585343fa88..720c210761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,32 +2,76 @@ FROM debian:9 +ARG TOOLCHAIN_FLAVOR=linux +ENV TOOLCHAIN_FLAVOR=$TOOLCHAIN_FLAVOR + # install build tools and dependencies ARG EMULATOR=0 ENV EMULATOR=$EMULATOR -RUN apt-get update && \ - apt-get install -y build-essential curl git python3 python3-pip +RUN apt-get update && apt-get install -y \ + build-essential wget git python3-pip + +# install dependencies from toolchain source build + +RUN if [ "$TOOLCHAIN_FLAVOR" = "src" ]; then \ + apt-get install -y autoconf autogen bison dejagnu \ + flex flip gawk git gperf gzip nsis \ + openssh-client p7zip-full perl python-dev \ + libisl-dev tcl tofrodos zip \ + texinfo texlive texlive-extra-utils; \ + fi + +# download toolchain + +ENV TOOLCHAIN_SHORTVER=8-2018q4 +ENV TOOLCHAIN_LONGVER=gcc-arm-none-eabi-8-2018-q4-major +ENV TOOLCHAIN_URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/$TOOLCHAIN_SHORTVER/$TOOLCHAIN_LONGVER-$TOOLCHAIN_FLAVOR.tar.bz2 +ENV TOOLCHAIN_HASH_linux=fb31fbdfe08406ece43eef5df623c0b2deb8b53e405e2c878300f7a1f303ee52 +ENV TOOLCHAIN_HASH_src=bc228325dbbfaf643f2ee5d19e01d8b1873fcb9c31781b5e1355d40a68704ce7 RUN if [ "$EMULATOR" = 1 ]; then \ apt-get install -y libsdl2-dev libsdl2-image-dev; \ - else \ - apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi; \ fi +# extract toolchain + +RUN cd /opt && wget $TOOLCHAIN_URL + +RUN cd /opt && echo "$TOOLCHAIN_HASH_linux $TOOLCHAIN_LONGVER-linux.tar.bz2\n$TOOLCHAIN_HASH_src $TOOLCHAIN_LONGVER-src.tar.bz2" | sha256sum -c --ignore-missing + +RUN cd /opt && tar xfj $TOOLCHAIN_LONGVER-$TOOLCHAIN_FLAVOR.tar.bz2 + +# build toolchain (if required) + +RUN if [ "$TOOLCHAIN_FLAVOR" = "src" ]; then \ + pushd /opt/$TOOLCHAIN_LONGVER ; \ + ./install-sources.sh --skip_steps=mingw32 ; \ + ./build-prerequisites.sh --skip_steps=mingw32 ; \ + ./build-toolchain.sh --skip_steps=mingw32,manual ; \ + popd ; \ + fi + +# download protobuf + ENV PROTOBUF_VERSION=3.4.0 ENV PROTOBUF_HASH=e4b51de1b75813e62d6ecdde582efa798586e09b5beaebfb866ae7c9eaadace4 -RUN curl -LO "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" +RUN wget "https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" RUN echo "${PROTOBUF_HASH} protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" | sha256sum -c +# setup toolchain + +ENV PATH=/opt/$TOOLCHAIN_LONGVER/bin:$PATH + ENV PYTHON=python3 -ENV LC_ALL=C.UTF-8 -ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 LANG=C.UTF-8 # use zipfile module to extract files world-readable RUN $PYTHON -m zipfile -e "protoc-${PROTOBUF_VERSION}-linux-x86_64.zip" /usr/local && chmod 755 /usr/local/bin/protoc ENV WORKON_HOME=/tmp/.venvs +# install python dependencies + RUN $PYTHON -m pip install pipenv From 50e0ddb6f8b9ba790f2aa8b13f4820d2bbf94030 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 24 Jan 2019 14:40:14 +0100 Subject: [PATCH 1055/1154] bootloader: update changelog --- bootloader/ChangeLog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bootloader/ChangeLog b/bootloader/ChangeLog index 0c386257ef..a348378c01 100644 --- a/bootloader/ChangeLog +++ b/bootloader/ChangeLog @@ -1,4 +1,7 @@ -Version 1.6.0 [unreleased] +Version 1.6.1 +* Fix USB issue on some Windows 10 installations + +Version 1.6.0 * Switch from HID to WebUSB Version 1.5.1 From 98ec2f096c76a12511fe628de422c153d8105c16 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 27 Jan 2019 15:06:05 +0100 Subject: [PATCH 1056/1154] bootloader: small changes to ui, replace vendor string --- Makefile | 1 - bootloader/bootloader.c | 18 ++++++------------ bootloader/usb.c | 15 +++++++-------- firmware/fsm_msg_common.h | 2 +- firmware/layout2.c | 8 ++++---- firmware/pinmatrix.c | 2 +- firmware/stellar.c | 2 +- layout.c | 4 ++-- oled.c | 4 ++-- oled.h | 2 +- serialno.c | 36 ------------------------------------ serialno.h | 26 -------------------------- 12 files changed, 25 insertions(+), 95 deletions(-) delete mode 100644 serialno.c delete mode 100644 serialno.h diff --git a/Makefile b/Makefile index d54c4afc96..140c3faf54 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ OBJS += buttons.o OBJS += layout.o OBJS += oled.o OBJS += rng.o -OBJS += serialno.o ifneq ($(EMULATOR),1) OBJS += setup.o diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 780af28b82..b9f840cc94 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -31,7 +31,6 @@ #include "util.h" #include "signatures.h" #include "layout.h" -#include "serialno.h" #include "rng.h" #include "timer.h" @@ -106,18 +105,13 @@ void bootloader_loop(void) oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); if (firmware_present()) { - oledDrawString(52, 0, "TREZOR", FONT_STANDARD); - static char serial[25]; - fill_serialno_fixed(serial); - oledDrawString(52, 20, "Serial No.", FONT_STANDARD); - oledDrawString(52, 40, serial + 12, FONT_STANDARD); // second part of serial - serial[12] = 0; - oledDrawString(52, 30, serial, FONT_STANDARD); // first part of serial - oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "Loader " VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); + oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); + oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); + oledDrawStringCenter(90, 50, VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); } else { - oledDrawString(52, 10, "Welcome!", FONT_STANDARD); - oledDrawString(52, 30, "Please visit", FONT_STANDARD); - oledDrawString(52, 50, "trezor.io/start", FONT_STANDARD); + oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD); + oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD); + oledDrawStringCenter(90, 50, "trezor.io/start", FONT_STANDARD); } oledRefresh(); diff --git a/bootloader/usb.c b/bootloader/usb.c index 2930c48c25..700fc81f1f 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -27,7 +27,6 @@ #include "oled.h" #include "rng.h" #include "usb.h" -#include "serialno.h" #include "layout.h" #include "util.h" #include "signatures.h" @@ -174,7 +173,7 @@ static void send_msg_failure(usbd_device *dev) static void send_msg_features(usbd_device *dev) { // response: Features message (id 17), payload len 30 - // - vendor = "bitcointrezor.com" + // - vendor = "trezor.io" // - major_version = VERSION_MAJOR // - minor_version = VERSION_MINOR // - patch_version = VERSION_PATCH @@ -188,9 +187,9 @@ static void send_msg_features(usbd_device *dev) // msg_id "\x00\x11" // msg_size - "\x00\x00\x00\x1e" + "\x00\x00\x00\x16" // data - "\x0a" "\x11" "bitcointrezor.com" + "\x0a" "\x09" "trezor.io" "\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR "\x20" VERSION_PATCH_CHAR @@ -198,7 +197,7 @@ static void send_msg_features(usbd_device *dev) "\x90\x01" "\x00" "\xaa" "\x01" "1" // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } else { while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, @@ -207,9 +206,9 @@ static void send_msg_features(usbd_device *dev) // msg_id "\x00\x11" // msg_size - "\x00\x00\x00\x1e" + "\x00\x00\x00\x16" // data - "\x0a\x11" "bitcointrezor.com" + "\x0a" "\x09" "trezor.io" "\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR "\x20" VERSION_PATCH_CHAR @@ -217,7 +216,7 @@ static void send_msg_features(usbd_device *dev) "\x90\x01" "\x01" "\xaa" "\x01" "1" // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" , 64) != 64) {} } } diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 218102f7b1..524d12b114 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -41,7 +41,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) { (void)msg; RESP_INIT(Features); - resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); + resp->has_vendor = true; strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor)); resp->has_major_version = true; resp->major_version = VERSION_MAJOR; resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; diff --git a/firmware/layout2.c b/firmware/layout2.c index 14f334f572..15bc7ef41c 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -246,22 +246,22 @@ void layoutHome(void) } else { if (label && strlen(label) > 0) { oledDrawBitmap(44, 4, &bmp_logo48); - oledDrawStringCenter(OLED_HEIGHT - 8, label, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, FONT_STANDARD); } else { oledDrawBitmap(40, 0, &bmp_logo64); } } if (storage_noBackup()) { oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "SEEDLESS", FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); } else if (storage_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); } else if (storage_needsBackup()) { oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); } oledRefresh(); diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index e2234292a8..94f8a06cc6 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -39,7 +39,7 @@ void pinmatrix_draw(const char *text) // use (2 - j) instead of j to achieve 789456123 layout int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; if (text) { - oledDrawStringCenter(0, text, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD); } oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); } diff --git a/firmware/stellar.c b/firmware/stellar.c index dc6b88f903..662cd5922b 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -1870,7 +1870,7 @@ void stellar_layoutSigningDialog(const char *line1, const char *line2, const cha // Warnings (drawn centered between the buttons if (warning) { - oledDrawStringCenter(OLED_HEIGHT - 8, warning, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, warning, FONT_STANDARD); } // Next / sign button diff --git a/layout.c b/layout.c index cb8302b904..6b3e5538a5 100644 --- a/layout.c +++ b/layout.c @@ -49,7 +49,7 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); if (desc) { - oledDrawStringCenter(OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); if (btnYes || btnNo) { oledHLine(OLED_HEIGHT - 21); } @@ -110,7 +110,7 @@ void layoutProgress(const char *desc, int permil) // text oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); if (desc) { - oledDrawStringCenter(OLED_HEIGHT - 16, desc, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 16, desc, FONT_STANDARD); } oledRefresh(); } diff --git a/oled.c b/oled.c index 77f30d526e..00a03a27e6 100644 --- a/oled.c +++ b/oled.c @@ -301,9 +301,9 @@ void oledDrawString(int x, int y, const char* text, int font) } } -void oledDrawStringCenter(int y, const char* text, int font) +void oledDrawStringCenter(int x, int y, const char* text, int font) { - int x = ( OLED_WIDTH - oledStringWidth(text, font) ) / 2; + x = x - oledStringWidth(text, font) / 2; oledDrawString(x, y, text, font); } diff --git a/oled.h b/oled.h index fcd7cc7d1b..afc09829bf 100644 --- a/oled.h +++ b/oled.h @@ -46,7 +46,7 @@ void oledDrawChar(int x, int y, char c, int zoom); int oledStringWidth(const char *text, int font); void oledDrawString(int x, int y, const char* text, int font); -void oledDrawStringCenter(int y, const char* text, int font); +void oledDrawStringCenter(int x, int y, const char* text, int font); void oledDrawStringRight(int x, int y, const char* text, int font); void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledInvert(int x1, int y1, int x2, int y2); diff --git a/serialno.c b/serialno.c deleted file mode 100644 index c621f95471..0000000000 --- a/serialno.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include -#include - -#include - -#include "serialno.h" -#include "util.h" -#include "sha2.h" - -void fill_serialno_fixed(char *s) -{ - uint32_t uuid[8]; - desig_get_unique_id(uuid); - sha256_Raw((const uint8_t *)uuid, 12, (uint8_t *)uuid); - sha256_Raw((const uint8_t *)uuid, 32, (uint8_t *)uuid); - data2hex(uuid, 12, s); -} diff --git a/serialno.h b/serialno.h deleted file mode 100644 index 4e157f9ce5..0000000000 --- a/serialno.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#ifndef __SERIALNO_H__ -#define __SERIALNO_H__ - -// buffer has to be (at least) 25 chars long -void fill_serialno_fixed(char *s); - -#endif From 299e14ad7973624343013db95fed464484f6a84c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 27 Jan 2019 14:28:21 +0100 Subject: [PATCH 1057/1154] make: add new debugging targets --- Makefile.include | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile.include b/Makefile.include index 8e1cff25cd..1f175f0e28 100644 --- a/Makefile.include +++ b/Makefile.include @@ -28,6 +28,7 @@ OBJDUMP := $(PREFIX)objdump AR := $(PREFIX)ar AS := $(PREFIX)as OPENOCD := openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f target/stm32f2x.cfg +GDB := $(PREFIX)gdb --nx -ex 'set remotetimeout unlimited' -ex 'set confirm off' -ex 'target remote 127.0.0.1:3333' -ex 'monitor reset halt' OPTFLAGS ?= -O3 DBGFLAGS ?= -g -DNDEBUG @@ -144,6 +145,15 @@ endif all: $(NAME).bin +openocd: + $(OPENOCD) + +gdb_bootloader: bootloader/bootloader.elf + $(GDB) $< + +gdb_firmware: firmware/trezor.elf + $(GDB) $< + flash: $(NAME).bin $(OPENOCD) -c "init; reset halt; flash write_image erase $(NAME).bin 0x8000000; exit" From 5d32308dfbe14a2c88655a4570ebb92071ee7154 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 29 Jan 2019 02:10:53 +0100 Subject: [PATCH 1058/1154] nix: use python3, not python36 --- shell.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell.nix b/shell.nix index e09b2131d9..186561ab19 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,7 @@ with import {}; let - myPython = python36.withPackages(p: [p.trezor p.Mako p.munch]); + myPython = python3.withPackages(p: [p.trezor p.Mako p.munch]); in stdenv.mkDerivation { name = "trezor-mcu-dev"; From 77a6718f7656c8aa19ebe4855cd063cfe3ea8d98 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 Jan 2019 17:35:16 +0100 Subject: [PATCH 1059/1154] ethereum: address in messages is now string --- firmware/ethereum.c | 86 ++++++++++++++++++----- firmware/ethereum.h | 1 + firmware/fsm_msg_ethereum.h | 43 +++++++----- firmware/protob/messages-ethereum.options | 8 +-- vendor/trezor-common | 2 +- 5 files changed, 100 insertions(+), 40 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 29168d5740..500102c398 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -421,19 +421,21 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, * - data (0 ..) */ -static bool ethereum_signing_check(EthereumSignTx *msg) +static bool ethereum_signing_check(const EthereumSignTx *msg) { if (!msg->has_gas_price || !msg->has_gas_limit) { return false; } - if (msg->to.size != 20 && msg->to.size != 0) { + size_t tolen = msg->has_to ? strlen(msg->to) : 0; + + if (tolen != 42 && tolen != 40 && tolen != 0) { /* Address has wrong length */ return false; } // sending transaction to address 0 (contract creation) without a data field - if (msg->to.size == 0 && (!msg->has_data_length || msg->data_length == 0)) { + if (tolen == 0 && (!msg->has_data_length || msg->data_length == 0)) { return false; } @@ -456,8 +458,15 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->value.size = 0; if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0; - if (!msg->has_to) - msg->to.size = 0; + bool toset; + uint8_t pubkeyhash[20]; + if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) { + toset = true; + } else { + msg->to[0] = 0; + toset = false; + memzero(pubkeyhash, sizeof(pubkeyhash)); + } if (!msg->has_nonce) msg->nonce.size = 0; @@ -520,15 +529,15 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) const TokenType *token = NULL; // detect ERC-20 token - if (msg->to.size == 20 && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 + if (toset && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - token = tokenByChainAddress(chain_id, msg->to.bytes); + token = tokenByChainAddress(chain_id, pubkeyhash); } if (token != NULL) { layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); } else { - layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL); + layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size, NULL); } if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { @@ -563,7 +572,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); + rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); if (tx_type) { @@ -586,7 +595,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - hash_rlp_field(msg->to.bytes, msg->to.size); + hash_rlp_field(pubkeyhash, toset ? 20 : 0); hash_rlp_field(msg->value.bytes, msg->value.size); hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); @@ -663,13 +672,18 @@ static void ethereum_message_hash(const uint8_t *message, size_t message_len, ui void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) { - uint8_t hash[32]; - - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { + uint8_t pubkeyhash[20]; + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) { return; } + resp->has_address = true; - resp->address.size = 20; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, false, 0); + // ethereum_address_checksum adds trailing zero + + uint8_t hash[32]; ethereum_message_hash(msg->message.bytes, msg->message.size, hash); uint8_t v; @@ -686,8 +700,14 @@ void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, E int ethereum_message_verify(const EthereumVerifyMessage *msg) { - if (msg->signature.size != 65 || msg->address.size != 20) { - fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); + if (msg->signature.size != 65) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature")); + return 1; + } + + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed address")); return 1; } @@ -714,8 +734,40 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg) keccak_Final(&ctx, hash); /* result are the least significant 160 bits */ - if (memcmp(msg->address.bytes, hash + 12, 20) != 0) { + if (memcmp(pubkeyhash, hash + 12, 20) != 0) { return 2; } return 0; } + +bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) +{ + memzero(pubkeyhash, 20); + size_t len = strlen(address); + if (len == 40) { + // do nothing + } else + if (len == 42) { + // check for "0x" prefix and strip it when required + if (address[0] != '0') return false; + if (address[1] != 'x' && address[1] != 'X') return false; + address += 2; + len -= 2; + } else { + return false; + } + for (size_t i = 0; i < len; i++) { + if (address[i] >= '0' && address[i] <= '9') { + pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4); + } else + if (address[i] >= 'a' && address[i] <= 'f') { + pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4); + } else + if (address[i] >= 'A' && address[i] <= 'F') { + pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4); + } else { + return false; + } + } + return true; +} diff --git a/firmware/ethereum.h b/firmware/ethereum.h index f36b4e34ff..0bcc006273 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -31,5 +31,6 @@ void ethereum_signing_txack(const EthereumTxAck *msg); void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); int ethereum_message_verify(const EthereumVerifyMessage *msg); +bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]); #endif diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 1ae7efa800..bc32f46f98 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -89,28 +89,31 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; - resp->address.size = 20; + uint8_t pubkeyhash[20]; - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return; + uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; + bool rskip60 = false; + uint32_t chain_id = 0; + // constants from trezor-common/defs/ethereum/networks.json + switch (slip44) { + case 137: rskip60 = true; chain_id = 30; break; + case 37310: rskip60 = true; chain_id = 31; break; + } + + resp->has_address = true; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id); + // ethereum_address_checksum adds trailing zero + if (msg->has_show_display && msg->show_display) { char desc[16]; strlcpy(desc, "Address:", sizeof(desc)); - uint32_t slip44 = msg->address_n[1] & 0x7fffffff; - bool rskip60 = false; - uint32_t chain_id = 0; - // constants from trezor-common/defs/ethereum/networks.json - switch (slip44) { - case 137: rskip60 = true; chain_id = 30; break; - case 37310: rskip60 = true; chain_id = 31; break; - } - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, chain_id); - - if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { + if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { return; } } @@ -151,9 +154,13 @@ void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) return; } - char address[43] = { '0', 'x' }; - ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); - layoutVerifyAddress(NULL, address); + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); + return; + } + + layoutVerifyAddress(NULL, msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/firmware/protob/messages-ethereum.options b/firmware/protob/messages-ethereum.options index 07b148c97b..12f658f068 100644 --- a/firmware/protob/messages-ethereum.options +++ b/firmware/protob/messages-ethereum.options @@ -2,7 +2,7 @@ EthereumSignTx.address_n max_count:8 EthereumSignTx.nonce max_size:32 EthereumSignTx.gas_price max_size:32 EthereumSignTx.gas_limit max_size:32 -EthereumSignTx.to max_size:20 +EthereumSignTx.to max_size:43 EthereumSignTx.value max_size:32 EthereumSignTx.data_initial_chunk max_size:1024 @@ -14,15 +14,15 @@ EthereumTxAck.data_chunk max_size:1024 EthereumSignMessage.address_n max_count:8 EthereumSignMessage.message max_size:1024 -EthereumVerifyMessage.address max_size:20 +EthereumVerifyMessage.address max_size:43 EthereumVerifyMessage.signature max_size:65 EthereumVerifyMessage.message max_size:1024 -EthereumMessageSignature.address max_size:20 +EthereumMessageSignature.address max_size:43 EthereumMessageSignature.signature max_size:65 EthereumGetAddress.address_n max_count:8 EthereumGetPublicKey.address_n max_count:8 -EthereumAddress.address max_size:20 +EthereumAddress.address max_size:43 EthereumPublicKey.xpub max_size:113 diff --git a/vendor/trezor-common b/vendor/trezor-common index 78e232cf30..495b35e212 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 78e232cf30d5d30ec1c7f06a740bbc990cc648e9 +Subproject commit 495b35e212f48ea2ac9e356febd5a49c3ee5254b From 7e3d0a0a77eabd1fab983edacf3b7cffeaeada41 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Jan 2019 19:20:29 +0100 Subject: [PATCH 1060/1154] signing: use the new hasher_InitParam API --- firmware/signing.c | 42 ++++++++++++++++++++++-------------------- vendor/trezor-crypto | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/firmware/signing.c b/firmware/signing.c index 37895258c2..74c16d6e05 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -527,9 +527,9 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) // segwit hashes for hashPrevouts and hashSequence if (overwintered) { - hasher_Init(&hasher_prevouts, HASHER_OVERWINTER_PREVOUTS); - hasher_Init(&hasher_sequence, HASHER_OVERWINTER_SEQUENCE); - hasher_Init(&hasher_outputs, HASHER_OVERWINTER_OUTPUTS); + hasher_InitParam(&hasher_prevouts, HASHER_BLAKE2B_PERSONAL, "ZcashPrevoutHash", 16); + hasher_InitParam(&hasher_sequence, HASHER_BLAKE2B_PERSONAL, "ZcashSequencHash", 16); + hasher_InitParam(&hasher_outputs, HASHER_BLAKE2B_PERSONAL, "ZcashOutputsHash", 16); hasher_Init(&hasher_check, coin->curve->hasher_sign); } else { hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); @@ -589,7 +589,7 @@ static bool signing_check_input(const TxInputType *txinput) { } // hash prevout and script type to check it later (relevant for fee computation) tx_prevout_hash(&hasher_check, txinput); - hasher_Update(&hasher_check, (const uint8_t *) &txinput->script_type, sizeof(&txinput->script_type)); + hasher_Update(&hasher_check, (const uint8_t *)&txinput->script_type, sizeof(&txinput->script_type)); return true; } @@ -758,18 +758,19 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence tx_prevout_hash(&hasher_preimage, txinput); // outpoint tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*) &txinput->amount, 8); // amount + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // amount tx_sequence_hash(&hasher_preimage, txinput); // nSequence hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // nHashType + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // nHashType hasher_Final(&hasher_preimage, hash); } static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); Hasher hasher_preimage; - hasher_Init(&hasher_preimage, HASHER_OVERWINTER_PREIMAGE); + // BRANCH_ID = 0x5ba81b19 / Overwinter + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, "ZcashSigHash\x19\x1b\xa8\x5b", 16); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId @@ -778,13 +779,13 @@ static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs // 6. hashJoinSplits hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 7. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 8. expiryHeight - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 9. nHashType + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // 7. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, 4); // 8. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // 9. nHashType tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 10b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 10c. value + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // 10c. value tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence hasher_Final(&hasher_preimage, hash); @@ -793,7 +794,8 @@ static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); Hasher hasher_preimage; - hasher_Init(&hasher_preimage, HASHER_SAPLING_PREIMAGE); + // BRANCH_ID = 0x76b809bb / Sapling + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, "ZcashSigHash\xbb\x09\xb8\x76", 16); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId @@ -806,14 +808,14 @@ static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); // 8. hashShieldedOutputs hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t*)&lock_time, 4); // 9. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t*)&expiry, 4); // 10. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // 9. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, 4); // 10. expiryHeight hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); // 11. valueBalance - hasher_Update(&hasher_preimage, (const uint8_t*)&hash_type, 4); // 12. nHashType + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // 12. nHashType tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 13b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t*)&txinput->amount, 8); // 13c. value + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // 13c. value tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence hasher_Final(&hasher_preimage, hash); @@ -823,13 +825,13 @@ static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); Hasher hasher_preimage; hasher_Init(&hasher_preimage, coin->curve->hasher_sign); - hasher_Update(&hasher_preimage, (const uint8_t*) &hash_type, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); hasher_Update(&hasher_preimage, hash_prefix, 32); hasher_Update(&hasher_preimage, hash_witness, 32); hasher_Final(&hasher_preimage, hash); } -static bool signing_sign_hash(TxInputType *txinput, const uint8_t* private_key, const uint8_t *public_key, const uint8_t *hash) { +static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key, const uint8_t *public_key, const uint8_t *hash) { resp.serialized.has_signature_index = true; resp.serialized.signature_index = idx1; resp.serialized.has_signature = true; @@ -1167,7 +1169,7 @@ void signing_txack(TransactionType *tx) } // check prevouts and script type tx_prevout_hash(&hasher_check, tx->inputs); - hasher_Update(&hasher_check, (const uint8_t *) &tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); + hasher_Update(&hasher_check, (const uint8_t *)&tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); if (idx2 == idx1) { if (!compile_input_script_sig(&tx->inputs[0])) { fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index d1c52401e4..21391dc5be 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit d1c52401e4c76c74a10455682ace0655b7aa644c +Subproject commit 21391dc5be9917bc32a518cf98376f79103727af From 8a4e8013f10faabc7792c93303f969a468222eb8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Jan 2019 21:17:00 +0100 Subject: [PATCH 1061/1154] firmware: process tx.branch_id (zcash) --- firmware/protob/Makefile | 2 +- firmware/signing.c | 14 ++++++++++---- vendor/trezor-common | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 0cf8453c18..dbdf0485db 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron > $@ + $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron -e MessageType_Eos > $@ clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h diff --git a/firmware/signing.c b/firmware/signing.c index 74c16d6e05..428fbd4d96 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -68,6 +68,7 @@ static uint32_t lock_time = 0; static uint32_t expiry = 0; static bool overwintered = false; static uint32_t version_group_id = 0; +static uint32_t branch_id = 0; static uint32_t next_nonsegwit_input; static uint32_t progress, progress_step, progress_meta_step; static bool multisig_fp_set, multisig_fp_mismatch; @@ -485,6 +486,7 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) expiry = msg->expiry; overwintered = msg->has_overwintered && msg->overwintered; version_group_id = msg->version_group_id; + branch_id = msg->branch_id; uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); if (coin->decred) { @@ -768,9 +770,11 @@ static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); Hasher hasher_preimage; - // BRANCH_ID = 0x5ba81b19 / Overwinter - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, "ZcashSigHash\x19\x1b\xa8\x5b", 16); + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId @@ -793,9 +797,11 @@ static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); Hasher hasher_preimage; - // BRANCH_ID = 0x76b809bb / Sapling - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, "ZcashSigHash\xbb\x09\xb8\x76", 16); + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId diff --git a/vendor/trezor-common b/vendor/trezor-common index 495b35e212..4b41d2e638 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 495b35e212f48ea2ac9e356febd5a49c3ee5254b +Subproject commit 4b41d2e63841517bf701618434c018acf4f1bca2 From a7c32248bda3b9e03c74bcaf93e340f5794557f8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 1 Feb 2019 15:17:06 +0100 Subject: [PATCH 1062/1154] reset: commit to storage unconditionally at the end of backup procedure --- firmware/reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index afdadab1c9..dd7fe102bf 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -171,11 +171,11 @@ void reset_backup(bool separated) } storage_setUnfinishedBackup(false); + storage_update(); if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { - storage_update(); fsm_sendSuccess(_("Device successfully initialized")); } layoutHome(); From f9ba64ea94bba28bb041a9e1aec5c27dd3ec64e5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Feb 2019 13:53:05 +0100 Subject: [PATCH 1063/1154] messages: introduce messages_map_limits --- firmware/messages.c | 2 + firmware/messages.h | 6 +-- firmware/protob/.gitignore | 1 + firmware/protob/Makefile | 8 ++-- firmware/protob/messages-bitcoin.options | 2 + firmware/protob/messages_map.py | 55 ++++++++++++++++++------ vendor/trezor-common | 2 +- 7 files changed, 56 insertions(+), 20 deletions(-) diff --git a/firmware/messages.c b/firmware/messages.c index 28ac098776..8e315413f7 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -45,6 +45,8 @@ static const struct MessagesMap_t MessagesMap[] = { {0, 0, 0, 0, 0} }; +#include "messages_map_limits.h" + const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) { const struct MessagesMap_t *m = MessagesMap; diff --git a/firmware/messages.h b/firmware/messages.h index 26c843ac3e..1806a7daee 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -24,9 +24,9 @@ #include #include "trezor.h" -#define MSG_IN_SIZE (11 * 1024) +#define MSG_IN_SIZE (15 * 1024) -#define MSG_OUT_SIZE (11 * 1024) +#define MSG_OUT_SIZE (3 * 1024) #define msg_read(buf, len) msg_read_common('n', (buf), (len)) #define msg_write(id, ptr) msg_write_common('n', (id), (ptr)) @@ -34,7 +34,7 @@ const uint8_t *msg_out_data(void); #if DEBUG_LINK -#define MSG_DEBUG_OUT_SIZE (4 * 1024) +#define MSG_DEBUG_OUT_SIZE (2 * 1024) #define msg_debug_read(buf, len) msg_read_common('d', (buf), (len)) #define msg_debug_write(id, ptr) msg_write_common('d', (id), (ptr)) diff --git a/firmware/protob/.gitignore b/firmware/protob/.gitignore index 8ea827fb73..9d1fced364 100644 --- a/firmware/protob/.gitignore +++ b/firmware/protob/.gitignore @@ -4,4 +4,5 @@ *.pb.h *.pyc messages_map.h +messages_map_limits.h __pycache__/ diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index dbdf0485db..1838454bc4 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -2,7 +2,7 @@ ifneq ($(V),1) Q := @ endif -all: messages_map.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages-lisk.pb.c messages_nem_pb2.py +all: messages_map.h messages_map_limits.h messages-bitcoin.pb.c messages-common.pb.c messages-crypto.pb.c messages-debug.pb.c messages-ethereum.pb.c messages-management.pb.c messages-nem.pb.c messages.pb.c messages-stellar.pb.c messages-lisk.pb.c messages_nem_pb2.py PYTHON ?= python @@ -25,8 +25,8 @@ messages_%_pb2.py: messages-%.proto @printf " PROTOC $@\n" $(Q)protoc -I/usr/include -I. $< --python_out=. -messages_map.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< | grep -v -e MessageType_Cardano -e MessageType_Tezos -e MessageType_Ripple -e MessageType_Monero -e MessageType_DebugMonero -e MessageType_Ontology -e MessageType_Tron -e MessageType_Eos > $@ +messages_map.h messages_map_limits.h: messages_map.py messages_pb2.py + $(Q)$(PYTHON) $< Cardano Tezos Ripple Monero DebugMonero Ontology Tron Eos clean: - rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h + rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h messages_map_limits.h diff --git a/firmware/protob/messages-bitcoin.options b/firmware/protob/messages-bitcoin.options index 68a1817616..f04d01f93e 100644 --- a/firmware/protob/messages-bitcoin.options +++ b/firmware/protob/messages-bitcoin.options @@ -47,5 +47,7 @@ TxRequestSerializedType.serialized_tx max_size:2048 MultisigRedeemScriptType.pubkeys max_count:15 MultisigRedeemScriptType.signatures max_count:15 max_size:73 +MultisigRedeemScriptType.nodes max_count:15 +MultisigRedeemScriptType.address_n max_count:8 HDNodePathType.address_n max_count:8 diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index f5ab67d274..ece7b3446e 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -1,12 +1,17 @@ #!/usr/bin/env python +import sys + from collections import defaultdict from messages_pb2 import MessageType from messages_pb2 import wire_in, wire_out from messages_pb2 import wire_debug_in, wire_debug_out from messages_pb2 import wire_bootloader, wire_no_fsm +fh = open("messages_map.h", "wt") +fl = open("messages_map_limits.h", "wt") + # len("MessageType_MessageType_") - len("_fields") == 17 -TEMPLATE = "\t{{ {type} {dir} {msg_id:46} {fields:29} {process_func} }}," +TEMPLATE = "\t{{ {type} {dir} {msg_id:46} {fields:29} {process_func} }},\n" LABELS = { wire_in: "in messages", @@ -16,11 +21,15 @@ LABELS = { } -def handle_message(message, extension): +def handle_message(fh, fl, skipped, message, extension): name = message.name short_name = name.split("MessageType_", 1).pop() assert(short_name != name) + for s in skipped: + if short_name.startswith(s): + return + interface = "d" if extension in (wire_debug_in, wire_debug_out) else "n" direction = "i" if extension in (wire_in, wire_debug_in) else "o" @@ -29,27 +38,44 @@ def handle_message(message, extension): no_fsm = options.Extensions[wire_no_fsm] if getattr(options, 'deprecated', None): - return '\t// Message %s is deprecated' % short_name + fh.write('\t// Message %s is deprecated\n' % short_name) + return if bootloader: - return '\t// Message %s is used in bootloader mode only' % short_name + fh.write('\t// Message %s is used in bootloader mode only\n' % short_name) + return if no_fsm: - return '\t// Message %s is not used in FSM' % short_name + fh.write('\t// Message %s is not used in FSM\n' % short_name) + return if direction == "i": process_func = "(void (*)(void *)) fsm_msg%s" % short_name else: process_func = "0" - return TEMPLATE.format( + fh.write(TEMPLATE.format( type="'%c'," % interface, dir="'%c'," % direction, msg_id="MessageType_%s," % name, fields="%s_fields," % short_name, process_func=process_func, - ) + )) + + bufsize = None + t = interface + direction + if t == "ni": + bufsize = "MSG_IN_SIZE" + elif t == "no": + bufsize = "MSG_OUT_SIZE" + elif t == "do": + bufsize = "MSG_DEBUG_OUT_SIZE" + if bufsize: + fl.write("_Static_assert(%s >= sizeof(%s), \"msg buffer too small\");\n" % (bufsize, short_name)) -print("\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!") +skipped = sys.argv[1:] + +fh.write("\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n") +fl.write("// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n\n") messages = defaultdict(list) @@ -62,12 +88,17 @@ for message in MessageType.DESCRIPTOR.values: for extension in (wire_in, wire_out, wire_debug_in, wire_debug_out): if extension == wire_debug_in: - print("\n#if DEBUG_LINK") + fh.write("\n#if DEBUG_LINK\n") + fl.write("\n#if DEBUG_LINK\n") - print("\n\t// {label}\n".format(label=LABELS[extension])) + fh.write("\n\t// {label}\n\n".format(label=LABELS[extension])) for message in messages[extension]: - print(handle_message(message, extension)) + handle_message(fh, fl, skipped, message, extension) if extension == wire_debug_out: - print("\n#endif") + fh.write("\n#endif\n") + fl.write("#endif\n") + +fh.close() +fl.close() diff --git a/vendor/trezor-common b/vendor/trezor-common index 4b41d2e638..0735c7d6f5 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 4b41d2e63841517bf701618434c018acf4f1bca2 +Subproject commit 0735c7d6f524b4c5108d201c789612aad7ce7920 From 19c7c8bc3b76a9489b9a5cce5d9b69d60b1f20cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Feb 2019 01:26:26 +0100 Subject: [PATCH 1064/1154] signing: implemented simplified API for MultisigRedeemScriptType If address_n is the same for all nodes in the multisig, provide it just once and supply nodes directly (not in the HDNodePathType structure) --- firmware/crypto.c | 87 ++++++++++++++++++++++++++++++------------ firmware/crypto.h | 4 +- firmware/transaction.c | 16 ++++---- 3 files changed, 73 insertions(+), 34 deletions(-) diff --git a/firmware/crypto.c b/firmware/crypto.c index 68019cb5aa..f71b093321 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -334,28 +334,55 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le } */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath) +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index) { - if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0; + const HDNodeType *node_ptr; + const uint32_t *address_n; + uint32_t address_n_count; + if (multisig->nodes_count) { // use multisig->nodes + if (index >= multisig->nodes_count) { + return 0; + } + node_ptr = &(multisig->nodes[index]); + address_n = multisig->address_n; + address_n_count = multisig->address_n_count; + } else + if (multisig->pubkeys_count) { // use multisig->pubkeys + if (index >= multisig->pubkeys_count) { + return 0; + } + node_ptr = &(multisig->pubkeys[index].node); + address_n = multisig->pubkeys[index].address_n; + address_n_count = multisig->pubkeys[index].address_n_count; + } else { + return 0; + } + if (node_ptr->chain_code.size != 32) return 0; + if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; static HDNode node; - if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, coin->curve_name, &node) == 0) { + if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, node_ptr->chain_code.bytes, node_ptr->public_key.bytes, coin->curve_name, &node)) { return 0; } layoutProgressUpdate(true); - for (uint32_t i = 0; i < hdnodepath->address_n_count; i++) { - if (hdnode_public_ckd(&node, hdnodepath->address_n[i]) == 0) { + for (uint32_t i = 0; i < address_n_count; i++) { + if (!hdnode_public_ckd(&node, address_n[i])) { return 0; } layoutProgressUpdate(true); } - return node.public_key; + return &node; +} + +uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) +{ + return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count; } int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) { - for (size_t i = 0; i < multisig->pubkeys_count; i++) { - const uint8_t *node_pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (node_pubkey && memcmp(node_pubkey, pubkey, 33) == 0) { + for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { return i; } } @@ -364,25 +391,35 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) { - static const HDNodePathType *ptr[15], *swap; - const uint32_t n = multisig->pubkeys_count; + static const HDNodeType *pubnodes[15], *swap; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (n < 1 || n > 15) { return 0; } - // check sanity - if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) return 0; + if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) { + return 0; + } for (uint32_t i = 0; i < n; i++) { - ptr[i] = &(multisig->pubkeys[i]); - if (!ptr[i]->node.has_public_key || ptr[i]->node.public_key.size != 33) return 0; - if (ptr[i]->node.chain_code.size != 32) return 0; + if (multisig->nodes_count) { // use multisig->nodes + pubnodes[i] = &(multisig->nodes[i]); + } else + if (multisig->pubkeys_count) { // use multisig->pubkeys + pubnodes[i] = &(multisig->pubkeys[i].node); + } else { + return 0; + } + } + for (uint32_t i = 0; i < n; i++) { + if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) return 0; + if (pubnodes[i]->chain_code.size != 32) return 0; } // minsort according to pubkey for (uint32_t i = 0; i < n - 1; i++) { for (uint32_t j = n - 1; j > i; j--) { - if (memcmp(ptr[i]->node.public_key.bytes, ptr[j]->node.public_key.bytes, 33) > 0) { - swap = ptr[i]; - ptr[i] = ptr[j]; - ptr[j] = swap; + if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, 33) > 0) { + swap = pubnodes[i]; + pubnodes[i] = pubnodes[j]; + pubnodes[j] = swap; } } } @@ -391,11 +428,11 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); for (uint32_t i = 0; i < n; i++) { - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.depth), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.fingerprint), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(ptr[i]->node.child_num), sizeof(uint32_t)); - sha256_Update(&ctx, ptr[i]->node.chain_code.bytes, 32); - sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t)); + sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); + sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); } sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); sha256_Final(&ctx, hash); diff --git a/firmware/crypto.h b/firmware/crypto.h index feb1c4c370..f8d77c9205 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -52,7 +52,9 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); */ -uint8_t *cryptoHDNodePathToPubkey(const CoinInfo *coin, const HDNodePathType *hdnodepath); +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index); + +uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig); int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); diff --git a/firmware/transaction.c b/firmware/transaction.c index f4a0845c6b..fbfd5c2f72 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -340,7 +340,7 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; uint32_t r = 0; @@ -348,9 +348,9 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip out[r] = 0x50 + m; r++; for (uint32_t i = 0; i < n; i++) { out[r] = 33; r++; // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - memcpy(out + r, pubkey, 33); r += 33; + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + memcpy(out + r, pubnode->public_key, 33); r += 33; } out[r] = 0x50 + n; r++; out[r] = 0xAE; r++; // OP_CHECKMULTISIG @@ -364,7 +364,7 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem { if (!multisig->has_m) return 0; const uint32_t m = multisig->m; - const uint32_t n = multisig->pubkeys_count; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); if (m < 1 || m > 15) return 0; if (n < 1 || n > 15) return 0; @@ -375,9 +375,9 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); for (uint32_t i = 0; i < n; i++) { d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 - const uint8_t *pubkey = cryptoHDNodePathToPubkey(coin, &(multisig->pubkeys[i])); - if (!pubkey) return 0; - hasher_Update(&hasher, pubkey, 33); + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + hasher_Update(&hasher, pubnode->public_key, 33); } d[0] = 0x50 + n; d[1] = 0xAE; From 11311da48a453e451e4bf6b79c835d598bf0f2ad Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 4 Feb 2019 14:25:13 +0100 Subject: [PATCH 1065/1154] fsm: input messages are no longer confidential --- firmware/fsm.h | 6 +++--- firmware/fsm_msg_crypto.h | 11 ++++++++--- firmware/messages.c | 6 +++--- firmware/protob/messages_map.py | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/firmware/fsm.h b/firmware/fsm.h index 0b07d1e1f6..4a8e53b38f 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -73,7 +73,7 @@ void fsm_msgSignMessage(const SignMessage *msg); void fsm_msgVerifyMessage(const VerifyMessage *msg); // crypto -void fsm_msgCipherKeyValue(CipherKeyValue *msg); // not const because we mutate msg->iv +void fsm_msgCipherKeyValue(const CipherKeyValue *msg); void fsm_msgSignIdentity(const SignIdentity *msg); void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg); void fsm_msgCosiCommit(const CosiCommit *msg); @@ -92,7 +92,7 @@ void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg); // ethereum void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg); void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg); -void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction +void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction during validation void fsm_msgEthereumTxAck(const EthereumTxAck *msg); void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg); void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg); @@ -102,7 +102,7 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg); void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg); void fsm_msgLiskSignMessage(const LiskSignMessage *msg); void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg); -void fsm_msgLiskSignTx(LiskSignTx *msg); // // not const because we mutate transaction +void fsm_msgLiskSignTx(LiskSignTx *msg); // not const because we mutate transaction during validation // nem void fsm_msgNEMGetAddress(NEMGetAddress *msg); // not const because we mutate msg->network diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index 006cbc09fa..b6cc5329ee 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -17,7 +17,7 @@ * along with this library. If not, see . */ -void fsm_msgCipherKeyValue(CipherKeyValue *msg) +void fsm_msgCipherKeyValue(const CipherKeyValue *msg) { CHECK_INITIALIZED @@ -49,15 +49,20 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg) hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); + if (msg->iv.size == 16) { + // override iv if provided + memcpy(data + 32, msg->iv.bytes, 16); + } + RESP_INIT(CipheredKeyValue); if (encrypt) { aes_encrypt_ctx ctx; aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); } else { aes_decrypt_ctx ctx; aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); } resp->has_value = true; resp->value.size = msg->value.size; diff --git a/firmware/messages.c b/firmware/messages.c index 8e315413f7..d944ccbe45 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -36,7 +36,7 @@ struct MessagesMap_t { char dir; // i = in, o = out uint16_t msg_id; const pb_field_t *fields; - void (*process_func)(void *ptr); + void (*process_func)(const void *ptr); }; static const struct MessagesMap_t MessagesMap[] = { @@ -222,7 +222,7 @@ enum { void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) { - static CONFIDENTIAL uint8_t msg_data[MSG_IN_SIZE]; + static uint8_t msg_data[MSG_IN_SIZE]; memzero(msg_data, sizeof(msg_data)); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); bool status = pb_decode(&stream, fields, msg_data); @@ -236,7 +236,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t * void msg_read_common(char type, const uint8_t *buf, uint32_t len) { static char read_state = READSTATE_IDLE; - static CONFIDENTIAL uint8_t msg_in[MSG_IN_SIZE]; + static uint8_t msg_in[MSG_IN_SIZE]; static uint16_t msg_id = 0xFFFF; static uint32_t msg_size = 0; static uint32_t msg_pos = 0; diff --git a/firmware/protob/messages_map.py b/firmware/protob/messages_map.py index ece7b3446e..c8c763047f 100755 --- a/firmware/protob/messages_map.py +++ b/firmware/protob/messages_map.py @@ -48,7 +48,7 @@ def handle_message(fh, fl, skipped, message, extension): return if direction == "i": - process_func = "(void (*)(void *)) fsm_msg%s" % short_name + process_func = "(void (*)(const void *))fsm_msg%s" % short_name else: process_func = "0" From 0ab3eee37d97437f230972ca52935ed15c644e22 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 31 Jan 2019 22:18:08 +0100 Subject: [PATCH 1066/1154] bootloader: make code smaller by changing the send_msg logic --- bootloader/usb.c | 98 ++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 57 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 700fc81f1f..16376d8a80 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -139,24 +139,27 @@ static uint8_t meta_backup[FLASH_META_LEN]; static void send_msg_success(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); // response: Success message (id 2), payload len 0 - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, + memcpy(response, // header "?##" // msg_id "\x00\x02" // msg_size - "\x00\x00\x00\x00" - // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} + "\x00\x00\x00\x00", + 9); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} } static void send_msg_failure(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); // response: Failure message (id 3), payload len 2 // - code = 99 (Failure_FirmwareError) - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, + memcpy(response, // header "?##" // msg_id @@ -164,15 +167,16 @@ static void send_msg_failure(usbd_device *dev) // msg_size "\x00\x00\x00\x02" // data - "\x08" "\x63" - // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} + "\x08" "\x63", + 11); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} } static void send_msg_features(usbd_device *dev) { - // response: Features message (id 17), payload len 30 + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Features message (id 17), payload len 25 // - vendor = "trezor.io" // - major_version = VERSION_MAJOR // - minor_version = VERSION_MINOR @@ -180,52 +184,33 @@ static void send_msg_features(usbd_device *dev) // - bootloader_mode = True // - firmware_present = True/False // - model = "1" - if (brand_new_firmware) { - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - // header - "?##" - // msg_id - "\x00\x11" - // msg_size - "\x00\x00\x00\x16" - // data - "\x0a" "\x09" "trezor.io" - "\x10" VERSION_MAJOR_CHAR - "\x18" VERSION_MINOR_CHAR - "\x20" VERSION_PATCH_CHAR - "\x28" "\x01" - "\x90\x01" "\x00" - "\xaa" "\x01" "1" - // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} - } else { - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, - // header - "?##" - // msg_id - "\x00\x11" - // msg_size - "\x00\x00\x00\x16" - // data - "\x0a" "\x09" "trezor.io" - "\x10" VERSION_MAJOR_CHAR - "\x18" VERSION_MINOR_CHAR - "\x20" VERSION_PATCH_CHAR - "\x28" "\x01" - "\x90\x01" "\x01" - "\xaa" "\x01" "1" - // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} - } + memcpy(response, + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x16" + // data + "\x0a" "\x09" "trezor.io" + "\x10" VERSION_MAJOR_CHAR + "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" "\x01" + "\x90\x01" "\x00" + "\xaa" "\x01" "1", + 34); + response[30] = brand_new_firmware ? 0x01 : 0x00; + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} } static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); // response: ButtonRequest message (id 26), payload len 2 // - code = ButtonRequest_FirmwareCheck (9) - while ( usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, + memcpy(response, // header "?##" // msg_id @@ -233,10 +218,10 @@ static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) // msg_size "\x00\x00\x00\x02" // data - "\x08" "\x09" - // padding - "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - , 64) != 64) {} + "\x08" "\x09", + 11 + ); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} } static void backup_metadata(uint8_t *backup) @@ -551,8 +536,7 @@ void usbInit(void) usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, set_config); usb21_setup(usbd_dev, &bos_descriptor); - static const char* origin_url = "trezor.io/start"; - webusb_setup(usbd_dev, origin_url); + webusb_setup(usbd_dev, "trezor.io/start"); winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } From 7288d056a16d25c30d774985d347f130623cb958 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 10 Feb 2019 13:17:25 +0100 Subject: [PATCH 1067/1154] util: readprotobufint uses const argument --- util.c | 2 +- util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 768410c318..575127421c 100644 --- a/util.c +++ b/util.c @@ -44,7 +44,7 @@ void data2hex(const void *data, uint32_t len, char *str) str[len * 2] = 0; } -uint32_t readprotobufint(uint8_t **ptr) +uint32_t readprotobufint(const uint8_t **ptr) { uint32_t result = (**ptr & 0x7F); if (**ptr & 0x80) { diff --git a/util.h b/util.h index 03faf2dc8d..384ede0e32 100644 --- a/util.h +++ b/util.h @@ -42,7 +42,7 @@ void uint32hex(uint32_t num, char *str); void data2hex(const void *data, uint32_t len, char *str); // read protobuf integer and advance pointer -uint32_t readprotobufint(uint8_t **ptr); +uint32_t readprotobufint(const uint8_t **ptr); extern void __attribute__((noreturn)) shutdown(void); From c609d10c3f465cbb7ced91b45935dfd4b265e2b1 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 10 Feb 2019 13:17:25 +0100 Subject: [PATCH 1068/1154] util: readprotobufint uses const argument --- bootloader/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index 16376d8a80..4532b6a1da 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -378,7 +378,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) return; } // read payload length - uint8_t *p = buf + 10; + const uint8_t *p = buf + 10; flash_len = readprotobufint(&p); if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big send_msg_failure(dev); From 26f9b5ba8106f504fcc77aa80c6152b245e5e958 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 10 Feb 2019 13:21:31 +0100 Subject: [PATCH 1069/1154] flash: unify lock/unlock sequences --- firmware/bl_check.c | 3 +++ supervise.c | 1 + 2 files changed, 4 insertions(+) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 92c0a76e14..5ca0a41c34 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -78,6 +78,8 @@ void check_bootloader(void) for (int tries = 0; tries < 10; tries++) { // replace bootloader + flash_wait_for_last_operation(); + flash_clear_status_flags(); flash_unlock(); for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { flash_erase_sector(i, FLASH_CR_PROGRAM_X32); @@ -86,6 +88,7 @@ void check_bootloader(void) const uint32_t *w = (const uint32_t *)(bl_data + i * 4); flash_program_word(FLASH_BOOT_START + i * 4, *w); } + flash_wait_for_last_operation(); flash_lock(); // check whether the write was OK r = memory_bootloader_hash(hash); diff --git a/supervise.c b/supervise.c index 3c21ea0e43..7669cc5ed0 100644 --- a/supervise.c +++ b/supervise.c @@ -25,6 +25,7 @@ #if !EMULATOR static void svhandler_flash_unlock(void) { + flash_wait_for_last_operation(); flash_clear_status_flags(); flash_unlock(); } From 4bc37c6b8227d0c49fc52c883fc5bb9c59d6969b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 01:44:10 +0100 Subject: [PATCH 1070/1154] signing: add default values for branch_id (zcash) --- firmware/signing.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/firmware/signing.c b/firmware/signing.c index 428fbd4d96..035ab05c72 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -487,6 +487,17 @@ void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) overwintered = msg->has_overwintered && msg->overwintered; version_group_id = msg->version_group_id; branch_id = msg->branch_id; + // set default values for Zcash if branch_id is unset + if (overwintered && (branch_id == 0)) { + switch (version) { + case 3: + branch_id = 0x5BA81B19; // Overwinter + break; + case 4: + branch_id = 0x76B809BB; // Sapling + break; + } + } uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); if (coin->decred) { From 5137f4ec00fa9c0ad506078859ce7e854a50de90 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 14:25:49 +0100 Subject: [PATCH 1071/1154] firmware: bump version to 1.8.0 --- firmware/ChangeLog | 3 +++ firmware/trezor.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index e754d1c171..8f31e2f6d3 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,3 +1,6 @@ +Version 1.8.0 +* Stable release, optional update + Version 1.7.3 * Stable release, optional update * Fix USB issue on some Windows 10 installations diff --git a/firmware/trezor.h b/firmware/trezor.h index dc3d471cb1..65a5158904 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -23,8 +23,8 @@ #include #define VERSION_MAJOR 1 -#define VERSION_MINOR 7 -#define VERSION_PATCH 3 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) From 4f32cb508383ec0e65843d037f6ac6473a668359 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 25 Jan 2019 11:58:23 +0100 Subject: [PATCH 1072/1154] firmware: integrate trezor-storage --- .gitmodules | 3 + Makefile | 2 + Makefile.include | 3 +- common.c | 65 +++ common.h | 43 ++ firmware/Makefile | 10 +- firmware/config.c | 854 ++++++++++++++++++++++++++++ firmware/{storage.h => config.h} | 105 ++-- firmware/fsm.c | 9 +- firmware/fsm_msg_common.h | 79 ++- firmware/fsm_msg_debug.h | 14 +- firmware/layout2.c | 21 +- firmware/protect.c | 157 +++--- firmware/protect.h | 3 +- firmware/recovery.c | 27 +- firmware/reset.c | 51 +- firmware/reset.h | 2 +- firmware/stellar.c | 4 +- firmware/storage.c | 936 ------------------------------- firmware/trezor.c | 8 +- firmware/u2f.c | 10 +- firmware/usb.c | 4 +- flash.c | 137 +++++ flash.h | 47 ++ norcow_config.h | 39 ++ secbool.h | 33 ++ vendor/trezor-storage | 1 + 27 files changed, 1484 insertions(+), 1183 deletions(-) create mode 100644 common.c create mode 100644 common.h create mode 100644 firmware/config.c rename firmware/{storage.h => config.h} (53%) delete mode 100644 firmware/storage.c create mode 100644 flash.c create mode 100644 flash.h create mode 100644 norcow_config.h create mode 100644 secbool.h create mode 160000 vendor/trezor-storage diff --git a/.gitmodules b/.gitmodules index 920894a059..ff5aff640d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "vendor/nanopb"] path = vendor/nanopb url = https://github.com/nanopb/nanopb.git +[submodule "vendor/trezor-storage"] + path = vendor/trezor-storage + url = https://github.com/trezor/trezor-storage.git diff --git a/Makefile b/Makefile index 140c3faf54..fce0a317c5 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,8 @@ OBJS += startup.o endif OBJS += buttons.o +OBJS += common.o +OBJS += flash.o OBJS += layout.o OBJS += oled.o OBJS += rng.o diff --git a/Makefile.include b/Makefile.include index 1f175f0e28..11e922652f 100644 --- a/Makefile.include +++ b/Makefile.include @@ -72,7 +72,8 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ - -I$(TOP_DIR)vendor/trezor-qrenc + -I$(TOP_DIR)vendor/trezor-qrenc \ + -I$(TOP_DIR)vendor/trezor-storage LDFLAGS += -L$(TOP_DIR) \ $(DBGFLAGS) \ diff --git a/common.c b/common.c new file mode 100644 index 0000000000..5a8c0c1cc5 --- /dev/null +++ b/common.c @@ -0,0 +1,65 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include "common.h" +#include "rng.h" +#include "layout.h" +#include "firmware/usb.h" + +void shutdown(void); + +void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { + char line[4][128] = {{0}}; + int i = 0; + if (expr != NULL) { + snprintf(line[i], sizeof(line[0]), "Expr: %s", expr); + i++; + } + if (msg != NULL) { + snprintf(line[i], sizeof(line[0]), "Msg: %s", msg); + i++; + } + if (file != NULL) { + snprintf(line[i], sizeof(line[0]), "File: %s:%d", file, line_num); + i++; + } + if (func != NULL) { + snprintf(line[i], sizeof(line[0]), "Func: %s", func); + i++; + } + error_shutdown("FATAL ERROR:", NULL, line[0], line[1], line[2], line[3]); +} + +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, line5, line6); + shutdown(); + for (;;); +} + +#ifndef NDEBUG +void __assert_func(const char *file, int line, const char *func, const char *expr) { + __fatal_error(expr, "assert failed", file, line, func); +} +#endif + +void hal_delay(uint32_t ms) +{ + usbSleep(ms); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000000..b89547a378 --- /dev/null +++ b/common.h @@ -0,0 +1,43 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TREZORHAL_COMMON_H__ +#define __TREZORHAL_COMMON_H__ + +#include +#include "secbool.h" + +#define XSTR(s) STR(s) +#define STR(s) #s + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); + +#define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) + +void hal_delay(uint32_t ms); + +#endif diff --git a/firmware/Makefile b/firmware/Makefile index c8095160ce..90e136324d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -11,7 +11,7 @@ endif OBJS += u2f.o OBJS += messages.o -OBJS += storage.o +OBJS += config.o OBJS += trezor.o OBJS += pinmatrix.o OBJS += fsm.o @@ -75,10 +75,18 @@ OBJS += ../vendor/trezor-crypto/aes/aeskey.o OBJS += ../vendor/trezor-crypto/aes/aestab.o OBJS += ../vendor/trezor-crypto/aes/aes_modes.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/chacha20poly1305.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/chacha_merged.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/poly1305-donna.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/rfc7539.o + OBJS += ../vendor/trezor-crypto/nem.o OBJS += ../vendor/trezor-qrenc/qr_encode.o +OBJS += ../vendor/trezor-storage/storage.o +OBJS += ../vendor/trezor-storage/norcow.o + OBJS += ../vendor/nanopb/pb_common.o OBJS += ../vendor/nanopb/pb_decode.o OBJS += ../vendor/nanopb/pb_encode.o diff --git a/firmware/config.c b/firmware/config.c new file mode 100644 index 0000000000..7799f1ff81 --- /dev/null +++ b/firmware/config.c @@ -0,0 +1,854 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + +#include "messages.pb.h" + +#include "trezor.h" +#include "sha2.h" +#include "aes/aes.h" +#include "pbkdf2.h" +#include "hmac.h" +#include "bip32.h" +#include "bip39.h" +#include "curves.h" +#include "util.h" +#include "memory.h" +#include "rng.h" +#include "config.h" +#include "debug.h" +#include "protect.h" +#include "layout2.h" +#include "usb.h" +#include "gettext.h" +#include "u2f.h" +#include "memzero.h" +#include "supervise.h" +#include "storage.h" + +/* Magic constant to check validity of storage block for storage versions 1 to 10. */ +static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t + +#define APP 0x0100 +#define FLAG_PUBLIC 0x8000 + +static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) +static const uint16_t KEY_VERSION = 1 | APP; // uint32 +static const uint16_t KEY_NODE = 2 | APP; // node +static const uint16_t KEY_MNEMONIC = 3 | APP; // string(241) +static const uint16_t KEY_PASSPHRASE_PROTECTION = 4 | APP; // bool +static const uint16_t KEY_LANGUAGE = 5 | APP | FLAG_PUBLIC; // string(17) +static const uint16_t KEY_LABEL = 6 | APP | FLAG_PUBLIC; // string(33) +static const uint16_t KEY_IMPORTED = 7 | APP; // bool +static const uint16_t KEY_HOMESCREEN = 8 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_NEEDS_BACKUP = 10 | APP; // bool +static const uint16_t KEY_FLAGS = 11 | APP; // uint32 +static const uint16_t KEY_U2F_ROOT = 12 | APP; // node +static const uint16_t KEY_UNFINISHED_BACKUP = 13 | APP; // bool +static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 14 | APP; // uint32 +static const uint16_t KEY_NO_BACKUP = 15 | APP; // bool + +// The PIN value corresponding to an empty PIN. +static const uint32_t PIN_EMPTY = 1; + +static uint32_t config_uuid[UUID_SIZE / sizeof(uint32_t)]; +_Static_assert(sizeof(config_uuid) == UUID_SIZE, "config_uuid has wrong size"); + +char config_uuid_str[2*UUID_SIZE + 1]; + +/* + Old storage layout: + + offset | type/length | description +--------+--------------+------------------------------- + 0x0000 | 4 bytes | magic = 'stor' + 0x0004 | 12 bytes | uuid + 0x0010 | ? bytes | Storage structure +--------+--------------+------------------------------- + 0x4000 | 4 kbytes | area for pin failures + 0x5000 | 256 bytes | area for u2f counter updates + 0x5100 | 11.75 kbytes | reserved + +The area for pin failures looks like this: +0 ... 0 pinfail 0xffffffff .. 0xffffffff +The pinfail is a binary number of the form 1...10...0, +the number of zeros is the number of pin failures. +This layout is used because we can only clear bits without +erasing the flash. + +The area for u2f counter updates is just a sequence of zero-bits +followed by a sequence of one-bits. The bits in a byte are numbered +from LSB to MSB. The number of zero bits is the offset that should +be added to the storage u2f_counter to get the real counter value. + + */ + +/* Current u2f offset, i.e. u2f counter is + * storage.u2f_counter + config_u2f_offset. + * This corresponds to the number of cleared bits in the U2FAREA. + */ +static bool sessionSeedCached, sessionSeedUsesPassphrase; + +static uint8_t CONFIDENTIAL sessionSeed[64]; + +static bool sessionPassphraseCached = false; +static char CONFIDENTIAL sessionPassphrase[51]; + +static const uint32_t CONFIG_VERSION = 10; + +static const uint8_t FALSE_BYTE = '\x00'; +static const uint8_t TRUE_BYTE = '\x01'; + +static uint32_t pin_to_int(const char *pin) +{ + uint32_t val = 1; + size_t i = 0; + for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) { + if (pin[i] < '0' || pin[i] > '9') { + return 0; + } + val = 10*val + pin[i] - '0'; + } + + if (pin[i] != '\0') { + return 0; + } + + return val; +} + +static bool config_set_bool(uint16_t key, bool value) +{ + if (value) { + return (sectrue == storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE))); + } else { + return (sectrue == storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE))); + } +} + +static bool config_get_bool(uint16_t key) +{ + uint8_t value = 0; + uint16_t len = 0; + secbool ret = storage_get(key, &value, sizeof(value), &len); + return (sectrue == ret && len == 1 && value == TRUE_BYTE); +} + +static bool config_has_key(uint16_t key) +{ + uint16_t len = 0; + return sectrue == storage_get(key, NULL, 0, &len); +} + +static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { + dest[0] = '\0'; + uint16_t len = 0; + if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { + return false; + } + dest[len] = '\0'; + return true; +} + +static uint32_t config_get_uint32(uint16_t key) { + uint32_t value = 0; + uint16_t len = 0; + if (sectrue != storage_get(key, &value, sizeof(value), &len) || len != sizeof(value)) { + return 0; + } + return value; +} + +void config_show_error(void) +{ + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); + shutdown(); +} + +static bool config_upgrade_v10(void) +{ +#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) + + if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + // wrong magic + return false; + } + + Storage config __attribute__((aligned(4))); + _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); + + memcpy(config_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); + memcpy(&config, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); + + // version 1: since 1.0.0 + // version 2: since 1.2.1 + // version 3: since 1.3.1 + // version 4: since 1.3.2 + // version 5: since 1.3.3 + // version 6: since 1.3.6 + // version 7: since 1.5.1 + // version 8: since 1.5.2 + // version 9: since 1.6.1 + // version 10: since 1.7.2 + if (config.version > CONFIG_VERSION) { + // downgrade -> clear storage + config_wipe(); + return false; + } + + size_t old_config_size = 0; + if (config.version == 0) { + } else if (config.version <= 2) { + old_config_size = OLD_STORAGE_SIZE(imported); + } else if (config.version <= 5) { + // added homescreen + old_config_size = OLD_STORAGE_SIZE(homescreen); + } else if (config.version <= 7) { + // added u2fcounter + old_config_size = OLD_STORAGE_SIZE(u2f_counter); + } else if (config.version <= 8) { + // added flags and needsBackup + old_config_size = OLD_STORAGE_SIZE(flags); + } else if (config.version <= 9) { + // added u2froot, unfinished_backup and auto_lock_delay_ms + old_config_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); + } else if (config.version <= 10) { + // added no_backup + old_config_size = OLD_STORAGE_SIZE(no_backup); + } + + // Erase newly added fields. + if (old_config_size != sizeof(Storage)) { + memzero(&config + old_config_size, sizeof(Storage) - old_config_size); + } + + const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; + uint32_t pin_wait = 0; + if (config.version <= 5) { + // Get PIN failure counter from version 5 format. + uint32_t pinctr = config.has_pin_failed_attempts ? config.pin_failed_attempts : 0; + if (pinctr > 31) { + pinctr = 31; + } + + pin_wait = (1 << pinctr) - 1; + } else { + // Get PIN failure counter from version 10 format. + uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; + while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) { + flash_pinfails += sizeof(uint32_t); + } + pin_wait = ~*(const uint32_t*)FLASH_PTR(flash_pinfails); + } + + uint32_t u2f_offset = 0; + if (config.has_u2f_counter) { + const uint32_t FLASH_STORAGE_U2FAREA = FLASH_STORAGE_PINAREA + 0x1000; + const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); + while (*u2fptr == 0) { + u2fptr++; + } + u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); + uint32_t u2fword = *u2fptr; + while ((u2fword & 1) == 0) { + u2f_offset++; + u2fword >>= 1; + } + } + + // TODO Add salt. + storage_init(NULL, (const uint8_t*)"", 0); + storage_unlock(PIN_EMPTY); + if (config.has_pin) { + storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); + } + while (pin_wait != 0) { + storage_pin_fails_increase(); + pin_wait >>= 1; + } + + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + if (config.has_node) { + storage_set(KEY_NODE, &config.node, sizeof(config.node)); + } + if (config.has_mnemonic) { + config_setMnemonic(config.mnemonic); + } + if (config.has_passphrase_protection) { + config_setPassphraseProtection(config.passphrase_protection); + } + if (config.has_language) { + config_setLanguage(config.language); + } + if (config.has_label) { + config_setLabel(config.label); + } + if (config.has_imported) { + config_setImported(config.imported); + } + if (config.has_homescreen) { + config_setHomescreen(config.homescreen.bytes, config.homescreen.size); + } + if (config.has_u2f_counter) { + config_setU2FCounter(config.u2f_counter + u2f_offset); + } + if (config.has_needs_backup) { + config_setNeedsBackup(config.needs_backup); + } + if (config.has_flags) { + config_applyFlags(config.flags); + } + if (config.has_unfinished_backup) { + config_setUnfinishedBackup(config.unfinished_backup); + } + if (config.has_auto_lock_delay_ms) { + config_setAutoLockDelayMs(config.auto_lock_delay_ms); + } + if (config.has_no_backup && config.no_backup) { + config_setNoBackup(); + } + memzero(&config, sizeof(config)); + + session_clear(true); + + return true; +} + +void config_init(void) +{ + config_upgrade_v10(); + + // TODO Add salt. + storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + + uint16_t len = 0; + if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + } else { + config_wipe(); + } +} + +void session_clear(bool lock) +{ + sessionSeedCached = false; + memzero(&sessionSeed, sizeof(sessionSeed)); + sessionPassphraseCached = false; + memzero(&sessionPassphrase, sizeof(sessionPassphrase)); + if (lock) { + storage_lock(); + } +} + +static void get_u2froot_callback(uint32_t iter, uint32_t total) +{ + layoutProgress(_("Updating"), 1000 * iter / total); +} + +static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { + static CONFIDENTIAL HDNode node; + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 + usbTiny(oldTiny); + hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); + hdnode_private_ckd(&node, U2F_KEY_PATH); + u2froot->depth = node.depth; + u2froot->child_num = U2F_KEY_PATH; + u2froot->chain_code.size = sizeof(node.chain_code); + memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); + u2froot->has_private_key = true; + u2froot->private_key.size = sizeof(node.private_key); + memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); + memzero(&node, sizeof(node)); + session_clear(false); // invalidate seed cache +} + +static void config_setNode(const HDNodeType *node) { + StorageHDNode storageHDNode; + memzero(&storageHDNode, sizeof(storageHDNode)); + + storageHDNode.depth = node->depth; + storageHDNode.fingerprint = node->fingerprint; + storageHDNode.child_num = node->child_num; + storageHDNode.chain_code.size = 32; + memcpy(storageHDNode.chain_code.bytes, node->chain_code.bytes, 32); + + if (node->has_private_key) { + storageHDNode.has_private_key = true; + storageHDNode.private_key.size = 32; + memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); + } + storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode)); +} + +#if DEBUG_LINK +void config_dumpNode(HDNodeType *node) +{ + memzero(node, sizeof(HDNodeType)); + + StorageHDNode storageNode; + uint16_t len = 0; + if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { + return; + } + + node->depth = storageNode.depth; + node->fingerprint = storageNode.fingerprint; + node->child_num = storageNode.child_num; + + node->chain_code.size = 32; + memcpy(node->chain_code.bytes, storageNode.chain_code.bytes, 32); + + if (storageNode.has_private_key) { + node->has_private_key = true; + node->private_key.size = 32; + memcpy(node->private_key.bytes, storageNode.private_key.bytes, 32); + } + + memzero(&storageNode, sizeof(storageNode)); +} +#endif + +void config_loadDevice(const LoadDevice *msg) +{ + session_clear(true); + // TODO We can't set anything with the storage locked. Shouldn't we wipe? + + config_set_bool(KEY_IMPORTED, true); + config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); + + if (msg->has_pin) { + config_changePin("", msg->pin); + } + + if (msg->has_node) { + storage_delete(KEY_MNEMONIC); + config_setNode(&(msg->node)); + } else if (msg->has_mnemonic) { + storage_delete(KEY_NODE); + config_setMnemonic(msg->mnemonic); + } + + if (msg->has_language) { + config_setLanguage(msg->language); + } + + config_setLabel(msg->has_label ? msg->label : ""); + + if (msg->has_u2f_counter) { + config_setU2FCounter(msg->u2f_counter); + } +} + +void config_setLabel(const char *label) +{ + if (label == NULL || label[0] == '\0') { + storage_delete(KEY_LABEL); + } else { + storage_set(KEY_LABEL, label, strnlen(label, MAX_LABEL_LEN)); + } +} + +void config_setLanguage(const char *lang) +{ + if (lang == NULL) { + return; + } + + // Sanity check. + if (strcmp(lang, "english") != 0) { + return; + } + storage_set(KEY_LABEL, lang, strnlen(lang, MAX_LANGUAGE_LEN)); +} + +void config_setPassphraseProtection(bool passphrase_protection) +{ + sessionSeedCached = false; + sessionPassphraseCached = false; + config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); +} + +bool config_hasPassphraseProtection(void) +{ + return config_get_bool(KEY_PASSPHRASE_PROTECTION); +} + +void config_setHomescreen(const uint8_t *data, uint32_t size) +{ + if (data != NULL && size == HOMESCREEN_SIZE) { + storage_set(KEY_HOMESCREEN, data, size); + } else { + storage_delete(KEY_HOMESCREEN); + } +} + +static void get_root_node_callback(uint32_t iter, uint32_t total) +{ + usbSleep(1); + layoutProgress(_("Waking up"), 1000 * iter / total); +} + +const uint8_t *config_getSeed(bool usePassphrase) +{ + // root node is properly cached + if (usePassphrase == sessionSeedUsesPassphrase + && sessionSeedCached) { + return sessionSeed; + } + + // if storage has mnemonic, convert it to node and use it + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + if (usePassphrase && !protectPassphrase()) { + memzero(mnemonic, sizeof(mnemonic)); + return NULL; + } + // if storage was not imported (i.e. it was properly generated or recovered) + if (!config_get_bool(KEY_IMPORTED)) { + // test whether mnemonic is a valid BIP-0039 mnemonic + if (!mnemonic_check(mnemonic)) { + // and if not then halt the device + config_show_error(); + } + } + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 + memzero(mnemonic, sizeof(mnemonic)); + usbTiny(oldTiny); + sessionSeedCached = true; + sessionSeedUsesPassphrase = usePassphrase; + return sessionSeed; + } + + return NULL; +} + +static bool config_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { + return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); +} + +bool config_getU2FRoot(HDNode *node) +{ + StorageHDNode u2fNode; + uint16_t len = 0; + if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) || len != sizeof(StorageHDNode)) { + memzero(&u2fNode, sizeof(u2fNode)); + return false; + } + bool ret = config_loadNode(&u2fNode, NIST256P1_NAME, node); + memzero(&u2fNode, sizeof(u2fNode)); + return ret; +} + +bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) +{ + // if storage has node, decrypt and use it + StorageHDNode storageHDNode; + uint16_t len = 0; + if (strcmp(curve, SECP256K1_NAME) == 0 && sectrue == storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) && len == sizeof(StorageHDNode)) { + if (!protectPassphrase()) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; + } + if (!config_loadNode(&storageHDNode, curve, node)) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; + } + if (config_hasPassphraseProtection() && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + // decrypt hd node + uint8_t secret[64]; + PBKDF2_HMAC_SHA512_CTX pctx; + char oldTiny = usbTiny(1); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); + get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); + } + pbkdf2_hmac_sha512_Final(&pctx, secret); + usbTiny(oldTiny); + aes_decrypt_ctx ctx; + aes_decrypt_key256(secret, &ctx); + aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); + aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); + } + return true; + } + memzero(&storageHDNode, sizeof(storageHDNode)); + + const uint8_t *seed = config_getSeed(usePassphrase); + if (seed == NULL) { + return false; + } + + return hdnode_from_seed(seed, 64, curve, node); +} + +bool config_getLabel(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_LABEL, dest, dest_size); +} + +bool config_getLanguage(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_LANGUAGE, dest, dest_size); +} + +bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) +{ + uint16_t len = 0; + secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len); + if (sectrue != ret || len != HOMESCREEN_SIZE) { + return false; + } + return true; +} + +void config_setMnemonic(const char *mnemonic) +{ + if (mnemonic == NULL) { + return; + } + + if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { + return; + } + + StorageHDNode u2fNode; + memzero(&u2fNode, sizeof(u2fNode)); + config_compute_u2froot(mnemonic, &u2fNode); + storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); + memzero(&u2fNode, sizeof(u2fNode)); +} + +bool config_hasNode(void) +{ + return config_has_key(KEY_NODE); +} + +bool config_hasMnemonic(void) +{ + return config_has_key(KEY_MNEMONIC); +} + +bool config_getMnemonic(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_MNEMONIC, dest, dest_size); +} + +/* Check whether mnemonic matches storage. The mnemonic must be + * a null-terminated string. + */ +bool config_containsMnemonic(const char *mnemonic) +{ + uint16_t len = 0; + uint8_t stored_mnemonic[MAX_MNEMONIC_LEN + 1]; + if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, MAX_MNEMONIC_LEN, &len)) { + return false; + } + stored_mnemonic[len] = '\0'; + + /* The execution time of the following code only depends on the + * (public) input. This avoids timing attacks. + */ + char diff = 0; + uint32_t i = 0; + for (; mnemonic[i]; i++) { + diff |= (stored_mnemonic[i] - mnemonic[i]); + } + diff |= stored_mnemonic[i]; + memzero(stored_mnemonic, sizeof(stored_mnemonic)); + return diff == 0; +} + +/* Check whether pin matches storage. The pin must be + * a null-terminated string with at most 9 characters. + */ +bool config_containsPin(const char *pin) +{ + return sectrue == storage_unlock(pin_to_int(pin)); +} + +bool config_hasPin(void) +{ + return storage_has_pin(); +} + +bool config_changePin(const char *old_pin, const char *new_pin) +{ + uint32_t new_pin_int = pin_to_int(new_pin); + if (new_pin_int == 0) { + return false; + } + + if (sectrue == storage_change_pin(pin_to_int(old_pin), new_pin_int)) { + return true; + } + return false; +} + +void session_cachePassphrase(const char *passphrase) +{ + strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); + sessionPassphraseCached = true; +} + +bool session_isPassphraseCached(void) +{ + return sessionPassphraseCached; +} + +bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) +{ + if (!passphrase && !sessionPassphraseCached) { + return false; + } else { + passphrase = sessionPassphrase; + } + if (!salt) { + // if salt is not provided fill the first half of the state with random data + random_buffer(state, 32); + } else { + // if salt is provided fill the first half of the state with salt + memcpy(state, salt, 32); + } + // state[0:32] = salt + // state[32:64] = HMAC(passphrase, salt || device_id) + HMAC_SHA256_CTX ctx; + hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); + hmac_sha256_Update(&ctx, state, 32); + hmac_sha256_Update(&ctx, (const uint8_t *)config_uuid, sizeof(config_uuid)); + hmac_sha256_Final(&ctx, state + 32); + + memzero(&ctx, sizeof(ctx)); + + return true; +} + +bool session_isPinCached(void) +{ + return storage_is_unlocked(); +} + +bool config_isInitialized(void) +{ + return config_has_key(KEY_NODE) || config_has_key(KEY_MNEMONIC); +} + +bool config_isImported(void) +{ + return config_get_bool(KEY_IMPORTED); +} + +void config_setImported(bool imported) +{ + config_set_bool(KEY_IMPORTED, imported); +} + +bool config_needsBackup(void) +{ + return config_get_bool(KEY_NEEDS_BACKUP); +} + +void config_setNeedsBackup(bool needs_backup) +{ + config_set_bool(KEY_NEEDS_BACKUP, needs_backup); +} + +bool config_unfinishedBackup(void) +{ + return config_get_bool(KEY_UNFINISHED_BACKUP); +} + +void config_setUnfinishedBackup(bool unfinished_backup) +{ + config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); +} + +bool config_noBackup(void) +{ + return config_get_bool(KEY_NO_BACKUP); +} + +void config_setNoBackup(void) +{ + config_set_bool(KEY_NO_BACKUP, true); +} + +void config_applyFlags(uint32_t flags) +{ + uint32_t old_flags = config_get_uint32(KEY_FLAGS); + flags |= old_flags; + if (flags == old_flags) { + return; // no new flags + } + storage_set(KEY_FLAGS, &flags, sizeof(flags)); +} + +uint32_t config_getFlags(void) +{ + return config_get_uint32(KEY_FLAGS); +} + +uint32_t config_nextU2FCounter(void) +{ + // TODO Implement efficient version. + uint32_t counter = 0; + uint16_t len = 0; + storage_get(KEY_U2F_COUNTER, &counter, sizeof(counter), &len); + counter++; + storage_set(KEY_U2F_COUNTER, &counter, sizeof(counter)); + return counter; +} + +void config_setU2FCounter(uint32_t u2fcounter) +{ + storage_set(KEY_U2F_COUNTER, &u2fcounter, sizeof(u2fcounter)); +} + +uint32_t config_getAutoLockDelayMs() +{ + const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes + uint32_t delay_ms = config_get_uint32(KEY_AUTO_LOCK_DELAY_MS); + return (delay_ms != 0) ? delay_ms : default_delay_ms; +} + +void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) +{ + const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds + auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); + storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms)); +} + +void config_wipe(void) +{ + storage_wipe(); + storage_unlock(PIN_EMPTY); + random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + session_clear(true); +} diff --git a/firmware/storage.h b/firmware/config.h similarity index 53% rename from firmware/storage.h rename to firmware/config.h index 3004e89901..8bde314da0 100644 --- a/firmware/storage.h +++ b/firmware/config.h @@ -17,8 +17,8 @@ * along with this library. If not, see . */ -#ifndef __STORAGE_H__ -#define __STORAGE_H__ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ #include "bip32.h" #include "messages-management.pb.h" @@ -76,85 +76,82 @@ typedef struct _Storage { STORAGE_BOOL (no_backup) } Storage; -extern Storage storageUpdate; +extern Storage configUpdate; -void storage_init(void); -void storage_generate_uuid(void); -void storage_clear_update(void); -void storage_update(void); -void session_clear(bool clear_pin); +#define MAX_PIN_LEN 9 +#define MAX_LABEL_LEN 32 +#define MAX_LANGUAGE_LEN 16 +#define MAX_MNEMONIC_LEN 240 +#define HOMESCREEN_SIZE 1024 +#define UUID_SIZE 12 -void storage_loadDevice(const LoadDevice *msg); +void config_init(void); +void session_clear(bool lock); -const uint8_t *storage_getSeed(bool usePassphrase); +void config_loadDevice(const LoadDevice *msg); -bool storage_getU2FRoot(HDNode *node); -bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase); +const uint8_t *config_getSeed(bool usePassphrase); -const char *storage_getLabel(void); -void storage_setLabel(const char *label); +bool config_getU2FRoot(HDNode *node); +bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase); -const char *storage_getLanguage(void); -void storage_setLanguage(const char *lang); +bool config_getLabel(char *dest, uint16_t dest_size); +void config_setLabel(const char *label); -void storage_setPassphraseProtection(bool passphrase_protection); -bool storage_hasPassphraseProtection(void); +bool config_getLanguage(char *dest, uint16_t dest_size); +void config_setLanguage(const char *lang); -const uint8_t *storage_getHomescreen(void); -void storage_setHomescreen(const uint8_t *data, uint32_t size); +void config_setPassphraseProtection(bool passphrase_protection); +bool config_hasPassphraseProtection(void); + +bool config_getHomescreen(uint8_t *dest, uint16_t dest_size); +void config_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); -void storage_setMnemonic(const char *mnemonic); -bool storage_containsMnemonic(const char *mnemonic); -bool storage_hasMnemonic(void); -const char *storage_getMnemonic(void); +void config_setMnemonic(const char *mnemonic); +bool config_containsMnemonic(const char *mnemonic); +bool config_hasMnemonic(void); +bool config_getMnemonic(char *dest, uint16_t dest_size); -bool storage_hasNode(void); +bool config_hasNode(void); #if DEBUG_LINK -void storage_dumpNode(HDNodeType *node); +void config_dumpNode(HDNodeType *node); #endif -bool storage_containsPin(const char *pin); -bool storage_hasPin(void); -const char *storage_getPin(void); -void storage_setPin(const char *pin); -void session_cachePin(void); -void session_uncachePin(void); +bool config_containsPin(const char *pin); +bool config_hasPin(void); +void config_setPin(const char *pin); +bool config_changePin(const char *old_pin, const char *new_pin); bool session_isPinCached(void); -void storage_clearPinArea(void); -void storage_resetPinFails(uint32_t flash_pinfails); -bool storage_increasePinFails(uint32_t flash_pinfails); -uint32_t storage_getPinWait(uint32_t flash_pinfails); -uint32_t storage_getPinFailsOffset(void); -uint32_t storage_nextU2FCounter(void); -void storage_setU2FCounter(uint32_t u2fcounter); +uint32_t config_nextU2FCounter(void); +void config_setU2FCounter(uint32_t u2fcounter); -bool storage_isInitialized(void); +bool config_isInitialized(void); -bool storage_isImported(void); -void storage_setImported(bool imported); +bool config_isImported(void); +void config_setImported(bool imported); -bool storage_needsBackup(void); -void storage_setNeedsBackup(bool needs_backup); +bool config_needsBackup(void); +void config_setNeedsBackup(bool needs_backup); -bool storage_unfinishedBackup(void); -void storage_setUnfinishedBackup(bool unfinished_backup); +bool config_unfinishedBackup(void); +void config_setUnfinishedBackup(bool unfinished_backup); -bool storage_noBackup(void); -void storage_setNoBackup(void); +bool config_noBackup(void); +void config_setNoBackup(void); -void storage_applyFlags(uint32_t flags); -uint32_t storage_getFlags(void); +void config_applyFlags(uint32_t flags); +uint32_t config_getFlags(void); -uint32_t storage_getAutoLockDelayMs(void); -void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); +uint32_t config_getAutoLockDelayMs(void); +void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); -void storage_wipe(void); +void config_wipe(void); -extern char storage_uuid_str[25]; +extern char config_uuid_str[2*UUID_SIZE + 1]; #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 50fd0fc45c..ce0732fa15 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -23,12 +23,11 @@ #include "fsm.h" #include "messages.h" #include "bip32.h" -#include "storage.h" +#include "config.h" #include "coins.h" #include "debug.h" #include "transaction.h" #include "rng.h" -#include "storage.h" #include "oled.h" #include "protect.h" #include "pinmatrix.h" @@ -70,13 +69,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); memzero(resp, sizeof(TYPE)); #define CHECK_INITIALIZED \ - if (!storage_isInitialized()) { \ + if (!config_isInitialized()) { \ fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ return; \ } #define CHECK_NOT_INITIALIZED \ - if (storage_isInitialized()) { \ + if (config_isInitialized()) { \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ return; \ } @@ -207,7 +206,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, if (fingerprint) { *fingerprint = 0; } - if (!storage_getRootNode(&node, curve, true)) { + if (!config_getRootNode(&node, curve, true)) { fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); return 0; diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 524d12b114..25fef38382 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -45,31 +45,31 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_major_version = true; resp->major_version = VERSION_MAJOR; resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; - resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); - resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); - resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); + resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); + resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); + resp->has_passphrase_protection = true; resp->passphrase_protection = config_hasPassphraseProtection(); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (storage_getLanguage()) { - resp->has_language = true; - strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); - } - if (storage_getLabel()) { + + if (config_getLanguage(resp->language, sizeof(resp->language))) { + resp->has_language = true; + } + + if (config_getLabel(resp->label, sizeof(resp->label))) { resp->has_label = true; - strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); } - resp->has_initialized = true; resp->initialized = storage_isInitialized(); - resp->has_imported = true; resp->imported = storage_isImported(); + resp->has_initialized = true; resp->initialized = config_isInitialized(); + resp->has_imported = true; resp->imported = config_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); - resp->has_unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); - resp->has_no_backup = true; resp->no_backup = storage_noBackup(); - resp->has_flags = true; resp->flags = storage_getFlags(); + resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); + resp->has_unfinished_backup = true; resp->unfinished_backup = config_unfinishedBackup(); + resp->has_no_backup = true; resp->no_backup = config_noBackup(); + resp->has_flags = true; resp->flags = config_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); @@ -111,14 +111,14 @@ void fsm_msgChangePin(const ChangePin *msg) { bool removal = msg->has_remove && msg->remove; if (removal) { - if (storage_hasPin()) { + if (config_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); } else { fsm_sendSuccess(_("PIN removed")); return; } } else { - if (storage_hasPin()) { + if (config_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); } else { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); @@ -130,19 +130,14 @@ void fsm_msgChangePin(const ChangePin *msg) return; } - CHECK_PIN_UNCACHED + if (protectChangePin(removal)) { + if (removal) { + fsm_sendSuccess(_("PIN removed")); + } else { + fsm_sendSuccess(_("PIN changed")); + } + } - if (removal) { - storage_setPin(""); - storage_update(); - fsm_sendSuccess(_("PIN removed")); - } else { - if (protectChangePin()) { - fsm_sendSuccess(_("PIN changed")); - } else { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - } - } layoutHome(); } @@ -155,7 +150,7 @@ void fsm_msgWipeDevice(const WipeDevice *msg) layoutHome(); return; } - storage_wipe(); + config_wipe(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change fsm_sendSuccess(_("Device wiped")); @@ -202,7 +197,7 @@ void fsm_msgLoadDevice(const LoadDevice *msg) } } - storage_loadDevice(msg); + config_loadDevice(msg); fsm_sendSuccess(_("Device loaded")); layoutHome(); } @@ -242,7 +237,11 @@ void fsm_msgBackupDevice(const BackupDevice *msg) CHECK_PIN_UNCACHED (void)msg; - reset_backup(true); + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + reset_backup(true, mnemonic); + } + memzero(mnemonic, sizeof(mnemonic)); } void fsm_msgCancel(const Cancel *msg) @@ -312,21 +311,20 @@ void fsm_msgApplySettings(const ApplySettings *msg) } if (msg->has_label) { - storage_setLabel(msg->label); + config_setLabel(msg->label); } if (msg->has_language) { - storage_setLanguage(msg->language); + config_setLanguage(msg->language); } if (msg->has_use_passphrase) { - storage_setPassphraseProtection(msg->use_passphrase); + config_setPassphraseProtection(msg->use_passphrase); } if (msg->has_homescreen) { - storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); + config_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } if (msg->has_auto_lock_delay_ms) { - storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); + config_setAutoLockDelayMs(msg->auto_lock_delay_ms); } - storage_update(); fsm_sendSuccess(_("Settings applied")); layoutHome(); } @@ -334,7 +332,7 @@ void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) { if (msg->has_flags) { - storage_applyFlags(msg->flags); + config_applyFlags(msg->flags); } fsm_sendSuccess(_("Flags applied")); } @@ -376,8 +374,7 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg) layoutHome(); return; } - storage_setU2FCounter(msg->u2f_counter); - storage_update(); + config_setU2FCounter(msg->u2f_counter); fsm_sendSuccess(_("U2F counter set")); layoutHome(); } diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 2ac38d4727..788bb5fb8d 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -32,9 +32,9 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.layout.size = OLED_BUFSIZE; memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - if (storage_hasPin()) { + if (config_hasPin()) { resp.has_pin = true; - strlcpy(resp.pin, storage_getPin(), sizeof(resp.pin)); + strlcpy(resp.pin, "1", sizeof(resp.pin)); } resp.has_matrix = true; @@ -52,18 +52,18 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - if (storage_hasMnemonic()) { + if (config_hasMnemonic()) { resp.has_mnemonic = true; - strlcpy(resp.mnemonic, storage_getMnemonic(), sizeof(resp.mnemonic)); + strlcpy(resp.mnemonic, config_getMnemonic(), sizeof(resp.mnemonic)); } - if (storage_hasNode()) { + if (config_hasNode()) { resp.has_node = true; - storage_dumpNode(&(resp.node)); + config_dumpNode(&(resp.node)); } resp.has_passphrase_protection = true; - resp.passphrase_protection = storage_hasPassphraseProtection(); + resp.passphrase_protection = config_hasPassphraseProtection(); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 15bc7ef41c..98474de615 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -22,7 +22,7 @@ #include #include "layout2.h" -#include "storage.h" +#include "config.h" #include "oled.h" #include "bitmaps.h" #include "string.h" @@ -235,31 +235,36 @@ void layoutHome(void) layoutSwipe(); } layoutLast = layoutHome; - const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start"); - const uint8_t *homescreen = storage_getHomescreen(); - if (homescreen) { + + char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); + if (config_isInitialized()) { + config_getLabel(label, sizeof(label)); + } + + uint8_t homescreen[HOMESCREEN_SIZE]; + if (config_getHomescreen(homescreen, sizeof(homescreen))) { BITMAP b; b.width = 128; b.height = 64; b.data = homescreen; oledDrawBitmap(0, 0, &b); } else { - if (label && strlen(label) > 0) { + if (label[0] != '\0') { oledDrawBitmap(44, 4, &bmp_logo48); oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, FONT_STANDARD); } else { oledDrawBitmap(40, 0, &bmp_logo64); } } - if (storage_noBackup()) { + if (config_noBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); } else - if (storage_unfinishedBackup()) { + if (config_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); } else - if (storage_needsBackup()) { + if (config_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); } diff --git a/firmware/protect.c b/firmware/protect.c index 4a1d12c7ed..43acf4ea87 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -18,7 +18,7 @@ */ #include "protect.h" -#include "storage.h" +#include "config.h" #include "memory.h" #include "messages.h" #include "usb.h" @@ -147,102 +147,115 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } -static void protectCheckMaxTry(uint32_t wait) { - if (wait < (1 << MAX_WRONG_PINS)) - return; +void protectPinUiCallback(uint32_t wait, uint32_t progress) +{ + (void) progress; - storage_wipe(); - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PIN"), _("attempts. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); - for (;;) {} // loop forever + // Convert wait to secstr string. + char secstrbuf[] = _("________0 seconds"); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + while (secs > 0 && secstr >= secstrbuf) { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } + if (wait == 1) { + // Change "seconds" to "second". + secstrbuf[16] = 0; + } + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + + /* TODO + if (msg_tiny_id == MessageType_MessageType_Initialize) { + protectAbortedByCancel = false; + protectAbortedByInitialize = true; + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + */ } bool protectPin(bool use_cached) { - if (!storage_hasPin() || (use_cached && session_isPinCached())) { + if (!config_hasPin() || (use_cached && session_isPinCached())) { return true; } - uint32_t fails = storage_getPinFailsOffset(); - uint32_t wait = storage_getPinWait(fails); - protectCheckMaxTry(wait); - usbTiny(1); - while (wait > 0) { - // convert wait to secstr string - char secstrbuf[20]; - strlcpy(secstrbuf, _("________0 seconds"), sizeof(secstrbuf)); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - while (secs > 0 && secstr >= secstrbuf) { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } - if (wait == 1) { - secstrbuf[16] = 0; - } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - // wait one second - usbSleep(1000); - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = false; - protectAbortedByInitialize = true; - msg_tiny_id = 0xFFFF; - usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - wait--; - } - usbTiny(0); - const char *pin; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + + // TODO If maximum number of PIN attempts: + // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); + + const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); if (!pin) { fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } - if (!storage_increasePinFails(fails)) { + + usbTiny(1); + bool ret = config_containsPin(pin); + usbTiny(0); + if (!ret) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; - } - if (storage_containsPin(pin)) { - session_cachePin(); - storage_resetPinFails(fails); - return true; - } else { - protectCheckMaxTry(storage_getPinWait(fails)); - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; } + return ret; } -bool protectChangePin(void) +bool protectChangePin(bool removal) { - static CONFIDENTIAL char pin_compare[17]; + static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; + const char* pin = NULL; - const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (pin == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(old_pin, pin, sizeof(old_pin)); + } - if (!pin) { - return false; - } + if (!removal) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(new_pin, pin, sizeof(new_pin)); - strlcpy(pin_compare, pin, sizeof(pin_compare)); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + return false; + } + } - const bool result = pin && (strncmp(pin_compare, pin, sizeof(pin_compare)) == 0); - - if (result) { - storage_setPin(pin_compare); - storage_update(); - } - - memzero(pin_compare, sizeof(pin_compare)); - - return result; + usbTiny(1); + bool ret = config_changePin(old_pin, new_pin); + usbTiny(0); + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } bool protectPassphrase(void) { - if (!storage_hasPassphraseProtection() || session_isPassphraseCached()) { + if (!config_hasPassphraseProtection() || session_isPassphraseCached()) { return true; } diff --git a/firmware/protect.h b/firmware/protect.h index 8a3af45108..eaf1782762 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -24,8 +24,9 @@ #include "messages-common.pb.h" bool protectButton(ButtonRequestType type, bool confirm_only); +void protectPinUiCallback(uint32_t wait, uint32_t progress); bool protectPin(bool use_cached); -bool protectChangePin(void); +bool protectChangePin(bool removal); bool protectPassphrase(void); extern bool protectAbortedByCancel; diff --git a/firmware/recovery.c b/firmware/recovery.c index f67af3bcdc..d5c7acd088 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -21,7 +21,7 @@ #include #include "recovery.h" #include "fsm.h" -#include "storage.h" +#include "config.h" #include "layout2.h" #include "protect.h" #include "messages.h" @@ -44,7 +44,7 @@ static uint32_t word_count; */ static int awaiting_word = 0; -/* True if we should not write anything back to storage +/* True if we should not write anything back to config * (can be used for testing seed for correctness). */ static bool dry_run; @@ -163,18 +163,17 @@ static void recovery_done(void) { if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { // New mnemonic is valid. if (!dry_run) { - // Update mnemonic on storage. - storage_setMnemonic(new_mnemonic); + // Update mnemonic on config. + config_setMnemonic(new_mnemonic); memzero(new_mnemonic, sizeof(new_mnemonic)); if (!enforce_wordlist) { - // not enforcing => mark storage as imported - storage_setImported(true); + // not enforcing => mark config as imported + config_setImported(true); } - storage_update(); fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - bool match = (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)); + bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); memzero(new_mnemonic, sizeof(new_mnemonic)); if (match) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, @@ -466,17 +465,15 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr } if (!dry_run) { - if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + if (pin_protection && !protectChangePin(false)) { layoutHome(); return; } - storage_setPassphraseProtection(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setU2FCounter(u2f_counter); - storage_update(); + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); } if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { diff --git a/firmware/reset.c b/firmware/reset.c index dd7fe102bf..df6bc83612 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -18,7 +18,7 @@ */ #include "reset.h" -#include "storage.h" +#include "config.h" #include "rng.h" #include "sha2.h" #include "messages.h" @@ -75,17 +75,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect } } - if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + if (pin_protection && !protectChangePin(false)) { layoutHome(); return; } - storage_setPassphraseProtection(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setU2FCounter(u2f_counter); - storage_update(); + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); EntropyRequest resp; memzero(&resp, sizeof(EntropyRequest)); @@ -104,45 +102,41 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); sha256_Final(&ctx, int_entropy); - if (no_backup) { - storage_setNoBackup(); - } else { - storage_setNeedsBackup(true); - } - storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); - mnemonic_clear(); + const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); memzero(int_entropy, 32); awaiting_entropy = false; + if (skip_backup || no_backup) { - storage_update(); + if (no_backup) { + config_setNoBackup(); + } else { + config_setNeedsBackup(true); + } + config_setMnemonic(mnemonic); fsm_sendSuccess(_("Device successfully initialized")); layoutHome(); } else { - reset_backup(false); + reset_backup(false, mnemonic); } - + mnemonic_clear(); } static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage -void reset_backup(bool separated) +void reset_backup(bool separated, const char* mnemonic) { - if (!storage_needsBackup()) { + if (!config_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } - storage_setUnfinishedBackup(true); - storage_setNeedsBackup(false); - if (separated) { - storage_update(); + config_setUnfinishedBackup(true); + config_setNeedsBackup(false); } - const char *mnemonic = storage_getMnemonic(); - for (int pass = 0; pass < 2; pass++) { int i = 0, word_pos = 1; while (mnemonic[i] != 0) { @@ -159,7 +153,6 @@ void reset_backup(bool separated) layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { - storage_clear_update(); session_clear(true); } layoutHome(); @@ -170,12 +163,14 @@ void reset_backup(bool separated) } } - storage_setUnfinishedBackup(false); + config_setUnfinishedBackup(false); storage_update(); if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { + config_setNeedsBackup(false); + config_setMnemonic(mnemonic); fsm_sendSuccess(_("Device successfully initialized")); } layoutHome(); diff --git a/firmware/reset.h b/firmware/reset.h index f4638ac36f..3ceea7533b 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -25,7 +25,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); -void reset_backup(bool separated); +void reset_backup(bool separated, const char* mnemonic); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); diff --git a/firmware/stellar.c b/firmware/stellar.c index 662cd5922b..5ee64d8574 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -38,7 +38,7 @@ #include "bignum.h" #include "oled.h" #include "base32.h" -#include "storage.h" +#include "config.h" #include "fsm.h" #include "protect.h" #include "util.h" @@ -1514,7 +1514,7 @@ const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_cou const char *curve = "ed25519"; // Device not initialized, passphrase request cancelled, or unsupported curve - if (!storage_getRootNode(&node, curve, true)) { + if (!config_getRootNode(&node, curve, true)) { return 0; } // Failed to derive private key diff --git a/firmware/storage.c b/firmware/storage.c deleted file mode 100644 index 6e7f66db32..0000000000 --- a/firmware/storage.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include -#include - -#include - -#include "messages.pb.h" - -#include "trezor.h" -#include "sha2.h" -#include "aes/aes.h" -#include "pbkdf2.h" -#include "hmac.h" -#include "bip32.h" -#include "bip39.h" -#include "curves.h" -#include "util.h" -#include "memory.h" -#include "rng.h" -#include "storage.h" -#include "debug.h" -#include "protect.h" -#include "layout2.h" -#include "usb.h" -#include "gettext.h" -#include "u2f.h" -#include "memzero.h" -#include "supervise.h" - -/* magic constant to check validity of storage block */ -static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t - -static uint32_t storage_uuid[12 / sizeof(uint32_t)]; -_Static_assert(sizeof(storage_uuid) == 12, "storage_uuid has wrong size"); - -Storage CONFIDENTIAL storageUpdate __attribute__((aligned(4))); -_Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); - -#define FLASH_STORAGE (FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid)) -#define storageRom ((const Storage *) FLASH_PTR(FLASH_STORAGE)) - -char storage_uuid_str[25]; - -/* - storage layout: - - offset | type/length | description ---------+--------------+------------------------------- - 0x0000 | 4 bytes | magic = 'stor' - 0x0004 | 12 bytes | uuid - 0x0010 | ? bytes | Storage structure ---------+--------------+------------------------------- - 0x4000 | 4 kbytes | area for pin failures - 0x5000 | 256 bytes | area for u2f counter updates - 0x5100 | 11.75 kbytes | reserved - -The area for pin failures looks like this: -0 ... 0 pinfail 0xffffffff .. 0xffffffff -The pinfail is a binary number of the form 1...10...0, -the number of zeros is the number of pin failures. -This layout is used because we can only clear bits without -erasing the flash. - -The area for u2f counter updates is just a sequence of zero-bits -followed by a sequence of one-bits. The bits in a byte are numbered -from LSB to MSB. The number of zero bits is the offset that should -be added to the storage u2f_counter to get the real counter value. - - */ - -#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000) -#define FLASH_STORAGE_PINAREA_LEN (0x1000) -#define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) -#define FLASH_STORAGE_U2FAREA_LEN (0x100) -#define FLASH_STORAGE_REALLEN (sizeof(storage_magic) + sizeof(storage_uuid) + sizeof(Storage)) - -#if !EMULATOR -// TODO: Fix this for emulator -_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); -#endif - -/* Current u2f offset, i.e. u2f counter is - * storage.u2f_counter + storage_u2f_offset. - * This corresponds to the number of cleared bits in the U2FAREA. - */ -static uint32_t storage_u2f_offset; - -static bool sessionSeedCached, sessionSeedUsesPassphrase; - -static uint8_t CONFIDENTIAL sessionSeed[64]; - -static bool sessionPinCached = false; - -static bool sessionPassphraseCached = false; -static char CONFIDENTIAL sessionPassphrase[51]; - -#define STORAGE_VERSION 10 - -void storage_show_error(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); - shutdown(); -} - -void storage_check_flash_errors(uint32_t status) -{ - // flash operation failed - if (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { - storage_show_error(); - } -} - -bool storage_from_flash(void) -{ - storage_clear_update(); - if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &storage_magic, sizeof(storage_magic)) != 0) { - // wrong magic - return false; - } - - const uint32_t version = storageRom->version; - // version 1: since 1.0.0 - // version 2: since 1.2.1 - // version 3: since 1.3.1 - // version 4: since 1.3.2 - // version 5: since 1.3.3 - // version 6: since 1.3.6 - // version 7: since 1.5.1 - // version 8: since 1.5.2 - // version 9: since 1.6.1 - // version 10: since 1.7.2 - if (version > STORAGE_VERSION) { - // downgrade -> clear storage - return false; - } - - // load uuid - memcpy(storage_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); - data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); - -#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - - // copy storage - size_t old_storage_size = 0; - - if (version == 0) { - } else if (version <= 2) { - old_storage_size = OLD_STORAGE_SIZE(imported); - } else if (version <= 5) { - // added homescreen - old_storage_size = OLD_STORAGE_SIZE(homescreen); - } else if (version <= 7) { - // added u2fcounter - old_storage_size = OLD_STORAGE_SIZE(u2f_counter); - } else if (version <= 8) { - // added flags and needsBackup - old_storage_size = OLD_STORAGE_SIZE(flags); - } else if (version <= 9) { - // added u2froot, unfinished_backup and auto_lock_delay_ms - old_storage_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); - } else if (version <= 10) { - // added no_backup - old_storage_size = OLD_STORAGE_SIZE(no_backup); - } - - // erase newly added fields - if (old_storage_size != sizeof(Storage)) { - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - for (uint32_t offset = old_storage_size; offset < sizeof(Storage); offset += sizeof(uint32_t)) { - flash_write32(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid) + offset, 0); - } - storage_check_flash_errors(svc_flash_lock()); - } - - if (version <= 5) { - // convert PIN failure counter from version 5 format - uint32_t pinctr = storageRom->has_pin_failed_attempts ? storageRom->pin_failed_attempts : 0; - if (pinctr > 31) { - pinctr = 31; - } - svc_flash_unlock(); - // erase extra storage sector - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); - // storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts - // are erased by storage_update below - storage_check_flash_errors(svc_flash_lock()); - } - const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); - while (*u2fptr == 0) { - u2fptr++; - } - storage_u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); - uint32_t u2fword = *u2fptr; - while ((u2fword & 1) == 0) { - storage_u2f_offset++; - u2fword >>= 1; - } - // force recomputing u2f root for storage version < 9. - // this is done by re-setting the mnemonic, which triggers the computation - if (version < 9) { - storageUpdate.has_mnemonic = storageRom->has_mnemonic; - strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); - } - // update storage version on flash - if (version != STORAGE_VERSION) { - storage_update(); - } - return true; -} - -void storage_init(void) -{ - if (!storage_from_flash()) { - storage_wipe(); - } -} - -void storage_generate_uuid(void) -{ - // set random uuid - random_buffer((uint8_t *)storage_uuid, sizeof(storage_uuid)); - data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); -} - -void session_clear(bool clear_pin) -{ - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - sessionPassphraseCached = false; - memzero(&sessionPassphrase, sizeof(sessionPassphrase)); - if (clear_pin) { - session_uncachePin(); - } -} - -static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwords) { - for (int i = 0; i < nwords; i++) { - flash_write32(addr, *src++); - addr += sizeof(uint32_t); - } - return addr; -} - -static void get_u2froot_callback(uint32_t iter, uint32_t total) -{ - layoutProgress(_("Updating"), 1000 * iter / total); -} - -static void storage_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { - static CONFIDENTIAL HDNode node; - char oldTiny = usbTiny(1); - mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 - usbTiny(oldTiny); - hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); - hdnode_private_ckd(&node, U2F_KEY_PATH); - u2froot->depth = node.depth; - u2froot->child_num = U2F_KEY_PATH; - u2froot->chain_code.size = sizeof(node.chain_code); - memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); - u2froot->has_private_key = true; - u2froot->private_key.size = sizeof(node.private_key); - memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - memzero(&node, sizeof(node)); - session_clear(false); // invalidate seed cache -} - -// if storage is filled in - update fields that has has_field set to true -// if storage is NULL - do not backup original content - essentialy a wipe -static void storage_commit_locked(bool update) -{ - if (update) { - if (storageUpdate.has_passphrase_protection) { - sessionSeedCached = false; - sessionPassphraseCached = false; - } - - storageUpdate.version = STORAGE_VERSION; - if (!storageUpdate.has_node && !storageUpdate.has_mnemonic) { - storageUpdate.has_node = storageRom->has_node; - memcpy(&storageUpdate.node, &storageRom->node, sizeof(StorageHDNode)); - storageUpdate.has_mnemonic = storageRom->has_mnemonic; - strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); - storageUpdate.has_u2froot = storageRom->has_u2froot; - memcpy(&storageUpdate.u2froot, &storageRom->u2froot, sizeof(StorageHDNode)); - } else if (storageUpdate.has_mnemonic) { - storageUpdate.has_u2froot = true; - storage_compute_u2froot(storageUpdate.mnemonic, &storageUpdate.u2froot); - } - if (!storageUpdate.has_passphrase_protection) { - storageUpdate.has_passphrase_protection = storageRom->has_passphrase_protection; - storageUpdate.passphrase_protection = storageRom->passphrase_protection; - } - if (!storageUpdate.has_pin) { - storageUpdate.has_pin = storageRom->has_pin; - strlcpy(storageUpdate.pin, storageRom->pin, sizeof(storageUpdate.pin)); - } else if (!storageUpdate.pin[0]) { - storageUpdate.has_pin = false; - } - if (!storageUpdate.has_language) { - storageUpdate.has_language = storageRom->has_language; - strlcpy(storageUpdate.language, storageRom->language, sizeof(storageUpdate.language)); - } - if (!storageUpdate.has_label) { - storageUpdate.has_label = storageRom->has_label; - strlcpy(storageUpdate.label, storageRom->label, sizeof(storageUpdate.label)); - } else if (!storageUpdate.label[0]) { - storageUpdate.has_label = false; - } - if (!storageUpdate.has_imported) { - storageUpdate.has_imported = storageRom->has_imported; - storageUpdate.imported = storageRom->imported; - } - if (!storageUpdate.has_homescreen) { - storageUpdate.has_homescreen = storageRom->has_homescreen; - memcpy(&storageUpdate.homescreen, &storageRom->homescreen, sizeof(storageUpdate.homescreen)); - } else if (storageUpdate.homescreen.size == 0) { - storageUpdate.has_homescreen = false; - } - if (!storageUpdate.has_u2f_counter) { - storageUpdate.has_u2f_counter = storageRom->has_u2f_counter; - storageUpdate.u2f_counter = storageRom->u2f_counter; - } - if (!storageUpdate.has_needs_backup) { - storageUpdate.has_needs_backup = storageRom->has_needs_backup; - storageUpdate.needs_backup = storageRom->needs_backup; - } - if (!storageUpdate.has_unfinished_backup) { - storageUpdate.has_unfinished_backup = storageRom->has_unfinished_backup; - storageUpdate.unfinished_backup = storageRom->unfinished_backup; - } - if (!storageUpdate.has_no_backup) { - storageUpdate.has_no_backup = storageRom->has_no_backup; - storageUpdate.no_backup = storageRom->no_backup; - } - if (!storageUpdate.has_flags) { - storageUpdate.has_flags = storageRom->has_flags; - storageUpdate.flags = storageRom->flags; - } - } - - // backup meta - uint32_t meta_backup[FLASH_META_DESC_LEN / sizeof(uint32_t)]; - memcpy(meta_backup, FLASH_PTR(FLASH_META_START), FLASH_META_DESC_LEN); - - // erase storage - svc_flash_erase_sector(FLASH_META_SECTOR_FIRST); - svc_flash_program(FLASH_CR_PROGRAM_X32); - - // copy meta back - uint32_t flash = FLASH_META_START; - flash = storage_flash_words(flash, meta_backup, FLASH_META_DESC_LEN / sizeof(uint32_t)); - - // copy storage - flash = storage_flash_words(flash, &storage_magic, sizeof(storage_magic) / sizeof(uint32_t)); - flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid) / sizeof(uint32_t)); - - if (update) { - flash = storage_flash_words(flash, (const uint32_t *)&storageUpdate, sizeof(storageUpdate) / sizeof(uint32_t)); - } - storage_clear_update(); - - // fill remainder with zero for future extensions - while (flash < FLASH_STORAGE_PINAREA) { - flash_write32(flash, 0); - flash += sizeof(uint32_t); - } -} - -void storage_clear_update(void) -{ - memzero(&storageUpdate, sizeof(storageUpdate)); -} - -void storage_update(void) -{ - svc_flash_unlock(); - storage_commit_locked(true); - storage_check_flash_errors(svc_flash_lock()); -} - -static void storage_setNode(const HDNodeType *node) { - storageUpdate.node.depth = node->depth; - storageUpdate.node.fingerprint = node->fingerprint; - storageUpdate.node.child_num = node->child_num; - - storageUpdate.node.chain_code.size = 32; - memcpy(storageUpdate.node.chain_code.bytes, node->chain_code.bytes, 32); - - if (node->has_private_key) { - storageUpdate.node.has_private_key = true; - storageUpdate.node.private_key.size = 32; - memcpy(storageUpdate.node.private_key.bytes, node->private_key.bytes, 32); - } -} - -#if DEBUG_LINK -void storage_dumpNode(HDNodeType *node) { - node->depth = storageRom->node.depth; - node->fingerprint = storageRom->node.fingerprint; - node->child_num = storageRom->node.child_num; - - node->chain_code.size = 32; - memcpy(node->chain_code.bytes, storageRom->node.chain_code.bytes, 32); - - if (storageRom->node.has_private_key) { - node->has_private_key = true; - node->private_key.size = 32; - memcpy(node->private_key.bytes, storageRom->node.private_key.bytes, 32); - } -} -#endif - -void storage_loadDevice(const LoadDevice *msg) -{ - session_clear(true); - - storageUpdate.has_imported = true; - storageUpdate.imported = true; - - storage_setPin(msg->has_pin ? msg->pin : ""); - storage_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); - - if (msg->has_node) { - storageUpdate.has_node = true; - storageUpdate.has_mnemonic = false; - storage_setNode(&(msg->node)); - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - } else if (msg->has_mnemonic) { - storageUpdate.has_mnemonic = true; - storageUpdate.has_node = false; - strlcpy(storageUpdate.mnemonic, msg->mnemonic, sizeof(storageUpdate.mnemonic)); - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - } - - if (msg->has_language) { - storageUpdate.has_language = true; - strlcpy(storageUpdate.language, msg->language, sizeof(storageUpdate.language)); - } - - storage_setLabel(msg->has_label ? msg->label : ""); - - if (msg->has_u2f_counter) { - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter = msg->u2f_counter - storage_u2f_offset; - } - - storage_update(); -} - -void storage_setLabel(const char *label) -{ - storageUpdate.has_label = true; - if (!label) return; - strlcpy(storageUpdate.label, label, sizeof(storageUpdate.label)); -} - -void storage_setLanguage(const char *lang) -{ - if (!lang) return; - // sanity check - if (strcmp(lang, "english") == 0) { - storageUpdate.has_language = true; - strlcpy(storageUpdate.language, lang, sizeof(storageUpdate.language)); - } -} - -void storage_setPassphraseProtection(bool passphrase_protection) -{ - sessionSeedCached = false; - sessionPassphraseCached = false; - - storageUpdate.has_passphrase_protection = true; - storageUpdate.passphrase_protection = passphrase_protection; -} - -bool storage_hasPassphraseProtection(void) -{ - return storageRom->has_passphrase_protection && storageRom->passphrase_protection; -} - -void storage_setHomescreen(const uint8_t *data, uint32_t size) -{ - storageUpdate.has_homescreen = true; - if (data && size == 1024) { - memcpy(storageUpdate.homescreen.bytes, data, size); - storageUpdate.homescreen.size = size; - } else { - memzero(storageUpdate.homescreen.bytes, sizeof(storageUpdate.homescreen.bytes)); - storageUpdate.homescreen.size = 0; - } -} - -static void get_root_node_callback(uint32_t iter, uint32_t total) -{ - usbSleep(1); - layoutProgress(_("Waking up"), 1000 * iter / total); -} - -const uint8_t *storage_getSeed(bool usePassphrase) -{ - // root node is properly cached - if (usePassphrase == sessionSeedUsesPassphrase - && sessionSeedCached) { - return sessionSeed; - } - - // if storage has mnemonic, convert it to node and use it - if (storageRom->has_mnemonic) { - if (usePassphrase && !protectPassphrase()) { - return NULL; - } - // if storage was not imported (i.e. it was properly generated or recovered) - if (!storageRom->has_imported || !storageRom->imported) { - // test whether mnemonic is a valid BIP-0039 mnemonic - if (!mnemonic_check(storageRom->mnemonic)) { - // and if not then halt the device - storage_show_error(); - } - } - char oldTiny = usbTiny(1); - mnemonic_to_seed(storageRom->mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 - usbTiny(oldTiny); - sessionSeedCached = true; - sessionSeedUsesPassphrase = usePassphrase; - return sessionSeed; - } - - return NULL; -} - -static bool storage_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { - return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); -} - -bool storage_getU2FRoot(HDNode *node) -{ - return storageRom->has_u2froot && storage_loadNode(&storageRom->u2froot, NIST256P1_NAME, node); -} - -bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) -{ - // if storage has node, decrypt and use it - if (storageRom->has_node && strcmp(curve, SECP256K1_NAME) == 0) { - if (!protectPassphrase()) { - return false; - } - if (!storage_loadNode(&storageRom->node, curve, node)) { - return false; - } - if (storageRom->has_passphrase_protection && storageRom->passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { - // decrypt hd node - uint8_t secret[64]; - PBKDF2_HMAC_SHA512_CTX pctx; - char oldTiny = usbTiny(1); - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); - get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); - for (int i = 0; i < 8; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); - get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); - } - pbkdf2_hmac_sha512_Final(&pctx, secret); - usbTiny(oldTiny); - aes_decrypt_ctx ctx; - aes_decrypt_key256(secret, &ctx); - aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); - aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); - } - return true; - } - - const uint8_t *seed = storage_getSeed(usePassphrase); - if (seed == NULL) { - return false; - } - - return hdnode_from_seed(seed, 64, curve, node); -} - -const char *storage_getLabel(void) -{ - return storageRom->has_label ? storageRom->label : 0; -} - -const char *storage_getLanguage(void) -{ - return storageRom->has_language ? storageRom->language : 0; -} - -const uint8_t *storage_getHomescreen(void) -{ - return (storageRom->has_homescreen && storageRom->homescreen.size == 1024) ? storageRom->homescreen.bytes : 0; -} - -void storage_setMnemonic(const char *mnemonic) -{ - storageUpdate.has_mnemonic = true; - strlcpy(storageUpdate.mnemonic, mnemonic, sizeof(storageUpdate.mnemonic)); -} - -bool storage_hasNode(void) -{ - return storageRom->has_node; -} - -bool storage_hasMnemonic(void) -{ - return storageRom->has_mnemonic; -} - -const char *storage_getMnemonic(void) -{ - return storageUpdate.has_mnemonic ? storageUpdate.mnemonic - : storageRom->has_mnemonic ? storageRom->mnemonic : 0; -} - -/* Check whether mnemonic matches storage. The mnemonic must be - * a null-terminated string. - */ -bool storage_containsMnemonic(const char *mnemonic) { - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - for (; mnemonic[i]; i++) { - diff |= (storageRom->mnemonic[i] - mnemonic[i]); - } - diff |= storageRom->mnemonic[i]; - return diff == 0; -} - -/* Check whether pin matches storage. The pin must be - * a null-terminated string with at most 9 characters. - */ -bool storage_containsPin(const char *pin) -{ - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - while (pin[i]) { - diff |= storageRom->pin[i] - pin[i]; - i++; - } - diff |= storageRom->pin[i]; - return diff == 0; -} - -bool storage_hasPin(void) -{ - return storageRom->has_pin && storageRom->pin[0] != 0; -} - -void storage_setPin(const char *pin) -{ - storageUpdate.has_pin = true; - strlcpy(storageUpdate.pin, pin, sizeof(storageUpdate.pin)); - session_cachePin(); -} - -const char *storage_getPin(void) -{ - return storageRom->has_pin ? storageRom->pin : 0; -} - -void session_cachePassphrase(const char *passphrase) -{ - strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); - sessionPassphraseCached = true; -} - -bool session_isPassphraseCached(void) -{ - return sessionPassphraseCached; -} - -bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) -{ - if (!passphrase && !sessionPassphraseCached) { - return false; - } else { - passphrase = sessionPassphrase; - } - if (!salt) { - // if salt is not provided fill the first half of the state with random data - random_buffer(state, 32); - } else { - // if salt is provided fill the first half of the state with salt - memcpy(state, salt, 32); - } - // state[0:32] = salt - // state[32:64] = HMAC(passphrase, salt || device_id) - HMAC_SHA256_CTX ctx; - hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); - hmac_sha256_Update(&ctx, state, 32); - hmac_sha256_Update(&ctx, (const uint8_t *)storage_uuid, sizeof(storage_uuid)); - hmac_sha256_Final(&ctx, state + 32); - - memzero(&ctx, sizeof(ctx)); - - return true; -} - -void session_cachePin(void) -{ - sessionPinCached = true; -} - -void session_uncachePin(void) -{ - sessionPinCached = false; -} - -bool session_isPinCached(void) -{ - return sessionPinCached; -} - -void storage_clearPinArea(void) -{ - svc_flash_unlock(); - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - storage_check_flash_errors(svc_flash_lock()); - storage_u2f_offset = 0; -} - -// called when u2f area or pin area overflows -static void storage_area_recycle(uint32_t new_pinfails) -{ - // first clear storage marker. In case of a failure below it is better - // to clear the storage than to allow restarting with zero PIN failures - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(FLASH_STORAGE_START, 0); - if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_START) != 0) { - storage_show_error(); - } - - // erase pinarea/u2f sector - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - flash_write32(FLASH_STORAGE_PINAREA, new_pinfails); - if (*(const volatile uint32_t *)FLASH_PTR(FLASH_STORAGE_PINAREA) != new_pinfails) { - storage_show_error(); - } - - // restore storage sector - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter += storage_u2f_offset; - storage_u2f_offset = 0; - storage_commit_locked(true); -} - -void storage_resetPinFails(uint32_t flash_pinfails) -{ - svc_flash_unlock(); - if (flash_pinfails + sizeof(uint32_t) - >= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) { - // recycle extra storage sector - storage_area_recycle(0xffffffff); - } else { - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_pinfails, 0); - } - storage_check_flash_errors(svc_flash_lock()); -} - -bool storage_increasePinFails(uint32_t flash_pinfails) -{ - uint32_t newctr = *(const uint32_t*)FLASH_PTR(flash_pinfails) << 1; - // counter already at maximum, we do not increase it any more - // return success so that a good pin is accepted - if (!newctr) - return true; - - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_pinfails, newctr); - storage_check_flash_errors(svc_flash_lock()); - - return *(const uint32_t*)FLASH_PTR(flash_pinfails) == newctr; -} - -uint32_t storage_getPinWait(uint32_t flash_pinfails) -{ - // The pin failure word is the inverted wait time in seconds. - // It's inverted because flash allows changing 1 to 0 but not vice versa. - return ~*(const uint32_t*)FLASH_PTR(flash_pinfails); -} - -uint32_t storage_getPinFailsOffset(void) -{ - uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; - while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) - flash_pinfails += sizeof(uint32_t); - return flash_pinfails; -} - -bool storage_isInitialized(void) -{ - return storageRom->has_node || storageRom->has_mnemonic; -} - -bool storage_isImported(void) -{ - return storageRom->has_imported && storageRom->imported; -} - -void storage_setImported(bool imported) -{ - storageUpdate.has_imported = true; - storageUpdate.imported = imported; -} - -bool storage_needsBackup(void) -{ - return storageUpdate.has_needs_backup ? storageUpdate.needs_backup - : storageRom->has_needs_backup && storageRom->needs_backup; -} - -void storage_setNeedsBackup(bool needs_backup) -{ - storageUpdate.has_needs_backup = true; - storageUpdate.needs_backup = needs_backup; -} - -bool storage_unfinishedBackup(void) -{ - return storageUpdate.has_unfinished_backup ? storageUpdate.unfinished_backup - : storageRom->has_unfinished_backup && storageRom->unfinished_backup; -} - -void storage_setUnfinishedBackup(bool unfinished_backup) -{ - storageUpdate.has_unfinished_backup = true; - storageUpdate.unfinished_backup = unfinished_backup; -} - -bool storage_noBackup(void) -{ - return storageUpdate.has_no_backup ? storageUpdate.no_backup - : storageRom->has_no_backup && storageRom->no_backup; -} - -void storage_setNoBackup(void) -{ - storageUpdate.has_no_backup = true; - storageUpdate.no_backup = true; -} - -void storage_applyFlags(uint32_t flags) -{ - if ((storageRom->flags | flags) == storageRom->flags) { - return; // no new flags - } - storageUpdate.has_flags = true; - storageUpdate.flags |= flags; - storage_update(); -} - -uint32_t storage_getFlags(void) -{ - return storageRom->has_flags ? storageRom->flags : 0; -} - -uint32_t storage_nextU2FCounter(void) -{ - uint32_t flash_u2f_offset = FLASH_STORAGE_U2FAREA + - sizeof(uint32_t) * (storage_u2f_offset / 32); - uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31); - - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_u2f_offset, newval); - storage_u2f_offset++; - if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) { - storage_area_recycle(*(const uint32_t*) - FLASH_PTR(storage_getPinFailsOffset())); - } - storage_check_flash_errors(svc_flash_lock()); - return storageRom->u2f_counter + storage_u2f_offset; -} - -void storage_setU2FCounter(uint32_t u2fcounter) -{ - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter = u2fcounter - storage_u2f_offset; -} - -uint32_t storage_getAutoLockDelayMs() -{ - const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - return storageRom->has_auto_lock_delay_ms ? storageRom->auto_lock_delay_ms : default_delay_ms; -} - -void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) -{ - const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds - auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); - storageUpdate.has_auto_lock_delay_ms = true; - storageUpdate.auto_lock_delay_ms = auto_lock_delay_ms; -} - -void storage_wipe(void) -{ - session_clear(true); - storage_generate_uuid(); - - svc_flash_unlock(); - storage_commit_locked(false); - storage_check_flash_errors(svc_flash_lock()); - - storage_clearPinArea(); -} diff --git a/firmware/trezor.c b/firmware/trezor.c index 4d256eaece..30a9e3746d 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -23,7 +23,7 @@ #include "util.h" #include "usb.h" #include "setup.h" -#include "storage.h" +#include "config.h" #include "layout.h" #include "layout2.h" #include "rng.h" @@ -76,7 +76,7 @@ void check_lock_screen(void) // if homescreen is shown for too long if (layoutLast == layoutHome) { - if ((timer_ms() - system_millis_lock_start) >= storage_getAutoLockDelayMs()) { + if ((timer_ms() - system_millis_lock_start) >= config_getAutoLockDelayMs()) { // lock the screen session_clear(true); layoutScreensaver(); @@ -108,13 +108,13 @@ int main(void) #if DEBUG_LINK oledSetDebugLink(1); - storage_wipe(); + config_wipe(); #endif oledDrawBitmap(40, 0, &bmp_logo64); oledRefresh(); - storage_init(); + config_init(); layoutHome(); usbInit(); for (;;) { diff --git a/firmware/u2f.c b/firmware/u2f.c index 456ca3f147..048b52a15f 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -21,7 +21,7 @@ #include #include "debug.h" -#include "storage.h" +#include "config.h" #include "bip32.h" #include "layout2.h" #include "usb.h" @@ -460,7 +460,7 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; - if (!storage_getU2FRoot(&node)) { + if (!config_getU2FRoot(&node)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); return 0; @@ -546,7 +546,7 @@ void u2f_register(const APDU *a) static U2F_REGISTER_REQ last_req; const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; - if (!storage_isInitialized()) { + if (!config_isInitialized()) { send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } @@ -654,7 +654,7 @@ void u2f_authenticate(const APDU *a) const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; static U2F_AUTHENTICATE_REQ last_req; - if (!storage_isInitialized()) { + if (!config_isInitialized()) { send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } @@ -727,7 +727,7 @@ void u2f_authenticate(const APDU *a) U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf; - const uint32_t ctr = storage_nextU2FCounter(); + const uint32_t ctr = config_nextU2FCounter(); resp->flags = U2F_AUTH_FLAG_TUP; resp->ctr[0] = ctr >> 24 & 0xff; resp->ctr[1] = ctr >> 16 & 0xff; diff --git a/firmware/usb.c b/firmware/usb.c index a40ce122b2..9da00ea913 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -25,7 +25,7 @@ #include "debug.h" #include "messages.h" #include "u2f.h" -#include "storage.h" +#include "config.h" #include "util.h" #include "timer.h" @@ -56,7 +56,7 @@ #define USB_STRINGS \ X(MANUFACTURER, "SatoshiLabs") \ X(PRODUCT, "TREZOR") \ - X(SERIAL_NUMBER, storage_uuid_str) \ + X(SERIAL_NUMBER, config_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ X(INTERFACE_U2F, "TREZOR U2F Interface") \ diff --git a/flash.c b/flash.c new file mode 100644 index 0000000000..9b9482550b --- /dev/null +++ b/flash.c @@ -0,0 +1,137 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "common.h" +#include "flash.h" +#include "memory.h" +#include "supervise.h" + +static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { + [ 0] = 0x08000000, // - 0x08003FFF | 16 KiB + [ 1] = 0x08004000, // - 0x08007FFF | 16 KiB + [ 2] = 0x08008000, // - 0x0800BFFF | 16 KiB + [ 3] = 0x0800C000, // - 0x0800FFFF | 16 KiB + [ 4] = 0x08010000, // - 0x0801FFFF | 64 KiB + [ 5] = 0x08020000, // - 0x0803FFFF | 128 KiB + [ 6] = 0x08040000, // - 0x0805FFFF | 128 KiB + [ 7] = 0x08060000, // - 0x0807FFFF | 128 KiB + [ 8] = 0x08080000, // - 0x0809FFFF | 128 KiB + [ 9] = 0x080A0000, // - 0x080BFFFF | 128 KiB + [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB + [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB + [12] = 0x08100000, // last element - not a valid sector +}; + +static secbool flash_check_success(uint32_t status) +{ + return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; +} + +void flash_init(void) +{ +} + +secbool flash_unlock_write(void) +{ + svc_flash_unlock(); + return sectrue; +} + +secbool flash_lock_write(void) +{ + return flash_check_success(svc_flash_lock()); +} + +const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) +{ + if (sector >= FLASH_SECTOR_COUNT) { + return NULL; + } + const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset; + const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; + if (addr + size > next) { + return NULL; + } + return (const void *)addr; +} + +secbool flash_erase(uint8_t sector) +{ + ensure(flash_unlock_write(), NULL); + svc_flash_erase_sector(sector); + ensure(flash_lock_write(), NULL); + + // Check whether the sector was really deleted (contains only 0xFF). + const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) +{ + uint32_t address = (uint32_t)flash_get_address(sector, offset, 1); + if (address == 0) { + return secfalse; + } + + if ((*((uint8_t*)address) & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X8); + flash_write8(address, data); + + if (*((uint8_t*)address) != data) { + return secfalse; + } + + return sectrue; +} + +secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) +{ + uint32_t address = (uint32_t)flash_get_address(sector, offset, 4); + if (address == 0) { + return secfalse; + } + + if (offset % 4 != 0) { + return secfalse; + } + + if ((*((uint32_t*)address) & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(address, data); + + if (*((uint32_t*)address) != data) { + return secfalse; + } + + return sectrue; +} diff --git a/flash.h b/flash.h new file mode 100644 index 0000000000..f67ea88239 --- /dev/null +++ b/flash.h @@ -0,0 +1,47 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TREZORHAL_FLASH_H +#define TREZORHAL_FLASH_H + +#include +#include +#include "secbool.h" + +#define FLASH_SECTOR_COUNT 24 + +// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) +#ifndef STM32F427xx +#define FLASH_SR_RDERR 0 +#endif + +#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) + +void flash_init(void); + +secbool __wur flash_unlock_write(void); +secbool __wur flash_lock_write(void); + +const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size); + +secbool __wur flash_erase(uint8_t sector); +secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); +secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); + +#endif // TREZORHAL_FLASH_H diff --git a/norcow_config.h b/norcow_config.h new file mode 100644 index 0000000000..ba57dfb4b2 --- /dev/null +++ b/norcow_config.h @@ -0,0 +1,39 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NORCOW_CONFIG_H__ +#define __NORCOW_CONFIG_H__ + +#include "flash.h" + +#define NORCOW_SECTOR_COUNT 2 +#define NORCOW_SECTOR_SIZE (16*1024) +#define NORCOW_SECTORS {2, 3} + +/* + * The length of the sector header in bytes. The header is preserved between sector erasures. + */ +#define NORCOW_HEADER_LEN (0x100) + +/* + * Current storage version. + */ +#define NORCOW_VERSION ((uint32_t)0x00000001) + +#endif diff --git a/secbool.h b/secbool.h new file mode 100644 index 0000000000..76dfb38dc1 --- /dev/null +++ b/secbool.h @@ -0,0 +1,33 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TREZORHAL_SECBOOL_H +#define TREZORHAL_SECBOOL_H + +#include + +typedef uint32_t secbool; +#define sectrue 0xAAAAAAAAU +#define secfalse 0x00000000U + +#ifndef __wur +#define __wur __attribute__ ((warn_unused_result)) +#endif + +#endif diff --git a/vendor/trezor-storage b/vendor/trezor-storage new file mode 160000 index 0000000000..840f7461ee --- /dev/null +++ b/vendor/trezor-storage @@ -0,0 +1 @@ +Subproject commit 840f7461ee6f0c5cb0db75c46018615dbd5b0256 From d970597ddd41f41fa7cb0e68c76b260f2cf70e3e Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 17:33:32 +0100 Subject: [PATCH 1073/1154] Fix emulator memory access. --- emulator/Makefile | 2 +- emulator/{flash.c => memory.c} | 0 flash.c | 24 ++++++++++++------------ flash.h | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) rename emulator/{flash.c => memory.c} (100%) diff --git a/emulator/Makefile b/emulator/Makefile index 1f2976dd01..1243a7fe54 100644 --- a/emulator/Makefile +++ b/emulator/Makefile @@ -3,7 +3,7 @@ EMULATOR := 1 OBJS += setup.o OBJS += buttons.o -OBJS += flash.o +OBJS += memory.o OBJS += oled.o OBJS += rng.o OBJS += timer.o diff --git a/emulator/flash.c b/emulator/memory.c similarity index 100% rename from emulator/flash.c rename to emulator/memory.c diff --git a/flash.c b/flash.c index 9b9482550b..998219c0b0 100644 --- a/flash.c +++ b/flash.c @@ -71,7 +71,7 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) if (addr + size > next) { return NULL; } - return (const void *)addr; + return (const void *) FLASH_PTR(addr); } secbool flash_erase(uint8_t sector) @@ -83,7 +83,7 @@ secbool flash_erase(uint8_t sector) // Check whether the sector was really deleted (contains only 0xFF). const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { return secfalse; } } @@ -92,19 +92,19 @@ secbool flash_erase(uint8_t sector) secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) { - uint32_t address = (uint32_t)flash_get_address(sector, offset, 1); - if (address == 0) { + uint8_t *address = (uint8_t *) flash_get_address(sector, offset, 1); + if (address == NULL) { return secfalse; } - if ((*((uint8_t*)address) & data) != data) { + if ((*address & data) != data) { return secfalse; } svc_flash_program(FLASH_CR_PROGRAM_X8); - flash_write8(address, data); + *(volatile uint8_t *) address = data; - if (*((uint8_t*)address) != data) { + if (*address != data) { return secfalse; } @@ -113,8 +113,8 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) { - uint32_t address = (uint32_t)flash_get_address(sector, offset, 4); - if (address == 0) { + uint32_t *address = (uint32_t *) flash_get_address(sector, offset, 4); + if (address == NULL) { return secfalse; } @@ -122,14 +122,14 @@ secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) return secfalse; } - if ((*((uint32_t*)address) & data) != data) { + if ((*address & data) != data) { return secfalse; } svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(address, data); + *(volatile uint32_t *) address = data; - if (*((uint32_t*)address) != data) { + if (*address != data) { return secfalse; } diff --git a/flash.h b/flash.h index f67ea88239..24e1a3ad64 100644 --- a/flash.h +++ b/flash.h @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_FLASH_H -#define TREZORHAL_FLASH_H +#ifndef FLASH_H +#define FLASH_H #include #include @@ -44,4 +44,4 @@ secbool __wur flash_erase(uint8_t sector); secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); -#endif // TREZORHAL_FLASH_H +#endif // FLASH_H From b8932205cec416d6fa3ee2a1a5b911b47d0ed939 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 17:55:20 +0100 Subject: [PATCH 1074/1154] Update trezor-storage. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 840f7461ee..2888c11095 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 840f7461ee6f0c5cb0db75c46018615dbd5b0256 +Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b From 681137c2eff61fdce56b95714e5ca26b702d5a19 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 18:31:10 +0100 Subject: [PATCH 1075/1154] Unlock for testing. --- firmware/config.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 7799f1ff81..4af3e381af 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -342,6 +342,8 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + storage_unlock(1); + uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); @@ -432,9 +434,6 @@ void config_dumpNode(HDNodeType *node) void config_loadDevice(const LoadDevice *msg) { - session_clear(true); - // TODO We can't set anything with the storage locked. Shouldn't we wipe? - config_set_bool(KEY_IMPORTED, true); config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); @@ -459,6 +458,8 @@ void config_loadDevice(const LoadDevice *msg) if (msg->has_u2f_counter) { config_setU2FCounter(msg->u2f_counter); } + + session_clear(true); } void config_setLabel(const char *label) From 679174ea7a26243765b3e795088866183e965de7 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 1 Feb 2019 15:47:52 +0100 Subject: [PATCH 1076/1154] Fix separated backup. Fix forgotten config_getMnemonic() in DEBUG_LINK build. --- firmware/fsm_msg_debug.h | 2 +- firmware/reset.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 788bb5fb8d..307066a3d0 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -54,7 +54,7 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) if (config_hasMnemonic()) { resp.has_mnemonic = true; - strlcpy(resp.mnemonic, config_getMnemonic(), sizeof(resp.mnemonic)); + config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); } if (config_hasNode()) { diff --git a/firmware/reset.c b/firmware/reset.c index df6bc83612..0765fe595f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -106,7 +106,6 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memzero(int_entropy, 32); awaiting_entropy = false; - if (skip_backup || no_backup) { if (no_backup) { config_setNoBackup(); @@ -127,7 +126,7 @@ static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage void reset_backup(bool separated, const char* mnemonic) { - if (!config_needsBackup()) { + if (separated && !config_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } From a7fcf9b036f648e30fcd71e88187e98986794458 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 1 Feb 2019 21:02:43 +0100 Subject: [PATCH 1077/1154] Fix key constant in config_setLanguage(). Update trezor-storage. --- firmware/config.c | 2 +- vendor/trezor-storage | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 4af3e381af..4259938a4b 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -481,7 +481,7 @@ void config_setLanguage(const char *lang) if (strcmp(lang, "english") != 0) { return; } - storage_set(KEY_LABEL, lang, strnlen(lang, MAX_LANGUAGE_LEN)); + storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN)); } void config_setPassphraseProtection(bool passphrase_protection) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 2888c11095..8fc03a5a95 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b +Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b From d433401311807305fde7a1fdf4aa6787e99941c8 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 4 Feb 2019 17:57:53 +0100 Subject: [PATCH 1078/1154] Update trezor-storage. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 8fc03a5a95..6d9a4962a4 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b +Subproject commit 6d9a4962a427717100517d59a4dcc1012199f0f5 From 247337c63d587b7bc08490d0ce6227e0f8dc9539 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 5 Feb 2019 11:57:19 +0100 Subject: [PATCH 1079/1154] Do not lock after wipe. Fix protectPinUiCallback() to correctly display '0 seconds' when wait is 0. --- firmware/config.c | 3 ++- firmware/protect.c | 4 ++-- firmware/recovery.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 4259938a4b..520effd2a0 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -342,6 +342,7 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + // TODO Remove storage_unlock(1); uint16_t len = 0; @@ -851,5 +852,5 @@ void config_wipe(void) data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); - session_clear(true); + session_clear(false); } diff --git a/firmware/protect.c b/firmware/protect.c index 43acf4ea87..0d416c41ec 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -155,11 +155,11 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) char secstrbuf[] = _("________0 seconds"); char *secstr = secstrbuf + 9; uint32_t secs = wait; - while (secs > 0 && secstr >= secstrbuf) { + do { secstr--; *secstr = (secs % 10) + '0'; secs /= 10; - } + } while (secs > 0 && secstr >= secstrbuf); if (wait == 1) { // Change "seconds" to "second". secstrbuf[16] = 0; diff --git a/firmware/recovery.c b/firmware/recovery.c index d5c7acd088..c12dda3afa 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -153,7 +153,7 @@ static void recovery_request(void) { * Check mnemonic and send success/failure. */ static void recovery_done(void) { - char new_mnemonic[241] = {0}; // TODO: remove constant + char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0}; strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); for (uint32_t i = 1; i < word_count; i++) { From e49e84ea5a95b4801b6211c37cbdabca09ff1019 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 5 Feb 2019 20:40:58 +0100 Subject: [PATCH 1080/1154] Reorder storage keys in config.c to correspond with trezor-core and add KEY_INITIALIZED. Add CHECK_PIN to fsm_msgApplyFlags() and to other fsm_msg functions in order to unlock storage. Improve error handling in reset.c and recovery.c. --- firmware/config.c | 57 +++++++++++++++++++++++++-------------- firmware/config.h | 2 +- firmware/fsm_msg_common.h | 14 +++++++--- firmware/protect.c | 13 +++++---- firmware/recovery.c | 15 ++++++----- firmware/reset.c | 17 ++++++++---- 6 files changed, 77 insertions(+), 41 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 520effd2a0..980d130585 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -53,20 +53,21 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) static const uint16_t KEY_VERSION = 1 | APP; // uint32 -static const uint16_t KEY_NODE = 2 | APP; // node -static const uint16_t KEY_MNEMONIC = 3 | APP; // string(241) -static const uint16_t KEY_PASSPHRASE_PROTECTION = 4 | APP; // bool -static const uint16_t KEY_LANGUAGE = 5 | APP | FLAG_PUBLIC; // string(17) -static const uint16_t KEY_LABEL = 6 | APP | FLAG_PUBLIC; // string(33) -static const uint16_t KEY_IMPORTED = 7 | APP; // bool -static const uint16_t KEY_HOMESCREEN = 8 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_MNEMONIC = 2 | APP; // string(241) +static const uint16_t KEY_LANGUAGE = 3 | APP | FLAG_PUBLIC; // string(17) +static const uint16_t KEY_LABEL = 4 | APP | FLAG_PUBLIC; // string(33) +static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // bool +static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool +static const uint16_t KEY_FLAGS = 8 | APP; // uint32 static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 -static const uint16_t KEY_NEEDS_BACKUP = 10 | APP; // bool -static const uint16_t KEY_FLAGS = 11 | APP; // uint32 -static const uint16_t KEY_U2F_ROOT = 12 | APP; // node -static const uint16_t KEY_UNFINISHED_BACKUP = 13 | APP; // bool -static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 14 | APP; // uint32 -static const uint16_t KEY_NO_BACKUP = 15 | APP; // bool +static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool +static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 +static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool +static const uint16_t KEY_INITIALIZED = 14 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_NODE = 15 | APP; // node +static const uint16_t KEY_IMPORTED = 16 | APP; // bool +static const uint16_t KEY_U2F_ROOT = 17 | APP | FLAG_PUBLIC; // node // The PIN value corresponding to an empty PIN. static const uint32_t PIN_EMPTY = 1; @@ -290,7 +291,9 @@ static bool config_upgrade_v10(void) storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); if (config.has_node) { - storage_set(KEY_NODE, &config.node, sizeof(config.node)); + if (sectrue == storage_set(KEY_NODE, &config.node, sizeof(config.node))) { + config_set_bool(KEY_INITIALIZED, true); + } } if (config.has_mnemonic) { config_setMnemonic(config.mnemonic); @@ -402,7 +405,9 @@ static void config_setNode(const HDNodeType *node) { storageHDNode.private_key.size = 32; memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); } - storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode)); + if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { + config_set_bool(KEY_INITIALIZED, true); + } } #if DEBUG_LINK @@ -628,21 +633,33 @@ bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) return true; } -void config_setMnemonic(const char *mnemonic) +bool config_setMnemonic(const char *mnemonic) { if (mnemonic == NULL) { - return; + return false; } if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { - return; + return false; + } + + if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { + storage_delete(KEY_MNEMONIC); + return false; } StorageHDNode u2fNode; memzero(&u2fNode, sizeof(u2fNode)); config_compute_u2froot(mnemonic, &u2fNode); - storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); + secbool ret = storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); memzero(&u2fNode, sizeof(u2fNode)); + + if (sectrue != ret) { + storage_delete(KEY_MNEMONIC); + storage_delete(KEY_INITIALIZED); + return false; + } + return true; } bool config_hasNode(void) @@ -756,7 +773,7 @@ bool session_isPinCached(void) bool config_isInitialized(void) { - return config_has_key(KEY_NODE) || config_has_key(KEY_MNEMONIC); + return config_get_bool(KEY_INITIALIZED); } bool config_isImported(void) diff --git a/firmware/config.h b/firmware/config.h index 8bde314da0..a44b6f29f3 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -111,7 +111,7 @@ void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); -void config_setMnemonic(const char *mnemonic); +bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); bool config_hasMnemonic(void); bool config_getMnemonic(char *dest, uint16_t dest_size); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 25fef38382..93e2d8abcd 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -63,7 +63,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) } resp->has_initialized = true; resp->initialized = config_isInitialized(); - resp->has_imported = true; resp->imported = config_isImported(); + resp->has_imported = config_hasKey(KEY_IMPORTED); resp->imported = config_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); @@ -180,6 +180,8 @@ void fsm_msgGetEntropy(const GetEntropy *msg) void fsm_msgLoadDevice(const LoadDevice *msg) { + CHECK_PIN + CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); @@ -204,6 +206,8 @@ void fsm_msgLoadDevice(const LoadDevice *msg) void fsm_msgResetDevice(const ResetDevice *msg) { + CHECK_PIN + CHECK_NOT_INITIALIZED CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); @@ -331,6 +335,8 @@ void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) { + CHECK_PIN + if (msg->has_flags) { config_applyFlags(msg->flags); } @@ -339,10 +345,10 @@ void fsm_msgApplyFlags(const ApplyFlags *msg) void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { + CHECK_PIN + const bool dry_run = msg->has_dry_run ? msg->dry_run : false; - if (dry_run) { - CHECK_PIN - } else { + if (!dry_run) { CHECK_NOT_INITIALIZED } diff --git a/firmware/protect.c b/firmware/protect.c index 0d416c41ec..423c2fd985 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -180,17 +180,20 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) bool protectPin(bool use_cached) { - if (!config_hasPin() || (use_cached && session_isPinCached())) { + if (use_cached && session_isPinCached()) { return true; } // TODO If maximum number of PIN attempts: // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); - const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; + const char *pin = ""; + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } } usbTiny(1); diff --git a/firmware/recovery.c b/firmware/recovery.c index c12dda3afa..f7e5460fc8 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -164,13 +164,16 @@ static void recovery_done(void) { // New mnemonic is valid. if (!dry_run) { // Update mnemonic on config. - config_setMnemonic(new_mnemonic); - memzero(new_mnemonic, sizeof(new_mnemonic)); - if (!enforce_wordlist) { - // not enforcing => mark config as imported - config_setImported(true); + if (config_setMnemonic(new_mnemonic)) { + if (!enforce_wordlist) { + // not enforcing => mark config as imported + config_setImported(true); + } + fsm_sendSuccess(_("Device recovered")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); } - fsm_sendSuccess(_("Device recovered")); + memzero(new_mnemonic, sizeof(new_mnemonic)); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); diff --git a/firmware/reset.c b/firmware/reset.c index 0765fe595f..58479ab2ee 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -97,6 +97,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } + awaiting_entropy = false; + SHA256_CTX ctx; sha256_Init(&ctx); sha256_Update(&ctx, int_entropy, 32); @@ -104,7 +106,6 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Final(&ctx, int_entropy); const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); memzero(int_entropy, 32); - awaiting_entropy = false; if (skip_backup || no_backup) { if (no_backup) { @@ -112,8 +113,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) } else { config_setNeedsBackup(true); } - config_setMnemonic(mnemonic); - fsm_sendSuccess(_("Device successfully initialized")); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } layoutHome(); } else { reset_backup(false, mnemonic); @@ -169,8 +173,11 @@ void reset_backup(bool separated, const char* mnemonic) fsm_sendSuccess(_("Seed successfully backed up")); } else { config_setNeedsBackup(false); - config_setMnemonic(mnemonic); - fsm_sendSuccess(_("Device successfully initialized")); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } } layoutHome(); } From 03e9ea4f5cd7f216e2c27da3e3acb6b0947a2e35 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 6 Feb 2019 19:01:06 +0100 Subject: [PATCH 1081/1154] Support interruption of the PIN wait dialog by Cancel and Initialize messages. --- firmware/config.c | 5 +---- firmware/protect.c | 15 ++++++++------- firmware/protect.h | 3 ++- vendor/trezor-storage | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 980d130585..0ba7ab7816 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -345,9 +345,6 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); - // TODO Remove - storage_unlock(1); - uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); @@ -643,7 +640,7 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { + if (!config_set_bool(KEY_INITIALIZED, true)) { storage_delete(KEY_MNEMONIC); return false; } diff --git a/firmware/protect.c b/firmware/protect.c index 423c2fd985..e322c3fe6d 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -147,7 +147,7 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } -void protectPinUiCallback(uint32_t wait, uint32_t progress) +secbool protectPinUiCallback(uint32_t wait, uint32_t progress) { (void) progress; @@ -166,16 +166,17 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) } layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - /* TODO - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = false; - protectAbortedByInitialize = true; + // Check for Cancel / Initialize. + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { msg_tiny_id = 0xFFFF; usbTiny(0); fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; + return sectrue; } - */ + + return secfalse; } bool protectPin(bool use_cached) diff --git a/firmware/protect.h b/firmware/protect.h index eaf1782762..bcabdac674 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -22,9 +22,10 @@ #include #include "messages-common.pb.h" +#include "secbool.h" bool protectButton(ButtonRequestType type, bool confirm_only); -void protectPinUiCallback(uint32_t wait, uint32_t progress); +secbool protectPinUiCallback(uint32_t wait, uint32_t progress); bool protectPin(bool use_cached); bool protectChangePin(bool removal); bool protectPassphrase(void); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 6d9a4962a4..4429888b93 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 6d9a4962a427717100517d59a4dcc1012199f0f5 +Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 From 5d4fb5556196c688713b49e69d9791a819663985 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 6 Feb 2019 19:02:51 +0100 Subject: [PATCH 1082/1154] Improve __fatal_error() layout. --- common.c | 65 +++++++++++++++++++++++++++++++++++--------------------- common.h | 2 +- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/common.c b/common.c index 5a8c0c1cc5..8489e02b8c 100644 --- a/common.c +++ b/common.c @@ -21,34 +21,51 @@ #include "common.h" #include "rng.h" #include "layout.h" +#include "oled.h" #include "firmware/usb.h" -void shutdown(void); - -void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { - char line[4][128] = {{0}}; - int i = 0; - if (expr != NULL) { - snprintf(line[i], sizeof(line[0]), "Expr: %s", expr); - i++; - } - if (msg != NULL) { - snprintf(line[i], sizeof(line[0]), "Msg: %s", msg); - i++; - } - if (file != NULL) { - snprintf(line[i], sizeof(line[0]), "File: %s:%d", file, line_num); - i++; - } - if (func != NULL) { - snprintf(line[i], sizeof(line[0]), "Func: %s", func); - i++; - } - error_shutdown("FATAL ERROR:", NULL, line[0], line[1], line[2], line[3]); +static void __attribute__((noreturn)) shutdown(void) +{ + for (;;); } -void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, line5, line6); +void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { + const BITMAP *icon = &bmp_icon_error; + char line[128] = {0}; + int y = icon->height + 3; + oledClear(); + + oledDrawBitmap(0, 0, icon); + oledDrawStringCenter((icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); + + snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + snprintf(line, sizeof(line), "Msg: %s", msg ? msg : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + const char *label = "File: "; + snprintf(line, sizeof(line), "%s:%d", file ? file : "(null)", line_num); + oledDrawStringRight(OLED_WIDTH - 1, y, line, FONT_STANDARD); + oledBox(0, y, oledStringWidth(label, FONT_STANDARD), y + FONT_HEIGHT, false); + oledDrawString(0, y, label, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + snprintf(line, sizeof(line), "Func: %s", func ? func : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + oledDrawString(0, y, "Please unplug the device.", FONT_STANDARD); + oledRefresh(); + + shutdown(); + for (;;); +} + +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, "Please unplug", "the device."); shutdown(); for (;;); } diff --git a/common.h b/common.h index b89547a378..9ac0a13c1c 100644 --- a/common.h +++ b/common.h @@ -34,7 +34,7 @@ #endif void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); -void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); #define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) From 7b0f5e031d7344ebc27448a58613e4ee745c4764 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 16:06:07 +0100 Subject: [PATCH 1083/1154] config: Change config_get*() functions to return status of the get operation. --- common.h | 10 ----- firmware/config.c | 84 ++++++++++++++++++++++----------------- firmware/config.h | 12 +++--- firmware/fsm_msg_common.h | 22 ++++------ firmware/fsm_msg_debug.h | 8 +--- firmware/layout2.c | 15 ++++--- firmware/protect.c | 4 +- firmware/reset.c | 12 +++--- norcow_config.h | 2 +- vendor/trezor-storage | 2 +- 10 files changed, 86 insertions(+), 85 deletions(-) diff --git a/common.h b/common.h index 9ac0a13c1c..9a40d000f7 100644 --- a/common.h +++ b/common.h @@ -23,16 +23,6 @@ #include #include "secbool.h" -#define XSTR(s) STR(s) -#define STR(s) #s - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); diff --git a/firmware/config.c b/firmware/config.c index 0ba7ab7816..aeda096afb 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -23,6 +23,7 @@ #include "messages.pb.h" +#include "common.h" #include "trezor.h" #include "sha2.h" #include "aes/aes.h" @@ -147,12 +148,17 @@ static bool config_set_bool(uint16_t key, bool value) } } -static bool config_get_bool(uint16_t key) +static bool config_get_bool(uint16_t key, bool *value) { - uint8_t value = 0; + uint8_t val = 0; uint16_t len = 0; - secbool ret = storage_get(key, &value, sizeof(value), &len); - return (sectrue == ret && len == 1 && value == TRUE_BYTE); + if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { + *value = (val == TRUE_BYTE); + return true; + } else { + *value = false; + return false; + } } static bool config_has_key(uint16_t key) @@ -161,7 +167,8 @@ static bool config_has_key(uint16_t key) return sectrue == storage_get(key, NULL, 0, &len); } -static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { +static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) +{ dest[0] = '\0'; uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { @@ -171,19 +178,14 @@ static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { return true; } -static uint32_t config_get_uint32(uint16_t key) { - uint32_t value = 0; - uint16_t len = 0; - if (sectrue != storage_get(key, &value, sizeof(value), &len) || len != sizeof(value)) { - return 0; - } - return value; -} - -void config_show_error(void) +static bool config_get_uint32(uint16_t key, uint32_t *value) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); - shutdown(); + uint16_t len = 0; + if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { + *value = 0; + return false; + } + return true; } static bool config_upgrade_v10(void) @@ -494,9 +496,9 @@ void config_setPassphraseProtection(bool passphrase_protection) config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } -bool config_hasPassphraseProtection(void) +bool config_getPassphraseProtection(bool *passphrase_protection) { - return config_get_bool(KEY_PASSPHRASE_PROTECTION); + return config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } void config_setHomescreen(const uint8_t *data, uint32_t size) @@ -530,11 +532,13 @@ const uint8_t *config_getSeed(bool usePassphrase) return NULL; } // if storage was not imported (i.e. it was properly generated or recovered) - if (!config_get_bool(KEY_IMPORTED)) { + bool imported = false; + config_get_bool(KEY_IMPORTED, &imported); + if (!imported) { // test whether mnemonic is a valid BIP-0039 mnemonic if (!mnemonic_check(mnemonic)) { // and if not then halt the device - config_show_error(); + error_shutdown(_("Storage failure"), _("detected."), NULL, NULL); } } char oldTiny = usbTiny(1); @@ -580,7 +584,9 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) memzero(&storageHDNode, sizeof(storageHDNode)); return false; } - if (config_hasPassphraseProtection() && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (passphrase_protection && sessionPassphraseCached && sessionPassphrase[0] != '\0') { // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; @@ -770,12 +776,14 @@ bool session_isPinCached(void) bool config_isInitialized(void) { - return config_get_bool(KEY_INITIALIZED); + bool initialized = false; + config_get_bool(KEY_INITIALIZED, &initialized); + return initialized; } -bool config_isImported(void) +bool config_getImported(bool* imported) { - return config_get_bool(KEY_IMPORTED); + return config_get_bool(KEY_IMPORTED, imported); } void config_setImported(bool imported) @@ -783,9 +791,9 @@ void config_setImported(bool imported) config_set_bool(KEY_IMPORTED, imported); } -bool config_needsBackup(void) +bool config_getNeedsBackup(bool *needs_backup) { - return config_get_bool(KEY_NEEDS_BACKUP); + return config_get_bool(KEY_NEEDS_BACKUP, needs_backup); } void config_setNeedsBackup(bool needs_backup) @@ -793,9 +801,9 @@ void config_setNeedsBackup(bool needs_backup) config_set_bool(KEY_NEEDS_BACKUP, needs_backup); } -bool config_unfinishedBackup(void) +bool config_getUnfinishedBackup(bool *unfinished_backup) { - return config_get_bool(KEY_UNFINISHED_BACKUP); + return config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } void config_setUnfinishedBackup(bool unfinished_backup) @@ -803,9 +811,9 @@ void config_setUnfinishedBackup(bool unfinished_backup) config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } -bool config_noBackup(void) +bool config_getNoBackup(bool *no_backup) { - return config_get_bool(KEY_NO_BACKUP); + return config_get_bool(KEY_NO_BACKUP, no_backup); } void config_setNoBackup(void) @@ -815,7 +823,8 @@ void config_setNoBackup(void) void config_applyFlags(uint32_t flags) { - uint32_t old_flags = config_get_uint32(KEY_FLAGS); + uint32_t old_flags = 0; + config_get_uint32(KEY_FLAGS, &old_flags); flags |= old_flags; if (flags == old_flags) { return; // no new flags @@ -823,9 +832,9 @@ void config_applyFlags(uint32_t flags) storage_set(KEY_FLAGS, &flags, sizeof(flags)); } -uint32_t config_getFlags(void) +bool config_getFlags(uint32_t *flags) { - return config_get_uint32(KEY_FLAGS); + return config_get_uint32(KEY_FLAGS, flags); } uint32_t config_nextU2FCounter(void) @@ -847,8 +856,11 @@ void config_setU2FCounter(uint32_t u2fcounter) uint32_t config_getAutoLockDelayMs() { const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - uint32_t delay_ms = config_get_uint32(KEY_AUTO_LOCK_DELAY_MS); - return (delay_ms != 0) ? delay_ms : default_delay_ms; + uint32_t delay_ms = 0; + if (config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &delay_ms)) { + return delay_ms; + } + return default_delay_ms; } void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) diff --git a/firmware/config.h b/firmware/config.h index a44b6f29f3..b015ca78f9 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -102,7 +102,7 @@ bool config_getLanguage(char *dest, uint16_t dest_size); void config_setLanguage(const char *lang); void config_setPassphraseProtection(bool passphrase_protection); -bool config_hasPassphraseProtection(void); +bool config_getPassphraseProtection(bool *passphrase_protection); bool config_getHomescreen(uint8_t *dest, uint16_t dest_size); void config_setHomescreen(const uint8_t *data, uint32_t size); @@ -132,20 +132,20 @@ void config_setU2FCounter(uint32_t u2fcounter); bool config_isInitialized(void); -bool config_isImported(void); +bool config_getImported(bool *imported); void config_setImported(bool imported); -bool config_needsBackup(void); +bool config_getNeedsBackup(bool *needs_backup); void config_setNeedsBackup(bool needs_backup); -bool config_unfinishedBackup(void); +bool config_getUnfinishedBackup(bool *unfinished_backup); void config_setUnfinishedBackup(bool unfinished_backup); -bool config_noBackup(void); +bool config_getNoBackup(bool *no_backup); void config_setNoBackup(void); void config_applyFlags(uint32_t flags); -uint32_t config_getFlags(void); +bool config_getFlags(uint32_t *flags); uint32_t config_getAutoLockDelayMs(void); void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 93e2d8abcd..aa906423f7 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -47,29 +47,23 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); - resp->has_passphrase_protection = true; resp->passphrase_protection = config_hasPassphraseProtection(); + resp->has_passphrase_protection = config_getPassphraseProtection(&(resp->passphrase_protection)); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (config_getLanguage(resp->language, sizeof(resp->language))) { - resp->has_language = true; - } - - if (config_getLabel(resp->label, sizeof(resp->label))) { - resp->has_label = true; - } - + resp->has_language = config_getLanguage(resp->language, sizeof(resp->language)); + resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_initialized = true; resp->initialized = config_isInitialized(); - resp->has_imported = config_hasKey(KEY_IMPORTED); resp->imported = config_isImported(); + resp->has_imported = config_getImported(&(resp->imported)); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); - resp->has_unfinished_backup = true; resp->unfinished_backup = config_unfinishedBackup(); - resp->has_no_backup = true; resp->no_backup = config_noBackup(); - resp->has_flags = true; resp->flags = config_getFlags(); + resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); + resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); + resp->has_no_backup = config_getNoBackup(&(resp->no_backup)); + resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 307066a3d0..0ef38279f6 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -52,18 +52,14 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - if (config_hasMnemonic()) { - resp.has_mnemonic = true; - config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); - } + resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); if (config_hasNode()) { resp.has_node = true; config_dumpNode(&(resp.node)); } - resp.has_passphrase_protection = true; - resp.passphrase_protection = config_hasPassphraseProtection(); + resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 98474de615..36e02829f5 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -256,15 +256,20 @@ void layoutHome(void) oledDrawBitmap(40, 0, &bmp_logo64); } } - if (config_noBackup()) { + + bool no_backup = false; + bool unfinished_backup = false; + bool needs_backup = false; + config_getNoBackup(&no_backup); + config_getUnfinishedBackup(&unfinished_backup); + config_getNeedsBackup(&needs_backup); + if (no_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); - } else - if (config_unfinishedBackup()) { + } else if (unfinished_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); - } else - if (config_needsBackup()) { + } else if (needs_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); } diff --git a/firmware/protect.c b/firmware/protect.c index e322c3fe6d..f048eb45a5 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -259,7 +259,9 @@ bool protectChangePin(bool removal) bool protectPassphrase(void) { - if (!config_hasPassphraseProtection() || session_isPassphraseCached()) { + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (!passphrase_protection || session_isPassphraseCached()) { return true; } diff --git a/firmware/reset.c b/firmware/reset.c index 58479ab2ee..8fa650c443 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -130,12 +130,14 @@ static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage void reset_backup(bool separated, const char* mnemonic) { - if (separated && !config_needsBackup()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); - return; - } - if (separated) { + bool needs_backup = false; + config_getNeedsBackup(&needs_backup); + if (!needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + return; + } + config_setUnfinishedBackup(true); config_setNeedsBackup(false); } diff --git a/norcow_config.h b/norcow_config.h index ba57dfb4b2..d78f0749e5 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -29,7 +29,7 @@ /* * The length of the sector header in bytes. The header is preserved between sector erasures. */ -#define NORCOW_HEADER_LEN (0x100) +#define NORCOW_HEADER_LEN (0x000) /* * Current storage version. diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 4429888b93..0497802014 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 +Subproject commit 0497802014edf03cdcce8cb70889d5a6e0bd3361 From c592a09459050281cbf9e30c57488cfed92b8f05 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 16:27:03 +0100 Subject: [PATCH 1084/1154] protect.c: Display 'Verifying PIN' instead of 'Wrong PIN entered' in the PIN_UI_WAIT_CALLBACK. --- firmware/protect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protect.c b/firmware/protect.c index f048eb45a5..2f961bb8c0 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -164,7 +164,7 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) // Change "seconds" to "second". secstrbuf[16] = 0; } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); // Check for Cancel / Initialize. protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); From 66ffa4c7dc1010392fdeabee7c22234016e82abe Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 00:46:16 +0100 Subject: [PATCH 1085/1154] config: Add hardware entropy to storage_init(). --- common.c | 2 ++ common.h | 3 +++ firmware/config.c | 6 ++---- firmware/trezor.c | 10 ++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/common.c b/common.c index 8489e02b8c..7d019ec310 100644 --- a/common.c +++ b/common.c @@ -24,6 +24,8 @@ #include "oled.h" #include "firmware/usb.h" +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + static void __attribute__((noreturn)) shutdown(void) { for (;;); diff --git a/common.h b/common.h index 9a40d000f7..912f73c54d 100644 --- a/common.h +++ b/common.h @@ -23,6 +23,9 @@ #include #include "secbool.h" +#define HW_ENTROPY_LEN 12 +extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); diff --git a/firmware/config.c b/firmware/config.c index aeda096afb..af55fccf15 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -279,8 +279,7 @@ static bool config_upgrade_v10(void) } } - // TODO Add salt. - storage_init(NULL, (const uint8_t*)"", 0); + storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); storage_unlock(PIN_EMPTY); if (config.has_pin) { storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); @@ -344,8 +343,7 @@ void config_init(void) { config_upgrade_v10(); - // TODO Add salt. - storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { diff --git a/firmware/trezor.c b/firmware/trezor.c index 30a9e3746d..fd59578025 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -17,6 +17,7 @@ * along with this library. If not, see . */ +#include "common.h" #include "trezor.h" #include "oled.h" #include "bitmaps.h" @@ -31,6 +32,8 @@ #include "buttons.h" #include "gettext.h" #include "bl_check.h" +#include "memzero.h" +#include /* Screen timeout */ uint32_t system_millis_lock_start; @@ -86,6 +89,13 @@ void check_lock_screen(void) int main(void) { +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); + HW_ENTROPY_DATA[0] = 1; +#else + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); +#endif + #ifndef APPVER setup(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks From ae48b528a9497f6b5e877720ae5f68438bd1dfaf Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:08:55 +0100 Subject: [PATCH 1086/1154] config: Rename session_isPinCached() to session_isUnlocked(). Change GetFeatures to always return pin_cached=false if PIN is not set, in order to maintain the same behavior as before. --- firmware/config.c | 2 +- firmware/config.h | 2 +- firmware/fsm_msg_common.h | 2 +- firmware/protect.c | 5 +---- firmware/trezor.c | 1 - 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index af55fccf15..8e52a29183 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -767,7 +767,7 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras return true; } -bool session_isPinCached(void) +bool session_isUnlocked(void) { return storage_is_unlocked(); } diff --git a/firmware/config.h b/firmware/config.h index b015ca78f9..df7bd58f55 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -125,7 +125,7 @@ bool config_containsPin(const char *pin); bool config_hasPin(void); void config_setPin(const char *pin); bool config_changePin(const char *old_pin, const char *new_pin); -bool session_isPinCached(void); +bool session_isUnlocked(void); uint32_t config_nextU2FCounter(void); void config_setU2FCounter(uint32_t u2fcounter); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index aa906423f7..9cafd4d302 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -58,7 +58,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_initialized = true; resp->initialized = config_isInitialized(); resp->has_imported = config_getImported(&(resp->imported)); - resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); + resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); diff --git a/firmware/protect.c b/firmware/protect.c index 2f961bb8c0..796997d1fc 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -181,13 +181,10 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) bool protectPin(bool use_cached) { - if (use_cached && session_isPinCached()) { + if (use_cached && session_isUnlocked()) { return true; } - // TODO If maximum number of PIN attempts: - // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); - const char *pin = ""; if (config_hasPin()) { pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); diff --git a/firmware/trezor.c b/firmware/trezor.c index fd59578025..50b7b60eed 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -91,7 +91,6 @@ int main(void) { #if EMULATOR memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); - HW_ENTROPY_DATA[0] = 1; #else desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); #endif From 05f3b74b65e8605c8d704f284d4430a86fc0251e Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:40:24 +0100 Subject: [PATCH 1087/1154] Fix rebase. --- firmware/reset.c | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index 8fa650c443..9813c0969f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -169,7 +169,6 @@ void reset_backup(bool separated, const char* mnemonic) } config_setUnfinishedBackup(false); - storage_update(); if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); From 3c05a2da12e4fc7115c6a3e38cfc00cf4f38281c Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:56:36 +0100 Subject: [PATCH 1088/1154] Fix rebase. --- common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.c b/common.c index 7d019ec310..7d1cfdd7af 100644 --- a/common.c +++ b/common.c @@ -38,7 +38,7 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, oledClear(); oledDrawBitmap(0, 0, icon); - oledDrawStringCenter((icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); oledDrawString(0, y, line, FONT_STANDARD); From faa0664b625cf75e99bcc4e070be5f4d3525a3fe Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 20:56:39 +0100 Subject: [PATCH 1089/1154] config: Use efficient implementation of U2F counter from trezor-storage. --- firmware/config.c | 15 ++++++--------- vendor/trezor-storage | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 8e52a29183..d8a28ccfc0 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -51,6 +51,7 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t #define APP 0x0100 #define FLAG_PUBLIC 0x8000 +#define FLAGS_WRITE 0xC000 static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) static const uint16_t KEY_VERSION = 1 | APP; // uint32 @@ -61,7 +62,7 @@ static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // boo static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool static const uint16_t KEY_FLAGS = 8 | APP; // uint32 -static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAGS_WRITE; // uint32 static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool @@ -837,18 +838,14 @@ bool config_getFlags(uint32_t *flags) uint32_t config_nextU2FCounter(void) { - // TODO Implement efficient version. - uint32_t counter = 0; - uint16_t len = 0; - storage_get(KEY_U2F_COUNTER, &counter, sizeof(counter), &len); - counter++; - storage_set(KEY_U2F_COUNTER, &counter, sizeof(counter)); - return counter; + uint32_t u2fcounter = 0; + storage_next_counter(KEY_U2F_COUNTER, &u2fcounter); + return u2fcounter; } void config_setU2FCounter(uint32_t u2fcounter) { - storage_set(KEY_U2F_COUNTER, &u2fcounter, sizeof(u2fcounter)); + storage_set_counter(KEY_U2F_COUNTER, u2fcounter); } uint32_t config_getAutoLockDelayMs() diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 0497802014..5c2765740d 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 0497802014edf03cdcce8cb70889d5a6e0bd3361 +Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c From 2f9010824da41ce01d7dd1b514acd865fbd90add Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 11 Feb 2019 12:51:51 +0100 Subject: [PATCH 1090/1154] config: Erase HW_ENTROPY_DATA when no longer needed. --- firmware/config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/config.c b/firmware/config.c index d8a28ccfc0..71319b81ac 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -345,6 +345,7 @@ void config_init(void) config_upgrade_v10(); storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { From 8502ee61a365ac8f5479a4689abf8950e74bca03 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 18:01:35 +0100 Subject: [PATCH 1091/1154] Upon fatal error display 'Contact TREZOR support' instead of 'Unplug your device'. --- common.c | 2 +- vendor/trezor-storage | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common.c b/common.c index 7d1cfdd7af..0530ee3fa0 100644 --- a/common.c +++ b/common.c @@ -59,7 +59,7 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, oledDrawString(0, y, line, FONT_STANDARD); y += FONT_HEIGHT + 1; - oledDrawString(0, y, "Please unplug the device.", FONT_STANDARD); + oledDrawString(0, y, "Contact TREZOR support.", FONT_STANDARD); oledRefresh(); shutdown(); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 5c2765740d..f05a2ff9cc 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c +Subproject commit f05a2ff9ccb4562ba4bd8a75a3607bbf24a0c074 From 0e48a1a39a481b67463ab3233f683f24787d2e7d Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 12 Feb 2019 15:46:28 +0100 Subject: [PATCH 1092/1154] Fix spaces/tabs so that a single convention is used in each file. --- emulator/timer.c | 2 +- firmware/layout2.c | 14 ++-- firmware/protect.c | 154 ++++++++++++++++++++++---------------------- firmware/recovery.c | 12 ++-- firmware/reset.c | 52 +++++++-------- firmware/trezor.c | 4 +- flash.c | 38 +++++------ 7 files changed, 138 insertions(+), 138 deletions(-) diff --git a/emulator/timer.c b/emulator/timer.c index eadbf76cce..efb95564bd 100644 --- a/emulator/timer.c +++ b/emulator/timer.c @@ -27,6 +27,6 @@ uint32_t timer_ms(void) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); - uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); + uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); return msec; } diff --git a/firmware/layout2.c b/firmware/layout2.c index 36e02829f5..1080ef2787 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -238,7 +238,7 @@ void layoutHome(void) char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); if (config_isInitialized()) { - config_getLabel(label, sizeof(label)); + config_getLabel(label, sizeof(label)); } uint8_t homescreen[HOMESCREEN_SIZE]; @@ -257,12 +257,12 @@ void layoutHome(void) } } - bool no_backup = false; - bool unfinished_backup = false; - bool needs_backup = false; - config_getNoBackup(&no_backup); - config_getUnfinishedBackup(&unfinished_backup); - config_getNeedsBackup(&needs_backup); + bool no_backup = false; + bool unfinished_backup = false; + bool needs_backup = false; + config_getNoBackup(&no_backup); + config_getUnfinishedBackup(&unfinished_backup); + config_getNeedsBackup(&needs_backup); if (no_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); diff --git a/firmware/protect.c b/firmware/protect.c index 796997d1fc..51f0754a05 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -149,34 +149,34 @@ const char *requestPin(PinMatrixRequestType type, const char *text) secbool protectPinUiCallback(uint32_t wait, uint32_t progress) { - (void) progress; + (void) progress; - // Convert wait to secstr string. - char secstrbuf[] = _("________0 seconds"); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - do { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } while (secs > 0 && secstr >= secstrbuf); - if (wait == 1) { - // Change "seconds" to "second". - secstrbuf[16] = 0; - } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + // Convert wait to secstr string. + char secstrbuf[] = _("________0 seconds"); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + do { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } while (secs > 0 && secstr >= secstrbuf); + if (wait == 1) { + // Change "seconds" to "second". + secstrbuf[16] = 0; + } + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - // Check for Cancel / Initialize. - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - msg_tiny_id = 0xFFFF; - usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return sectrue; - } + // Check for Cancel / Initialize. + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return sectrue; + } - return secfalse; + return secfalse; } bool protectPin(bool use_cached) @@ -187,77 +187,77 @@ bool protectPin(bool use_cached) const char *pin = ""; if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } } - usbTiny(1); + usbTiny(1); bool ret = config_containsPin(pin); - usbTiny(0); + usbTiny(0); if (!ret) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); } - return ret; + return ret; } bool protectChangePin(bool removal) { - static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; - static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; - const char* pin = NULL; + static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; + const char* pin = NULL; - if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (pin == NULL) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - strlcpy(old_pin, pin, sizeof(old_pin)); - } + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (pin == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(old_pin, pin, sizeof(old_pin)); + } - if (!removal) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - strlcpy(new_pin, pin, sizeof(new_pin)); + if (!removal) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(new_pin, pin, sizeof(new_pin)); - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - return false; - } - } + if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + return false; + } + } - usbTiny(1); - bool ret = config_changePin(old_pin, new_pin); - usbTiny(0); - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - if (ret == false) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - } - return ret; + usbTiny(1); + bool ret = config_changePin(old_pin, new_pin); + usbTiny(0); + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } bool protectPassphrase(void) { - bool passphrase_protection = false; - config_getPassphraseProtection(&passphrase_protection); + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); if (!passphrase_protection || session_isPassphraseCached()) { return true; } diff --git a/firmware/recovery.c b/firmware/recovery.c index f7e5460fc8..dd3b7edb09 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -165,13 +165,13 @@ static void recovery_done(void) { if (!dry_run) { // Update mnemonic on config. if (config_setMnemonic(new_mnemonic)) { - if (!enforce_wordlist) { - // not enforcing => mark config as imported - config_setImported(true); - } - fsm_sendSuccess(_("Device recovered")); + if (!enforce_wordlist) { + // not enforcing => mark config as imported + config_setImported(true); + } + fsm_sendSuccess(_("Device recovered")); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); } memzero(new_mnemonic, sizeof(new_mnemonic)); } else { diff --git a/firmware/reset.c b/firmware/reset.c index 9813c0969f..82bf7191d6 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -97,7 +97,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } - awaiting_entropy = false; + awaiting_entropy = false; SHA256_CTX ctx; sha256_Init(&ctx); @@ -108,21 +108,21 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memzero(int_entropy, 32); if (skip_backup || no_backup) { - if (no_backup) { - config_setNoBackup(); - } else { - config_setNeedsBackup(true); - } - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } + if (no_backup) { + config_setNoBackup(); + } else { + config_setNeedsBackup(true); + } + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } layoutHome(); } else { reset_backup(false, mnemonic); } - mnemonic_clear(); + mnemonic_clear(); } static char current_word[10]; @@ -131,15 +131,15 @@ static char current_word[10]; void reset_backup(bool separated, const char* mnemonic) { if (separated) { - bool needs_backup = false; - config_getNeedsBackup(&needs_backup); - if (!needs_backup) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); - return; - } + bool needs_backup = false; + config_getNeedsBackup(&needs_backup); + if (!needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + return; + } - config_setUnfinishedBackup(true); - config_setNeedsBackup(false); + config_setUnfinishedBackup(true); + config_setNeedsBackup(false); } for (int pass = 0; pass < 2; pass++) { @@ -173,12 +173,12 @@ void reset_backup(bool separated, const char* mnemonic) if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { - config_setNeedsBackup(false); - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } + config_setNeedsBackup(false); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } } layoutHome(); } diff --git a/firmware/trezor.c b/firmware/trezor.c index 50b7b60eed..97b5ddd69f 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -90,9 +90,9 @@ void check_lock_screen(void) int main(void) { #if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); #else - desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); #endif #ifndef APPVER diff --git a/flash.c b/flash.c index 998219c0b0..1501b6aa2a 100644 --- a/flash.c +++ b/flash.c @@ -43,7 +43,7 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { static secbool flash_check_success(uint32_t status) { - return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; + return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; } void flash_init(void) @@ -58,7 +58,7 @@ secbool flash_unlock_write(void) secbool flash_lock_write(void) { - return flash_check_success(svc_flash_lock()); + return flash_check_success(svc_flash_lock()); } const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) @@ -77,16 +77,16 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) secbool flash_erase(uint8_t sector) { ensure(flash_unlock_write(), NULL); - svc_flash_erase_sector(sector); - ensure(flash_lock_write(), NULL); + svc_flash_erase_sector(sector); + ensure(flash_lock_write(), NULL); - // Check whether the sector was really deleted (contains only 0xFF). - const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; - for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { - return secfalse; - } - } + // Check whether the sector was really deleted (contains only 0xFF). + const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { + return secfalse; + } + } return sectrue; } @@ -98,14 +98,14 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) } if ((*address & data) != data) { - return secfalse; + return secfalse; } - svc_flash_program(FLASH_CR_PROGRAM_X8); - *(volatile uint8_t *) address = data; + svc_flash_program(FLASH_CR_PROGRAM_X8); + *(volatile uint8_t *) address = data; if (*address != data) { - return secfalse; + return secfalse; } return sectrue; @@ -123,14 +123,14 @@ secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) } if ((*address & data) != data) { - return secfalse; + return secfalse; } - svc_flash_program(FLASH_CR_PROGRAM_X32); - *(volatile uint32_t *) address = data; + svc_flash_program(FLASH_CR_PROGRAM_X32); + *(volatile uint32_t *) address = data; if (*address != data) { - return secfalse; + return secfalse; } return sectrue; From dc848be167b183562c2a268df648f8c0087c73a8 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 12 Feb 2019 17:56:33 +0100 Subject: [PATCH 1093/1154] config: Cache auto-lock delay. --- firmware/config.c | 28 +++++++++++++++++++++------- vendor/trezor-storage | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 71319b81ac..0ec42b3809 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -111,12 +111,15 @@ be added to the storage u2f_counter to get the real counter value. * This corresponds to the number of cleared bits in the U2FAREA. */ static bool sessionSeedCached, sessionSeedUsesPassphrase; - static uint8_t CONFIDENTIAL sessionSeed[64]; static bool sessionPassphraseCached = false; static char CONFIDENTIAL sessionPassphrase[51]; +#define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes +static secbool autoLockDelayMsCached = secfalse; +static uint32_t autoLockDelayMs = autoLockDelayMsDefault; + static const uint32_t CONFIG_VERSION = 10; static const uint8_t FALSE_BYTE = '\x00'; @@ -851,19 +854,29 @@ void config_setU2FCounter(uint32_t u2fcounter) uint32_t config_getAutoLockDelayMs() { - const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - uint32_t delay_ms = 0; - if (config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &delay_ms)) { - return delay_ms; + if (sectrue == autoLockDelayMsCached) { + return autoLockDelayMs; } - return default_delay_ms; + + if (sectrue != storage_is_unlocked()) { + return autoLockDelayMsDefault; + } + + if (!config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { + autoLockDelayMs = autoLockDelayMsDefault; + } + autoLockDelayMsCached = sectrue; + return autoLockDelayMs; } void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); - storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms)); + if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms))) { + autoLockDelayMs = auto_lock_delay_ms; + autoLockDelayMsCached = sectrue; + } } void config_wipe(void) @@ -872,6 +885,7 @@ void config_wipe(void) storage_unlock(PIN_EMPTY); random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + autoLockDelayMsCached = secfalse; storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); session_clear(false); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index f05a2ff9cc..13b256ab2c 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit f05a2ff9ccb4562ba4bd8a75a3607bbf24a0c074 +Subproject commit 13b256ab2c11791e0c13696a8c507787a374884f From 45193ffc1dd3813ad036b769b7d8743b6af5c9e7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 13 Feb 2019 15:53:27 +0100 Subject: [PATCH 1094/1154] config: Use secbool instead of bool at least internally. --- firmware/config.c | 96 +++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 0ec42b3809..344910497d 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -110,10 +110,10 @@ be added to the storage u2f_counter to get the real counter value. * storage.u2f_counter + config_u2f_offset. * This corresponds to the number of cleared bits in the U2FAREA. */ -static bool sessionSeedCached, sessionSeedUsesPassphrase; +static secbool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t CONFIDENTIAL sessionSeed[64]; -static bool sessionPassphraseCached = false; +static secbool sessionPassphraseCached = secfalse; static char CONFIDENTIAL sessionPassphrase[51]; #define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes @@ -143,62 +143,62 @@ static uint32_t pin_to_int(const char *pin) return val; } -static bool config_set_bool(uint16_t key, bool value) +static secbool config_set_bool(uint16_t key, bool value) { if (value) { - return (sectrue == storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE))); + return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE)); } else { - return (sectrue == storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE))); + return storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE)); } } -static bool config_get_bool(uint16_t key, bool *value) +static secbool config_get_bool(uint16_t key, bool *value) { uint8_t val = 0; uint16_t len = 0; if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { *value = (val == TRUE_BYTE); - return true; + return sectrue; } else { *value = false; - return false; + return secfalse; } } -static bool config_has_key(uint16_t key) +static secbool config_has_key(uint16_t key) { uint16_t len = 0; - return sectrue == storage_get(key, NULL, 0, &len); + return storage_get(key, NULL, 0, &len); } -static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) +static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { - dest[0] = '\0'; uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { - return false; + dest[0] = '\0'; + return secfalse; } dest[len] = '\0'; - return true; + return sectrue; } -static bool config_get_uint32(uint16_t key, uint32_t *value) +static secbool config_get_uint32(uint16_t key, uint32_t *value) { uint16_t len = 0; if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { *value = 0; - return false; + return secfalse; } - return true; + return sectrue; } -static bool config_upgrade_v10(void) +static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic - return false; + return secfalse; } Storage config __attribute__((aligned(4))); @@ -220,7 +220,7 @@ static bool config_upgrade_v10(void) if (config.version > CONFIG_VERSION) { // downgrade -> clear storage config_wipe(); - return false; + return secfalse; } size_t old_config_size = 0; @@ -340,7 +340,7 @@ static bool config_upgrade_v10(void) session_clear(true); - return true; + return sectrue; } void config_init(void) @@ -360,9 +360,9 @@ void config_init(void) void session_clear(bool lock) { - sessionSeedCached = false; + sessionSeedCached = secfalse; memzero(&sessionSeed, sizeof(sessionSeed)); - sessionPassphraseCached = false; + sessionPassphraseCached = secfalse; memzero(&sessionPassphrase, sizeof(sessionPassphrase)); if (lock) { storage_lock(); @@ -494,14 +494,14 @@ void config_setLanguage(const char *lang) void config_setPassphraseProtection(bool passphrase_protection) { - sessionSeedCached = false; - sessionPassphraseCached = false; + sessionSeedCached = secfalse; + sessionPassphraseCached = secfalse; config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } bool config_getPassphraseProtection(bool *passphrase_protection) { - return config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); + return sectrue == config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } void config_setHomescreen(const uint8_t *data, uint32_t size) @@ -522,8 +522,8 @@ static void get_root_node_callback(uint32_t iter, uint32_t total) const uint8_t *config_getSeed(bool usePassphrase) { // root node is properly cached - if (usePassphrase == sessionSeedUsesPassphrase - && sessionSeedCached) { + if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) + && sectrue == sessionSeedCached) { return sessionSeed; } @@ -548,8 +548,8 @@ const uint8_t *config_getSeed(bool usePassphrase) mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 memzero(mnemonic, sizeof(mnemonic)); usbTiny(oldTiny); - sessionSeedCached = true; - sessionSeedUsesPassphrase = usePassphrase; + sessionSeedCached = sectrue; + sessionSeedUsesPassphrase = usePassphrase ? sectrue : secfalse; return sessionSeed; } @@ -589,7 +589,7 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) } bool passphrase_protection = false; config_getPassphraseProtection(&passphrase_protection); - if (passphrase_protection && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + if (passphrase_protection && sectrue == sessionPassphraseCached && sessionPassphrase[0] != '\0') { // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; @@ -621,12 +621,12 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) bool config_getLabel(char *dest, uint16_t dest_size) { - return config_get_string(KEY_LABEL, dest, dest_size); + return sectrue == config_get_string(KEY_LABEL, dest, dest_size); } bool config_getLanguage(char *dest, uint16_t dest_size) { - return config_get_string(KEY_LANGUAGE, dest, dest_size); + return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size); } bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) @@ -649,7 +649,7 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (!config_set_bool(KEY_INITIALIZED, true)) { + if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { storage_delete(KEY_MNEMONIC); return false; } @@ -670,17 +670,17 @@ bool config_setMnemonic(const char *mnemonic) bool config_hasNode(void) { - return config_has_key(KEY_NODE); + return sectrue == config_has_key(KEY_NODE); } bool config_hasMnemonic(void) { - return config_has_key(KEY_MNEMONIC); + return sectrue == config_has_key(KEY_MNEMONIC); } bool config_getMnemonic(char *dest, uint16_t dest_size) { - return config_get_string(KEY_MNEMONIC, dest, dest_size); + return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); } /* Check whether mnemonic matches storage. The mnemonic must be @@ -718,7 +718,7 @@ bool config_containsPin(const char *pin) bool config_hasPin(void) { - return storage_has_pin(); + return sectrue == storage_has_pin(); } bool config_changePin(const char *old_pin, const char *new_pin) @@ -737,17 +737,17 @@ bool config_changePin(const char *old_pin, const char *new_pin) void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); - sessionPassphraseCached = true; + sessionPassphraseCached = sectrue; } bool session_isPassphraseCached(void) { - return sessionPassphraseCached; + return sectrue == sessionPassphraseCached; } bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) { - if (!passphrase && !sessionPassphraseCached) { + if (!passphrase && sectrue != sessionPassphraseCached) { return false; } else { passphrase = sessionPassphrase; @@ -774,7 +774,7 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras bool session_isUnlocked(void) { - return storage_is_unlocked(); + return sectrue == storage_is_unlocked(); } bool config_isInitialized(void) @@ -786,7 +786,7 @@ bool config_isInitialized(void) bool config_getImported(bool* imported) { - return config_get_bool(KEY_IMPORTED, imported); + return sectrue == config_get_bool(KEY_IMPORTED, imported); } void config_setImported(bool imported) @@ -796,7 +796,7 @@ void config_setImported(bool imported) bool config_getNeedsBackup(bool *needs_backup) { - return config_get_bool(KEY_NEEDS_BACKUP, needs_backup); + return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup); } void config_setNeedsBackup(bool needs_backup) @@ -806,7 +806,7 @@ void config_setNeedsBackup(bool needs_backup) bool config_getUnfinishedBackup(bool *unfinished_backup) { - return config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); + return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } void config_setUnfinishedBackup(bool unfinished_backup) @@ -816,7 +816,7 @@ void config_setUnfinishedBackup(bool unfinished_backup) bool config_getNoBackup(bool *no_backup) { - return config_get_bool(KEY_NO_BACKUP, no_backup); + return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup); } void config_setNoBackup(void) @@ -837,7 +837,7 @@ void config_applyFlags(uint32_t flags) bool config_getFlags(uint32_t *flags) { - return config_get_uint32(KEY_FLAGS, flags); + return sectrue == config_get_uint32(KEY_FLAGS, flags); } uint32_t config_nextU2FCounter(void) @@ -862,7 +862,7 @@ uint32_t config_getAutoLockDelayMs() return autoLockDelayMsDefault; } - if (!config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { + if (sectrue != config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { autoLockDelayMs = autoLockDelayMsDefault; } autoLockDelayMsCached = sectrue; From 6b66c7540c1f0feec2ed531e12e6babb92bb95d3 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 13 Feb 2019 17:12:55 +0100 Subject: [PATCH 1095/1154] config: Remove unused functions config_hasMnemonic() and config_hasNode(). Since mnemonic and node are protected entries, these functions would always return false when storage is locked. We now instead use the INITIALIZED flag which is public. --- firmware/config.c | 32 ++++++++------------------------ firmware/config.h | 4 +--- firmware/fsm_msg_debug.h | 7 ++----- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 344910497d..32186d0b85 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -165,12 +165,6 @@ static secbool config_get_bool(uint16_t key, bool *value) } } -static secbool config_has_key(uint16_t key) -{ - uint16_t len = 0; - return storage_get(key, NULL, 0, &len); -} - static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { uint16_t len = 0; @@ -410,17 +404,19 @@ static void config_setNode(const HDNodeType *node) { if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { config_set_bool(KEY_INITIALIZED, true); } + memzero(&storageHDNode, sizeof(storageHDNode)); } #if DEBUG_LINK -void config_dumpNode(HDNodeType *node) +bool config_dumpNode(HDNodeType *node) { memzero(node, sizeof(HDNodeType)); StorageHDNode storageNode; uint16_t len = 0; if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { - return; + memzero(&storageNode, sizeof(storageNode)); + return false; } node->depth = storageNode.depth; @@ -437,6 +433,7 @@ void config_dumpNode(HDNodeType *node) } memzero(&storageNode, sizeof(storageNode)); + return true; } #endif @@ -649,11 +646,6 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { - storage_delete(KEY_MNEMONIC); - return false; - } - StorageHDNode u2fNode; memzero(&u2fNode, sizeof(u2fNode)); config_compute_u2froot(mnemonic, &u2fNode); @@ -662,22 +654,14 @@ bool config_setMnemonic(const char *mnemonic) if (sectrue != ret) { storage_delete(KEY_MNEMONIC); - storage_delete(KEY_INITIALIZED); return false; } + + config_set_bool(KEY_INITIALIZED, true); + return true; } -bool config_hasNode(void) -{ - return sectrue == config_has_key(KEY_NODE); -} - -bool config_hasMnemonic(void) -{ - return sectrue == config_has_key(KEY_MNEMONIC); -} - bool config_getMnemonic(char *dest, uint16_t dest_size) { return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); diff --git a/firmware/config.h b/firmware/config.h index df7bd58f55..9fd8cd089e 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -113,12 +113,10 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); -bool config_hasMnemonic(void); bool config_getMnemonic(char *dest, uint16_t dest_size); -bool config_hasNode(void); #if DEBUG_LINK -void config_dumpNode(HDNodeType *node); +bool config_dumpNode(HDNodeType *node); #endif bool config_containsPin(const char *pin); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 0ef38279f6..0ed3bd1bce 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -52,12 +52,9 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); + resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); - if (config_hasNode()) { - resp.has_node = true; - config_dumpNode(&(resp.node)); - } + resp.has_node = config_dumpNode(&(resp.node)); resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); From 0b79d0e59687cb4ce9d98d30f830e41c5df3e9f7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 15:13:47 +0100 Subject: [PATCH 1096/1154] config: Store cleartext PIN for DEBUG_LINK. --- firmware/config.c | 63 +++++++++++++++++++++++++++------------- firmware/config.h | 1 + firmware/fsm_msg_debug.h | 5 +--- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 32186d0b85..69698a5541 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -53,23 +53,24 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t #define FLAG_PUBLIC 0x8000 #define FLAGS_WRITE 0xC000 -static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) -static const uint16_t KEY_VERSION = 1 | APP; // uint32 -static const uint16_t KEY_MNEMONIC = 2 | APP; // string(241) -static const uint16_t KEY_LANGUAGE = 3 | APP | FLAG_PUBLIC; // string(17) -static const uint16_t KEY_LABEL = 4 | APP | FLAG_PUBLIC; // string(33) -static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // bool -static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) -static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool -static const uint16_t KEY_FLAGS = 8 | APP; // uint32 -static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAGS_WRITE; // uint32 -static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool -static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 -static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool -static const uint16_t KEY_INITIALIZED = 14 | APP | FLAG_PUBLIC; // uint32 -static const uint16_t KEY_NODE = 15 | APP; // node -static const uint16_t KEY_IMPORTED = 16 | APP; // bool -static const uint16_t KEY_U2F_ROOT = 17 | APP | FLAG_PUBLIC; // node +#define KEY_UUID ( 0 | APP | FLAG_PUBLIC) // bytes(12) +#define KEY_VERSION ( 1 | APP) // uint32 +#define KEY_MNEMONIC ( 2 | APP) // string(241) +#define KEY_LANGUAGE ( 3 | APP | FLAG_PUBLIC) // string(17) +#define KEY_LABEL ( 4 | APP | FLAG_PUBLIC) // string(33) +#define KEY_PASSPHRASE_PROTECTION ( 5 | APP | FLAG_PUBLIC) // bool +#define KEY_HOMESCREEN ( 6 | APP | FLAG_PUBLIC) // bytes(1024) +#define KEY_NEEDS_BACKUP ( 7 | APP) // bool +#define KEY_FLAGS ( 8 | APP) // uint32 +#define KEY_U2F_COUNTER ( 9 | APP | FLAGS_WRITE) // uint32 +#define KEY_UNFINISHED_BACKUP ( 11 | APP) // bool +#define KEY_AUTO_LOCK_DELAY_MS ( 12 | APP) // uint32 +#define KEY_NO_BACKUP ( 13 | APP) // bool +#define KEY_INITIALIZED ( 14 | APP | FLAG_PUBLIC) // uint32 +#define KEY_NODE ( 15 | APP) // node +#define KEY_IMPORTED ( 16 | APP) // bool +#define KEY_U2F_ROOT ( 17 | APP | FLAG_PUBLIC) // node +#define KEY_DEBUG_LINK_PIN (255 | APP | FLAG_PUBLIC) // string(10) // The PIN value corresponding to an empty PIN. static const uint32_t PIN_EMPTY = 1; @@ -167,6 +168,10 @@ static secbool config_get_bool(uint16_t key, bool *value) static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { + if (dest_size == 0) { + return secfalse; + } + uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { dest[0] = '\0'; @@ -712,12 +717,30 @@ bool config_changePin(const char *old_pin, const char *new_pin) return false; } - if (sectrue == storage_change_pin(pin_to_int(old_pin), new_pin_int)) { - return true; + secbool ret = storage_change_pin(pin_to_int(old_pin), new_pin_int); + +#if DEBUG_LINK + if (sectrue == ret) { + if (new_pin_int != PIN_EMPTY) { + storage_set(KEY_DEBUG_LINK_PIN, new_pin, strnlen(new_pin, MAX_PIN_LEN)); + } else { + storage_delete(KEY_DEBUG_LINK_PIN); + } } - return false; +#endif + + memzero(&new_pin_int, sizeof(new_pin_int)); + + return sectrue == ret; } +#if DEBUG_LINK +bool config_getPin(char *dest, uint16_t dest_size) +{ + return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size); +} +#endif + void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); diff --git a/firmware/config.h b/firmware/config.h index 9fd8cd089e..fc97ef0f0a 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -117,6 +117,7 @@ bool config_getMnemonic(char *dest, uint16_t dest_size); #if DEBUG_LINK bool config_dumpNode(HDNodeType *node); +bool config_getPin(char *dest, uint16_t dest_size); #endif bool config_containsPin(const char *pin); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 0ed3bd1bce..cf1973ddbd 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -32,10 +32,7 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.layout.size = OLED_BUFSIZE; memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - if (config_hasPin()) { - resp.has_pin = true; - strlcpy(resp.pin, "1", sizeof(resp.pin)); - } + resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin)); resp.has_matrix = true; strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); From 55bc3c74302dcd06c9908614d4d88f50b8d78cd2 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 16:28:29 +0100 Subject: [PATCH 1097/1154] config: Check metadata magic before upgrading storage from version 10. Bump config version. --- firmware/config.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 69698a5541..e4824f4ab8 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -46,8 +46,14 @@ #include "supervise.h" #include "storage.h" -/* Magic constant to check validity of storage block for storage versions 1 to 10. */ -static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t +/* Magic constants to check validity of storage block for storage versions 1 to 10. */ +static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t + +#if !EMULATOR +static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' as uint32_t +#else +static const uint32_t META_MAGIC_V10 = 0xFFFFFFFF; +#endif #define APP 0x0100 #define FLAG_PUBLIC 0x8000 @@ -121,7 +127,7 @@ static char CONFIDENTIAL sessionPassphrase[51]; static secbool autoLockDelayMsCached = secfalse; static uint32_t autoLockDelayMs = autoLockDelayMsDefault; -static const uint32_t CONFIG_VERSION = 10; +static const uint32_t CONFIG_VERSION = 11; static const uint8_t FALSE_BYTE = '\x00'; static const uint8_t TRUE_BYTE = '\x01'; @@ -195,7 +201,8 @@ static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + if (memcmp(FLASH_PTR(FLASH_META_MAGIC), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || + memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic return secfalse; } From d5e18a489a817c2b1079b34163204d2a04c3bcab Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 16:53:48 +0100 Subject: [PATCH 1098/1154] Update trezor-storage. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 13b256ab2c..94cb1a4dbe 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 13b256ab2c11791e0c13696a8c507787a374884f +Subproject commit 94cb1a4dbe2e28aaaf36cd741800cf5c1b16e08f From b4c0b59c8973298e55ca22c1a69a7399a7abb8c4 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 18:59:31 +0100 Subject: [PATCH 1099/1154] msg: GetFeatures should always return passphrase_protection, needs_backup, unfinished_backup and no_backup, even if the value is not available in storage. --- firmware/fsm_msg_common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 9cafd4d302..10d61a1dc6 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -47,7 +47,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); - resp->has_passphrase_protection = config_getPassphraseProtection(&(resp->passphrase_protection)); + resp->has_passphrase_protection = true; config_getPassphraseProtection(&(resp->passphrase_protection)); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; @@ -60,9 +60,9 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_imported = config_getImported(&(resp->imported)); resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); - resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); - resp->has_no_backup = config_getNoBackup(&(resp->no_backup)); + resp->has_needs_backup = true; config_getNeedsBackup(&(resp->needs_backup)); + resp->has_unfinished_backup = true; config_getUnfinishedBackup(&(resp->unfinished_backup)); + resp->has_no_backup = true; config_getNoBackup(&(resp->no_backup)); resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); From 5230a0f8468176862025ece3894997562b3b7f6a Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 20:51:50 +0100 Subject: [PATCH 1100/1154] config: Do not lock storage after completing loadDevice(). --- firmware/config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index e4824f4ab8..e7de2d0409 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -451,6 +451,7 @@ bool config_dumpNode(HDNodeType *node) void config_loadDevice(const LoadDevice *msg) { + session_clear(false); config_set_bool(KEY_IMPORTED, true); config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); @@ -475,8 +476,6 @@ void config_loadDevice(const LoadDevice *msg) if (msg->has_u2f_counter) { config_setU2FCounter(msg->u2f_counter); } - - session_clear(true); } void config_setLabel(const char *label) From 9a9c537afdf940c809b46cf660afafc16e559284 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 14:12:18 +0100 Subject: [PATCH 1101/1154] vendor: update trezor-storage --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 94cb1a4dbe..5688a9e47e 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 94cb1a4dbe2e28aaaf36cd741800cf5c1b16e08f +Subproject commit 5688a9e47e6d0d21b63ac22924199de2da696db7 From 67c0f8b8a1e03047adfda73dacbe85cbae099f34 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 14:22:52 +0100 Subject: [PATCH 1102/1154] storage: use fixed hw_entropy in unprivileged mode --- firmware/trezor.c | 17 +++++++++-------- norcow_config.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index 97b5ddd69f..c26ec0deda 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -89,12 +89,6 @@ void check_lock_screen(void) int main(void) { -#if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); -#else - desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); -#endif - #ifndef APPVER setup(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks @@ -106,12 +100,19 @@ int main(void) #endif if (!is_mode_unprivileged()) { - + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); timer_init(); - #ifdef APPVER // enable MPU (Memory Protection Unit) mpu_config(); +#endif + } else { +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); +#else + // we are running in unprivileged mode + // use fixed HW_ENTROPY + memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); #endif } diff --git a/norcow_config.h b/norcow_config.h index d78f0749e5..ba57dfb4b2 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -29,7 +29,7 @@ /* * The length of the sector header in bytes. The header is preserved between sector erasures. */ -#define NORCOW_HEADER_LEN (0x000) +#define NORCOW_HEADER_LEN (0x100) /* * Current storage version. From 79e9ae28b78b39f61a7190f524f92683aa684a9f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Feb 2019 17:21:35 +0100 Subject: [PATCH 1103/1154] vendor: replace vendor/trezor-qrenc with vendor/QR-Code-generator --- .gitmodules | 6 +++--- Makefile.include | 2 +- firmware/Makefile | 3 +-- firmware/layout2.c | 28 ++++++++++++++++++++-------- vendor/QR-Code-generator | 1 + vendor/trezor-qrenc | 1 - 6 files changed, 26 insertions(+), 15 deletions(-) create mode 160000 vendor/QR-Code-generator delete mode 160000 vendor/trezor-qrenc diff --git a/.gitmodules b/.gitmodules index ff5aff640d..abca705b72 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "trezor-common"] path = vendor/trezor-common url = https://github.com/trezor/trezor-common.git -[submodule "trezor-qrenc"] - path = vendor/trezor-qrenc - url = https://github.com/trezor/trezor-qrenc.git [submodule "libopencm3"] path = vendor/libopencm3 url = https://github.com/libopencm3/libopencm3.git @@ -16,3 +13,6 @@ [submodule "vendor/trezor-storage"] path = vendor/trezor-storage url = https://github.com/trezor/trezor-storage.git +[submodule "vendor/QR-Code-generator"] + path = vendor/QR-Code-generator + url = https://github.com/nayuki/QR-Code-generator.git diff --git a/Makefile.include b/Makefile.include index 11e922652f..fdf6b5fca5 100644 --- a/Makefile.include +++ b/Makefile.include @@ -72,7 +72,7 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ - -I$(TOP_DIR)vendor/trezor-qrenc \ + -I$(TOP_DIR)vendor/QR-Code-generator/c \ -I$(TOP_DIR)vendor/trezor-storage LDFLAGS += -L$(TOP_DIR) \ diff --git a/firmware/Makefile b/firmware/Makefile index 90e136324d..672a063a40 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -82,7 +82,7 @@ OBJS += ../vendor/trezor-crypto/chacha20poly1305/rfc7539.o OBJS += ../vendor/trezor-crypto/nem.o -OBJS += ../vendor/trezor-qrenc/qr_encode.o +OBJS += ../vendor/QR-Code-generator/c/qrcodegen.o OBJS += ../vendor/trezor-storage/storage.o OBJS += ../vendor/trezor-storage/norcow.o @@ -117,7 +117,6 @@ DEBUG_LOG ?= 0 CFLAGS += -Wno-sequence-point CFLAGS += -I../vendor/nanopb -Iprotob -DPB_FIELD_16BIT=1 -CFLAGS += -DQR_MAX_VERSION=0 CFLAGS += -DDEBUG_LINK=$(DEBUG_LINK) CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' diff --git a/firmware/layout2.c b/firmware/layout2.c index 1080ef2787..1a5b98004e 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -27,7 +27,7 @@ #include "bitmaps.h" #include "string.h" #include "util.h" -#include "qr_encode.h" +#include "qrcodegen.h" #include "timer.h" #include "bignum.h" #include "secp256k1.h" @@ -553,6 +553,8 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last) oledRefresh(); } +#define QR_MAX_VERSION 9 + void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account) { if (layoutLast != layoutAddress) { @@ -564,7 +566,6 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno uint32_t addrlen = strlen(address); if (qrcode) { - static unsigned char bitdata[QR_MAX_BITDATA]; char address_upcase[addrlen + 1]; if (ignorecase) { for (uint32_t i = 0; i < addrlen + 1; i++) { @@ -572,16 +573,28 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno address[i] + 'A' - 'a' : address[i]; } } - int side = qr_encode(addrlen <= (ignorecase ? 60 : 40) ? QR_LEVEL_M : QR_LEVEL_L, 0, - ignorecase ? address_upcase : address, 0, bitdata); + uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + + int side = 0; + if (qrcodegen_encodeText( + ignorecase ? address_upcase : address, + tempdata, + codedata, + qrcodegen_Ecc_LOW, + qrcodegen_VERSION_MIN, + QR_MAX_VERSION, + qrcodegen_Mask_AUTO, + true)) { + side = qrcodegen_getSize(codedata); + } oledInvert(0, 0, 63, 63); if (side > 0 && side <= 29) { int offset = 32 - side; for (int i = 0; i < side; i++) { for (int j = 0; j< side; j++) { - int a = j * side + i; - if (bitdata[a / 8] & (1 << (7 - a % 8))) { + if (qrcodegen_getModule(codedata, i, j)) { oledBox(offset + i * 2, offset + j * 2, offset + 1 + i * 2, offset + 1 + j * 2, false); } @@ -591,8 +604,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno int offset = 32 - (side / 2); for (int i = 0; i < side; i++) { for (int j = 0; j< side; j++) { - int a = j * side + i; - if (bitdata[a / 8] & (1 << (7 - a % 8))) { + if (qrcodegen_getModule(codedata, i, j)) { oledClearPixel(offset + i, offset + j); } } diff --git a/vendor/QR-Code-generator b/vendor/QR-Code-generator new file mode 160000 index 0000000000..40d24f38aa --- /dev/null +++ b/vendor/QR-Code-generator @@ -0,0 +1 @@ +Subproject commit 40d24f38aa0a8180b271b6c88be8633f842ed9d4 diff --git a/vendor/trezor-qrenc b/vendor/trezor-qrenc deleted file mode 160000 index 4da44cacb7..0000000000 --- a/vendor/trezor-qrenc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4da44cacb7bd69aa297bafe4a41c498a050225a4 From 07d2994d0ccbb5e86a4467f0c90e0da7bb4ed38e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 17 Feb 2019 19:16:35 +0100 Subject: [PATCH 1104/1154] vendor: add ignore=untracked to QR code generator submodule The submodule does not contain .gitignore and we produce .d and .o files in their directory :-/ --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index abca705b72..3af103ead3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,4 @@ [submodule "vendor/QR-Code-generator"] path = vendor/QR-Code-generator url = https://github.com/nayuki/QR-Code-generator.git + ignore = untracked From 402e7c4ec633ed18810ebfb0af3cad42e03d867c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Feb 2019 00:53:56 +0100 Subject: [PATCH 1105/1154] firmware: fix undefined symbol in emulator --- firmware/trezor.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index c26ec0deda..90cf928adc 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -33,7 +33,9 @@ #include "gettext.h" #include "bl_check.h" #include "memzero.h" +#if !EMULATOR #include +#endif /* Screen timeout */ uint32_t system_millis_lock_start; @@ -99,17 +101,21 @@ int main(void) __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); +#endif + if (!is_mode_unprivileged()) { +#if !EMULATOR desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); +#endif timer_init(); #ifdef APPVER // enable MPU (Memory Protection Unit) mpu_config(); #endif } else { -#if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); -#else +#if !EMULATOR // we are running in unprivileged mode // use fixed HW_ENTROPY memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); From 540be4989729d93fb2e40a86865962fbff28e535 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Feb 2019 17:57:09 +0100 Subject: [PATCH 1106/1154] firmware: use OTP block 3 for storing randomness --- common.h | 2 +- firmware/Makefile | 1 + firmware/otp.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ firmware/otp.h | 36 ++++++++++++++++++++++++++ firmware/trezor.c | 39 ++++++++++++++++++---------- 5 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 firmware/otp.c create mode 100644 firmware/otp.h diff --git a/common.h b/common.h index 912f73c54d..a4fd9886ef 100644 --- a/common.h +++ b/common.h @@ -23,7 +23,7 @@ #include #include "secbool.h" -#define HW_ENTROPY_LEN 12 +#define HW_ENTROPY_LEN (12 + 32) extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); diff --git a/firmware/Makefile b/firmware/Makefile index 672a063a40..91e84acadc 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -7,6 +7,7 @@ OBJS += udp.o else OBJS += usb.o OBJS += bl_check.o +OBJS += otp.o endif OBJS += u2f.o diff --git a/firmware/otp.c b/firmware/otp.c new file mode 100644 index 0000000000..74810f6686 --- /dev/null +++ b/firmware/otp.c @@ -0,0 +1,65 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2019 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include "otp.h" + +#define FLASH_OTP_BASE 0x1FFF7800U +#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U + +bool flash_otp_is_locked(uint8_t block) +{ + return 0x00 == *(volatile uint8_t *)(FLASH_OTP_LOCK_BASE + block); +} + +bool flash_otp_lock(uint8_t block) +{ + if (block >= FLASH_OTP_NUM_BLOCKS) { + return false; + } + flash_unlock(); + flash_program_byte(FLASH_OTP_LOCK_BASE + block, 0x00); + flash_lock(); + return true; +} + +bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen) +{ + if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return false; + } + for (uint8_t i = 0; i < datalen; i++) { + data[i] = *(volatile uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); + } + return true; +} + +bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen) +{ + if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return false; + } + flash_unlock(); + for (uint8_t i = 0; i < datalen; i++) { + uint32_t address = FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; + flash_program_byte(address, data[i]); + } + flash_lock(); + return true; +} diff --git a/firmware/otp.h b/firmware/otp.h new file mode 100644 index 0000000000..471e230c0f --- /dev/null +++ b/firmware/otp.h @@ -0,0 +1,36 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2019 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __OTP_H__ +#define __OTP_H__ + +#include +#include + +#define FLASH_OTP_NUM_BLOCKS 16 +#define FLASH_OTP_BLOCK_SIZE 32 + +#define FLASH_OTP_BLOCK_RANDOMNESS 3 + +bool flash_otp_is_locked(uint8_t block); +bool flash_otp_lock(uint8_t block); +bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen); +bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen); + +#endif diff --git a/firmware/trezor.c b/firmware/trezor.c index 90cf928adc..dff99dd7fa 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -34,6 +34,7 @@ #include "bl_check.h" #include "memzero.h" #if !EMULATOR +#include "otp.h" #include #endif @@ -89,6 +90,29 @@ void check_lock_screen(void) } } +static void collect_hw_entropy(bool privileged) +{ +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); +#else + if (privileged) { + desig_get_unique_id((uint32_t *)HW_ENTROPY_DATA); + // set entropy in the OTP randomness block + if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { + uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; + random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); + flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE); + flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS); + } + // collect entropy from OTP randomness block + flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, FLASH_OTP_BLOCK_SIZE); + } else { + // unprivileged mode => use fixed HW_ENTROPY + memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); + } +#endif +} + int main(void) { #ifndef APPVER @@ -100,26 +124,15 @@ int main(void) setupApp(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks #endif - -#if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); -#endif - if (!is_mode_unprivileged()) { -#if !EMULATOR - desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); -#endif + collect_hw_entropy(true); timer_init(); #ifdef APPVER // enable MPU (Memory Protection Unit) mpu_config(); #endif } else { -#if !EMULATOR - // we are running in unprivileged mode - // use fixed HW_ENTROPY - memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); -#endif + collect_hw_entropy(false); } #if DEBUG_LINK From 827df268a6b60008bf6466634827a0e96c825469 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Feb 2019 18:24:40 +0100 Subject: [PATCH 1107/1154] firmware: fix unused argument in collect_hw_entropy --- firmware/trezor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/trezor.c b/firmware/trezor.c index dff99dd7fa..ae64082286 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -93,6 +93,7 @@ void check_lock_screen(void) static void collect_hw_entropy(bool privileged) { #if EMULATOR + (void)privileged; memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); #else if (privileged) { From c58c265d9c9c7845b3f62b2089d1c9b356dfd49f Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 18 Feb 2019 18:12:04 +0100 Subject: [PATCH 1108/1154] config: Check mnemonic by comparing hashes instead of the actual mnemonics, to mitigate side-channel attacks. --- firmware/config.c | 27 +++++++++++++++------------ firmware/fsm_msg_common.h | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index e7de2d0409..b2042acbfa 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -684,22 +684,25 @@ bool config_getMnemonic(char *dest, uint16_t dest_size) bool config_containsMnemonic(const char *mnemonic) { uint16_t len = 0; - uint8_t stored_mnemonic[MAX_MNEMONIC_LEN + 1]; - if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, MAX_MNEMONIC_LEN, &len)) { + uint8_t stored_mnemonic[MAX_MNEMONIC_LEN]; + if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, sizeof(stored_mnemonic), &len)) { return false; } - stored_mnemonic[len] = '\0'; - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - for (; mnemonic[i]; i++) { - diff |= (stored_mnemonic[i] - mnemonic[i]); - } - diff |= stored_mnemonic[i]; + // Compare the digests to mitigate side-channel attacks. + uint8_t digest_stored[SHA256_DIGEST_LENGTH]; + sha256_Raw(stored_mnemonic, len, digest_stored); memzero(stored_mnemonic, sizeof(stored_mnemonic)); + + uint8_t digest_input[SHA256_DIGEST_LENGTH]; + sha256_Raw((const uint8_t*)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), digest_input); + + uint8_t diff = 0; + for (size_t i = 0; i < sizeof(digest_input); i++) { + diff |= (digest_stored[i] - digest_input[i]); + } + memzero(digest_stored, sizeof(digest_stored)); + memzero(digest_input, sizeof(digest_input)); return diff == 0; } diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 10d61a1dc6..6f6872a3e1 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -339,7 +339,7 @@ void fsm_msgApplyFlags(const ApplyFlags *msg) void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { - CHECK_PIN + CHECK_PIN_UNCACHED const bool dry_run = msg->has_dry_run ? msg->dry_run : false; if (!dry_run) { From d95112ba052a371336cfa3dc7f5a7598a96d8a5d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Feb 2019 19:58:00 +0100 Subject: [PATCH 1109/1154] firmware/protect: show progressbar in verifying pin dialog + update trezor-storage --- firmware/protect.c | 12 +++++++++--- vendor/trezor-storage | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 51f0754a05..1802ed2019 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -149,8 +149,6 @@ const char *requestPin(PinMatrixRequestType type, const char *text) secbool protectPinUiCallback(uint32_t wait, uint32_t progress) { - (void) progress; - // Convert wait to secstr string. char secstrbuf[] = _("________0 seconds"); char *secstr = secstrbuf + 9; @@ -165,7 +163,15 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) secstrbuf[16] = 0; } layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - + // progressbar + oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); + progress = progress * (OLED_WIDTH - 4) / 1000; + if (progress > OLED_WIDTH - 4) { + progress = OLED_WIDTH - 4; + } + oledBox(2, OLED_HEIGHT - 6, 1 + progress, OLED_HEIGHT - 3, 1); + oledRefresh(); // Check for Cancel / Initialize. protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 5688a9e47e..d7e7d8ef27 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 5688a9e47e6d0d21b63ac22924199de2da696db7 +Subproject commit d7e7d8ef27cd57480d5c4eed17541f9a5bc72f72 From 7e82f275536ec85c83eec25f6860134de6093857 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Feb 2019 15:32:18 +0100 Subject: [PATCH 1110/1154] protect: make waiting UI more sexy --- firmware/protect.c | 6 +++++- vendor/trezor-storage | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 1802ed2019..99223ae332 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -162,7 +162,11 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) // Change "seconds" to "second". secstrbuf[16] = 0; } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + oledClear(); + oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, _("Verifying PIN"), FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), FONT_STANDARD); // progressbar oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index d7e7d8ef27..d715873ee6 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit d7e7d8ef27cd57480d5c4eed17541f9a5bc72f72 +Subproject commit d715873ee62d776ddc0f85028f7622374d4e0fe7 From a00c7f9720762cabdcfd7995bfbe8669ae1304e8 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Feb 2019 17:52:29 +0100 Subject: [PATCH 1111/1154] mpu: rename mpu_config to mpu_config_firmware --- firmware/trezor.c | 2 +- setup.c | 2 +- setup.h | 2 +- util.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index ae64082286..7a68329324 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -130,7 +130,7 @@ int main(void) timer_init(); #ifdef APPVER // enable MPU (Memory Protection Unit) - mpu_config(); + mpu_config_firmware(); #endif } else { collect_hw_entropy(false); diff --git a/setup.c b/setup.c index d0853db691..e59682b28c 100644 --- a/setup.c +++ b/setup.c @@ -162,7 +162,7 @@ void setupApp(void) #define SRAM_BASE (0x20000000U) // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) -void mpu_config(void) +void mpu_config_firmware(void) { #if MEMORY_PROTECT // Disable MPU diff --git a/setup.h b/setup.h index 34b88aae55..f6e3f91f77 100644 --- a/setup.h +++ b/setup.h @@ -27,6 +27,6 @@ extern uint32_t __stack_chk_guard; void setup(void); void setupApp(void); -void mpu_config(void); +void mpu_config_firmware(void); #endif diff --git a/util.h b/util.h index 384ede0e32..8202a4d04f 100644 --- a/util.h +++ b/util.h @@ -64,7 +64,7 @@ static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table // Set stack pointer __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); } else { // untrusted firmware - mpu_config(); // * configure MPU + mpu_config_firmware(); // * configure MPU for the firmware __asm__ volatile("msr msp, %0" :: "r" (_stack)); } From 44bb5864d42e95bb5c15a351f21792df83f4fc61 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 19 Feb 2019 18:01:10 +0100 Subject: [PATCH 1112/1154] fix whitespace --- firmware/config.h | 70 +++---- firmware/ethereum_tokens.h.mako | 8 +- firmware/fsm_msg_common.h | 32 +-- firmware/fsm_msg_stellar.h | 346 ++++++++++++++++---------------- firmware/stellar.h | 24 +-- memory.c | 2 +- 6 files changed, 241 insertions(+), 241 deletions(-) diff --git a/firmware/config.h b/firmware/config.h index fc97ef0f0a..636becec3c 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -24,56 +24,56 @@ #include "messages-management.pb.h" #define STORAGE_FIELD(TYPE, NAME) \ - bool has_##NAME; \ - TYPE NAME; + bool has_##NAME; \ + TYPE NAME; #define STORAGE_STRING(NAME, SIZE) \ - bool has_##NAME; \ - char NAME[SIZE]; + bool has_##NAME; \ + char NAME[SIZE]; #define STORAGE_BYTES(NAME, SIZE) \ - bool has_##NAME; \ - struct { \ - uint32_t size; \ - uint8_t bytes[SIZE]; \ - } NAME; + bool has_##NAME; \ + struct { \ + uint32_t size; \ + uint8_t bytes[SIZE]; \ + } NAME; #define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME) #define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME) #define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME) typedef struct { - uint32_t depth; - uint32_t fingerprint; - uint32_t child_num; - struct { - uint32_t size; - uint8_t bytes[32]; - } chain_code; + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + struct { + uint32_t size; + uint8_t bytes[32]; + } chain_code; - STORAGE_BYTES(private_key, 32); - STORAGE_BYTES(public_key, 33); + STORAGE_BYTES(private_key, 32); + STORAGE_BYTES(public_key, 33); } StorageHDNode; typedef struct _Storage { - uint32_t version; + uint32_t version; - STORAGE_NODE (node) - STORAGE_STRING (mnemonic, 241) - STORAGE_BOOL (passphrase_protection) - STORAGE_UINT32 (pin_failed_attempts) - STORAGE_STRING (pin, 10) - STORAGE_STRING (language, 17) - STORAGE_STRING (label, 33) - STORAGE_BOOL (imported) - STORAGE_BYTES (homescreen, 1024) - STORAGE_UINT32 (u2f_counter) - STORAGE_BOOL (needs_backup) - STORAGE_UINT32 (flags) - STORAGE_NODE (u2froot) - STORAGE_BOOL (unfinished_backup) - STORAGE_UINT32 (auto_lock_delay_ms) - STORAGE_BOOL (no_backup) + STORAGE_NODE (node) + STORAGE_STRING (mnemonic, 241) + STORAGE_BOOL (passphrase_protection) + STORAGE_UINT32 (pin_failed_attempts) + STORAGE_STRING (pin, 10) + STORAGE_STRING (language, 17) + STORAGE_STRING (label, 33) + STORAGE_BOOL (imported) + STORAGE_BYTES (homescreen, 1024) + STORAGE_UINT32 (u2f_counter) + STORAGE_BOOL (needs_backup) + STORAGE_UINT32 (flags) + STORAGE_NODE (u2froot) + STORAGE_BOOL (unfinished_backup) + STORAGE_UINT32 (auto_lock_delay_ms) + STORAGE_BOOL (no_backup) } Storage; extern Storage configUpdate; diff --git a/firmware/ethereum_tokens.h.mako b/firmware/ethereum_tokens.h.mako index 25de96ae52..12008d7efd 100644 --- a/firmware/ethereum_tokens.h.mako +++ b/firmware/ethereum_tokens.h.mako @@ -10,10 +10,10 @@ #define TOKENS_COUNT ${len(erc20_list)} typedef struct { - uint32_t chain_id; - const char * const address; - const char * const ticker; - int decimals; + uint32_t chain_id; + const char * const address; + const char * const ticker; + int decimals; } TokenType; extern const TokenType tokens[TOKENS_COUNT]; diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 6f6872a3e1..96da11d830 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -55,7 +55,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); resp->has_language = config_getLanguage(resp->language, sizeof(resp->language)); - resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); + resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_initialized = true; resp->initialized = config_isInitialized(); resp->has_imported = config_getImported(&(resp->imported)); resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); @@ -124,13 +124,13 @@ void fsm_msgChangePin(const ChangePin *msg) return; } - if (protectChangePin(removal)) { - if (removal) { - fsm_sendSuccess(_("PIN removed")); - } else { - fsm_sendSuccess(_("PIN changed")); - } - } + if (protectChangePin(removal)) { + if (removal) { + fsm_sendSuccess(_("PIN removed")); + } else { + fsm_sendSuccess(_("PIN changed")); + } + } layoutHome(); } @@ -174,7 +174,7 @@ void fsm_msgGetEntropy(const GetEntropy *msg) void fsm_msgLoadDevice(const LoadDevice *msg) { - CHECK_PIN + CHECK_PIN CHECK_NOT_INITIALIZED @@ -200,7 +200,7 @@ void fsm_msgLoadDevice(const LoadDevice *msg) void fsm_msgResetDevice(const ResetDevice *msg) { - CHECK_PIN + CHECK_PIN CHECK_NOT_INITIALIZED @@ -235,11 +235,11 @@ void fsm_msgBackupDevice(const BackupDevice *msg) CHECK_PIN_UNCACHED (void)msg; - char mnemonic[MAX_MNEMONIC_LEN + 1]; - if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { - reset_backup(true, mnemonic); - } - memzero(mnemonic, sizeof(mnemonic)); + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + reset_backup(true, mnemonic); + } + memzero(mnemonic, sizeof(mnemonic)); } void fsm_msgCancel(const Cancel *msg) @@ -329,7 +329,7 @@ void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) { - CHECK_PIN + CHECK_PIN if (msg->has_flags) { config_applyFlags(msg->flags); diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index 52188b3627..0c989f4b37 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -19,269 +19,269 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg) { - RESP_INIT(StellarAddress); + RESP_INIT(StellarAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); - if (!node) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); - return; - } + const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + return; + } - if (msg->has_show_display && msg->show_display) { - const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2], - NULL, - NULL, NULL - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_show_display && msg->show_display) { + const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), + str_addr_rows[0], + str_addr_rows[1], + str_addr_rows[2], + NULL, + NULL, NULL + ); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - resp->has_address = true; - stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); + resp->has_address = true; + stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); - msg_write(MessageType_MessageType_StellarAddress, resp); + msg_write(MessageType_MessageType_StellarAddress, resp); - layoutHome(); + layoutHome(); } void fsm_msgStellarSignTx(const StellarSignTx *msg) { - CHECK_INITIALIZED - CHECK_PIN + CHECK_INITIALIZED + CHECK_PIN - if (!stellar_signingInit(msg)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); - layoutHome(); - return; - } + if (!stellar_signingInit(msg)) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); + layoutHome(); + return; + } - // Confirm transaction basics - stellar_layoutTransactionSummary(msg); + // Confirm transaction basics + stellar_layoutTransactionSummary(msg); - // Respond with a request for the first operation - RESP_INIT(StellarTxOpRequest); + // Respond with a request for the first operation + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); } void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) { - if (!stellar_confirmCreateAccountOp(msg)) return; + if (!stellar_confirmCreateAccountOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) { - // This will display additional dialogs to the user - if (!stellar_confirmPaymentOp(msg)) return; + // This will display additional dialogs to the user + if (!stellar_confirmPaymentOp(msg)) return; - // Last operation was confirmed, send a StellarSignedTx - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + // Last operation was confirmed, send a StellarSignedTx + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) { - if (!stellar_confirmPathPaymentOp(msg)) return; + if (!stellar_confirmPathPaymentOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) { - if (!stellar_confirmManageOfferOp(msg)) return; + if (!stellar_confirmManageOfferOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) { - if (!stellar_confirmCreatePassiveOfferOp(msg)) return; + if (!stellar_confirmCreatePassiveOfferOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) { - if (!stellar_confirmSetOptionsOp(msg)) return; + if (!stellar_confirmSetOptionsOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) { - if (!stellar_confirmChangeTrustOp(msg)) return; + if (!stellar_confirmChangeTrustOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) { - if (!stellar_confirmAllowTrustOp(msg)) return; + if (!stellar_confirmAllowTrustOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) { - if (!stellar_confirmAccountMergeOp(msg)) return; + if (!stellar_confirmAccountMergeOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) { - if (!stellar_confirmManageDataOp(msg)) return; + if (!stellar_confirmManageDataOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) { - if (!stellar_confirmBumpSequenceOp(msg)) return; + if (!stellar_confirmBumpSequenceOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } diff --git a/firmware/stellar.h b/firmware/stellar.h index 3c5e34411a..14ce551f92 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -35,21 +35,21 @@ #define STELLAR_KEY_SIZE 32 typedef struct { - // BIP32 path to the address being used for signing - uint32_t address_n[10]; - size_t address_n_count; - uint8_t signing_pubkey[32]; + // BIP32 path to the address being used for signing + uint32_t address_n[10]; + size_t address_n_count; + uint8_t signing_pubkey[32]; - // 1 - public network, 2 - official testnet, 3 - other private network - uint8_t network_type; + // 1 - public network, 2 - official testnet, 3 - other private network + uint8_t network_type; - // Total number of operations expected - uint32_t num_operations; - // Number that have been confirmed by the user - uint32_t confirmed_operations; + // Total number of operations expected + uint32_t num_operations; + // Number that have been confirmed by the user + uint32_t confirmed_operations; - // sha256 context that will eventually be signed - SHA256_CTX sha256_ctx; + // sha256 context that will eventually be signed + SHA256_CTX sha256_ctx; } StellarTransaction; // Signing process diff --git a/memory.c b/memory.c index 1d68a3a2a7..11c550b6e6 100644 --- a/memory.c +++ b/memory.c @@ -34,6 +34,7 @@ void memory_protect(void) if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { return; // already set up correctly - bail out } + flash_unlock_option_bytes(); // Section 2.8.6 Flash option control register (FLASH_OPTCR) // Bits 31:28 Reserved, must be kept cleared. @@ -67,7 +68,6 @@ void memory_write_unlock(void) } int memory_bootloader_hash(uint8_t *hash) - { sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash); sha256_Raw(hash, 32, hash); From c7af39bf8dab11816ef977527c976ddc54f1d32e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Feb 2019 08:52:42 +0100 Subject: [PATCH 1113/1154] use shutdown from startup.s --- common.c | 8 +------- util.h | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/common.c b/common.c index 0530ee3fa0..2c2e31c09c 100644 --- a/common.c +++ b/common.c @@ -22,15 +22,11 @@ #include "rng.h" #include "layout.h" #include "oled.h" +#include "util.h" #include "firmware/usb.h" uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; -static void __attribute__((noreturn)) shutdown(void) -{ - for (;;); -} - void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { const BITMAP *icon = &bmp_icon_error; char line[128] = {0}; @@ -63,13 +59,11 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, oledRefresh(); shutdown(); - for (;;); } void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, "Please unplug", "the device."); shutdown(); - for (;;); } #ifndef NDEBUG diff --git a/util.h b/util.h index 8202a4d04f..bd95099082 100644 --- a/util.h +++ b/util.h @@ -44,6 +44,7 @@ void data2hex(const void *data, uint32_t len, char *str); // read protobuf integer and advance pointer uint32_t readprotobufint(const uint8_t **ptr); +// defined in startup.s (or setup.c for emulator) extern void __attribute__((noreturn)) shutdown(void); #if !EMULATOR From fd46339f5cc2971cd202697503c81a04d4b402f3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 16 Feb 2019 15:54:28 +0100 Subject: [PATCH 1114/1154] ethereum: clear local variables in layoutEthereumFee --- firmware/ethereum.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 500102c398..c9de7c9cca 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -377,6 +377,9 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, char tx_value[32]; char gas_value[32]; + memzero(tx_value, sizeof(tx_value)); + memzero(gas_value, sizeof(gas_value)); + memzero(pad_val, sizeof(pad_val)); memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); bn_read_be(pad_val, &val); From 7492cf07fc96e830ff69c9af470add8e78abe42a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 17 Feb 2019 18:51:24 +0100 Subject: [PATCH 1115/1154] firmware: fix buffer size in address_n_str --- firmware/layout2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 1a5b98004e..0ca71faf97 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -128,8 +128,8 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou } } - // "Path: m" / i ' - static char address_str[7 + 8 * (1 + 9 + 1) + 1]; + // "Path: m" / i ' + static char address_str[7 + 8 * (1 + 10 + 1) + 1]; char *c = address_str + sizeof(address_str) - 1; *c = 0; c--; From 0f5c96926cef227e83aba211efa5838bef3413e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 17 Feb 2019 20:22:18 +0100 Subject: [PATCH 1116/1154] firmware/u2f: memzero the readbuffer --- firmware/u2f.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/u2f.c b/firmware/u2f.c index 048b52a15f..6cb05914db 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -175,6 +175,8 @@ void u2fhid_init_cmd(const U2FHID_FRAME *f) { void u2fhid_read_start(const U2FHID_FRAME *f) { U2F_ReadBuffer readbuffer; + memzero(&readbuffer, sizeof(readbuffer)); + if (!(f->type & TYPE_INIT)) { return; } From 22f37e81a3270da5e8e5d6c55abc8f15f3a35567 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 20 Feb 2019 20:34:00 +0100 Subject: [PATCH 1117/1154] bootloader: enable MPU, introduce delays to USB stack --- Makefile | 1 + bootloader/bootloader.c | 3 + firmware/usb.c | 4 +- setup.c | 49 ++++ setup.h | 2 + usb21_standard.c | 4 +- usb_private.h | 161 +++++++++++ usb_standard.c | 604 ++++++++++++++++++++++++++++++++++++++++ util.c | 19 ++ util.h | 3 + webusb.c | 4 +- winusb.c | 10 +- 12 files changed, 858 insertions(+), 6 deletions(-) create mode 100644 usb_private.h create mode 100644 usb_standard.c diff --git a/Makefile b/Makefile index fce0a317c5..7c270e621e 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ ifneq ($(EMULATOR),1) OBJS += timer.o endif +OBJS += usb_standard.o OBJS += usb21_standard.o OBJS += webusb.o OBJS += winusb.o diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index b9f840cc94..292632db29 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -129,6 +129,8 @@ int main(void) oledInit(); #endif + mpu_config_bootloader(); + #ifndef APPVER // at least one button is unpressed uint16_t state = gpio_port_read(BTN_PORT); @@ -147,6 +149,7 @@ int main(void) timer_init(); } + mpu_config_off(); load_app(signed_firmware); } #endif diff --git a/firmware/usb.c b/firmware/usb.c index 9da00ea913..356bd03650 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -259,6 +259,8 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (void)complete; (void)dev; + wait_random(); + if ((req->bmRequestType != 0x81) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200)) @@ -266,7 +268,7 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin debugLog(0, "", "hid_control_request u2f"); *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); + *len = MIN_8bits(*len, sizeof(hid_report_descriptor_u2f)); return 1; } diff --git a/setup.c b/setup.c index e59682b28c..e554ad17a9 100644 --- a/setup.c +++ b/setup.c @@ -141,6 +141,7 @@ void setupApp(void) gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } +#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) @@ -161,6 +162,54 @@ void setupApp(void) #define FLASH_BASE (0x08000000U) #define SRAM_BASE (0x20000000U) +void mpu_config_off(void) +{ + // Disable MPU + MPU_CTRL = 0; + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +} + +void mpu_config_bootloader(void) +{ + // Disable MPU + MPU_CTRL = 0; + + // Note: later entries overwrite previous ones + // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-write) + MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRW_URW; + + // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) + MPU_RBAR = (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B | MPU_RASR_ATTR_AP_PNO_UNO; + + // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) + MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) + MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Don't enable DMA controller access + // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) + MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + + // Enable MPU + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; + + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + + __asm__ volatile("dsb"); + __asm__ volatile("isb"); +} + // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) void mpu_config_firmware(void) { diff --git a/setup.h b/setup.h index f6e3f91f77..503e418cad 100644 --- a/setup.h +++ b/setup.h @@ -27,6 +27,8 @@ extern uint32_t __stack_chk_guard; void setup(void); void setupApp(void); +void mpu_config_off(void); +void mpu_config_bootloader(void); void mpu_config_firmware(void); #endif diff --git a/usb21_standard.c b/usb21_standard.c index 7ed1986cf4..d6aab2bfd9 100644 --- a/usb21_standard.c +++ b/usb21_standard.c @@ -62,13 +62,15 @@ static int usb21_standard_get_descriptor(usbd_device* usbd_dev, (void)complete; (void)usbd_dev; + wait_random(); + if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { int descr_type = req->wValue >> 8; if (descr_type == USB_DT_BOS) { if (!usb21_bos) { return USBD_REQ_NOTSUPP; } - *len = MIN(*len, build_bos_descriptor(usb21_bos, *buf, *len)); + *len = MIN_8bits(*len, build_bos_descriptor(usb21_bos, *buf, *len)); return USBD_REQ_HANDLED; } } diff --git a/usb_private.h b/usb_private.h new file mode 100644 index 0000000000..bb553be32e --- /dev/null +++ b/usb_private.h @@ -0,0 +1,161 @@ +/** @defgroup usb_private_defines USB Private Structures + +@brief Defined Constants and Types for the USB Private Structures + +@ingroup USB_defines + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#ifndef __USB_PRIVATE_H +#define __USB_PRIVATE_H + +#define MAX_USER_CONTROL_CALLBACK 4 +#define MAX_USER_SET_CONFIG_CALLBACK 4 + +/** Internal collection of device information. */ +struct _usbd_device { + const struct usb_device_descriptor *desc; + const struct usb_config_descriptor *config; + const char **strings; + int num_strings; + + uint8_t *ctrl_buf; /**< Internal buffer used for control transfers */ + uint16_t ctrl_buf_len; + + uint8_t current_address; + uint8_t current_config; + + uint16_t pm_top; /**< Top of allocated endpoint buffer memory */ + + /* User callback functions for various USB events */ + void (*user_callback_reset)(void); + void (*user_callback_suspend)(void); + void (*user_callback_resume)(void); + void (*user_callback_sof)(void); + + struct usb_control_state { + enum { + IDLE, STALLED, + DATA_IN, LAST_DATA_IN, STATUS_IN, + DATA_OUT, LAST_DATA_OUT, STATUS_OUT, + } state; + struct usb_setup_data req __attribute__((aligned(4))); + uint8_t *ctrl_buf; + uint16_t ctrl_len; + usbd_control_complete_callback complete; + bool needs_zlp; + } control_state; + + struct user_control_callback { + usbd_control_callback cb; + uint8_t type; + uint8_t type_mask; + } user_control_callback[MAX_USER_CONTROL_CALLBACK]; + + usbd_endpoint_callback user_callback_ctr[8][3]; + + /* User callback function for some standard USB function hooks */ + usbd_set_config_callback user_callback_set_config[MAX_USER_SET_CONFIG_CALLBACK]; + + usbd_set_altsetting_callback user_callback_set_altsetting; + + const struct _usbd_driver *driver; + + /* private driver data */ + + uint16_t fifo_mem_top; + uint16_t fifo_mem_top_ep0; + uint8_t force_nak[4]; + /* + * We keep a backup copy of the out endpoint size registers to restore + * them after a transaction. + */ + uint32_t doeptsiz[4]; + /* + * Received packet size for each endpoint. This is assigned in + * stm32f107_poll() which reads the packet status push register GRXSTSP + * for use in stm32f107_ep_read_packet(). + */ + uint16_t rxbcnt; +}; + +enum _usbd_transaction { + USB_TRANSACTION_IN, + USB_TRANSACTION_OUT, + USB_TRANSACTION_SETUP, +}; + +/* Do not appear to belong to the API, so are omitted from docs */ +/**@}*/ + +void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea); +void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea); +void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea); + +int _usbd_standard_request_device(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request_endpoint(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len); +int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len); + +void _usbd_reset(usbd_device *usbd_dev); + +/* Functions provided by the hardware abstraction. */ +struct _usbd_driver { + usbd_device *(*init)(void); + void (*set_address)(usbd_device *usbd_dev, uint8_t addr); + void (*ep_setup)(usbd_device *usbd_dev, uint8_t addr, uint8_t type, + uint16_t max_size, usbd_endpoint_callback cb); + void (*ep_reset)(usbd_device *usbd_dev); + void (*ep_stall_set)(usbd_device *usbd_dev, uint8_t addr, + uint8_t stall); + void (*ep_nak_set)(usbd_device *usbd_dev, uint8_t addr, uint8_t nak); + uint8_t (*ep_stall_get)(usbd_device *usbd_dev, uint8_t addr); + uint16_t (*ep_write_packet)(usbd_device *usbd_dev, uint8_t addr, + const void *buf, uint16_t len); + uint16_t (*ep_read_packet)(usbd_device *usbd_dev, uint8_t addr, + void *buf, uint16_t len); + void (*poll)(usbd_device *usbd_dev); + void (*disconnect)(usbd_device *usbd_dev, bool disconnected); + uint32_t base_address; + bool set_address_before_status; + uint16_t rx_fifo_size; +}; + +#endif + diff --git a/usb_standard.c b/usb_standard.c new file mode 100644 index 0000000000..3576c289c0 --- /dev/null +++ b/usb_standard.c @@ -0,0 +1,604 @@ +/** @defgroup usb_standard_file Generic USB Standard Request Interface + +@ingroup USB + +@brief Generic USB Standard Request Interface + +@version 1.0.0 + +@author @htmlonly © @endhtmlonly 2010 +Gareth McMullin + +@date 10 March 2013 + +LGPL License Terms @ref lgpl_license +*/ + +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/**@{*/ + +#include +#include +#include "usb_private.h" +#include "util.h" + +int usbd_register_set_config_callback(usbd_device *usbd_dev, + usbd_set_config_callback callback) +{ + int i; + + for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) { + if (usbd_dev->user_callback_set_config[i]) { + continue; + } + + usbd_dev->user_callback_set_config[i] = callback; + return 0; + } + + return -1; +} + +void usbd_register_set_altsetting_callback(usbd_device *usbd_dev, + usbd_set_altsetting_callback callback) +{ + usbd_dev->user_callback_set_altsetting = callback; +} + +static uint16_t build_config_descriptor(usbd_device *usbd_dev, + uint8_t index, uint8_t *buf, uint16_t len) +{ + uint8_t *tmpbuf = buf; + const struct usb_config_descriptor *cfg = &usbd_dev->config[index]; + uint16_t count, total = 0, totallen = 0; + uint16_t i, j, k; + + memcpy(buf, cfg, count = MIN(len, cfg->bLength)); + buf += count; + len -= count; + total += count; + totallen += cfg->bLength; + + /* For each interface... */ + for (i = 0; i < cfg->bNumInterfaces; i++) { + /* Interface Association Descriptor, if any */ + if (cfg->interface[i].iface_assoc) { + const struct usb_iface_assoc_descriptor *assoc = + cfg->interface[i].iface_assoc; + memcpy(buf, assoc, count = MIN(len, assoc->bLength)); + buf += count; + len -= count; + total += count; + totallen += assoc->bLength; + } + /* For each alternate setting... */ + for (j = 0; j < cfg->interface[i].num_altsetting; j++) { + const struct usb_interface_descriptor *iface = + &cfg->interface[i].altsetting[j]; + /* Copy interface descriptor. */ + memcpy(buf, iface, count = MIN(len, iface->bLength)); + buf += count; + len -= count; + total += count; + totallen += iface->bLength; + /* Copy extra bytes (function descriptors). */ + if (iface->extra) { + memcpy(buf, iface->extra, + count = MIN(len, iface->extralen)); + buf += count; + len -= count; + total += count; + totallen += iface->extralen; + } + /* For each endpoint... */ + for (k = 0; k < iface->bNumEndpoints; k++) { + const struct usb_endpoint_descriptor *ep = + &iface->endpoint[k]; + memcpy(buf, ep, count = MIN(len, ep->bLength)); + buf += count; + len -= count; + total += count; + totallen += ep->bLength; + /* Copy extra bytes (class specific). */ + if (ep->extra) { + memcpy(buf, ep->extra, + count = MIN(len, ep->extralen)); + buf += count; + len -= count; + total += count; + totallen += ep->extralen; + } + } + } + } + + /* Fill in wTotalLength. */ + *(uint16_t *)(tmpbuf + 2) = totallen; + + return total; +} + +static int usb_descriptor_type(uint16_t wValue) +{ + return wValue >> 8; +} + +static int usb_descriptor_index(uint16_t wValue) +{ + return wValue & 0xFF; +} + +static int usb_standard_get_descriptor(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + + wait_random(); + + int i, array_idx, descr_idx; + struct usb_string_descriptor *sd; + + descr_idx = usb_descriptor_index(req->wValue); + + switch (usb_descriptor_type(req->wValue)) { + case USB_DT_DEVICE: + *buf = (uint8_t *) usbd_dev->desc; + *len = MIN_8bits(*len, usbd_dev->desc->bLength); + return USBD_REQ_HANDLED; + case USB_DT_CONFIGURATION: + *buf = usbd_dev->ctrl_buf; + *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len); + return USBD_REQ_HANDLED; + case USB_DT_STRING: + sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf; + + if (descr_idx == 0) { + /* Send sane Language ID descriptor... */ + sd->wData[0] = USB_LANGID_ENGLISH_US; + sd->bLength = sizeof(sd->bLength) + + sizeof(sd->bDescriptorType) + + sizeof(sd->wData[0]); + + *len = MIN_8bits(*len, sd->bLength); + } else { + array_idx = descr_idx - 1; + + if (!usbd_dev->strings) { + /* Device doesn't support strings. */ + return USBD_REQ_NOTSUPP; + } + + /* Check that string index is in range. */ + if (array_idx >= usbd_dev->num_strings) { + return USBD_REQ_NOTSUPP; + } + + /* Strings with Language ID differnet from + * USB_LANGID_ENGLISH_US are not supported */ + if (req->wIndex != USB_LANGID_ENGLISH_US) { + return USBD_REQ_NOTSUPP; + } + + /* This string is returned as UTF16, hence the + * multiplication + */ + sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 + + sizeof(sd->bLength) + + sizeof(sd->bDescriptorType); + + *len = MIN_8bits(*len, sd->bLength); + + for (i = 0; i < (*len / 2) - 1; i++) { + sd->wData[i] = + usbd_dev->strings[array_idx][i]; + } + } + + sd->bDescriptorType = USB_DT_STRING; + *buf = (uint8_t *)sd; + + return USBD_REQ_HANDLED; + } + return USBD_REQ_NOTSUPP; +} + +static int usb_standard_set_address(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + (void)req; + (void)buf; + (void)len; + + /* The actual address is only latched at the STATUS IN stage. */ + if ((req->bmRequestType != 0) || (req->wValue >= 128)) { + return 0; + } + + usbd_dev->current_address = req->wValue; + + /* + * Special workaround for STM32F10[57] that require the address + * to be set here. This is undocumented! + */ + if (usbd_dev->driver->set_address_before_status) { + usbd_dev->driver->set_address(usbd_dev, req->wValue); + } + + return 1; +} + +static int usb_standard_set_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + unsigned i; + int found_index = -1; + const struct usb_config_descriptor *cfg; + + (void)req; + (void)buf; + (void)len; + + if (req->wValue > 0) { + for (i = 0; i < usbd_dev->desc->bNumConfigurations; i++) { + if (req->wValue + == usbd_dev->config[i].bConfigurationValue) { + found_index = i; + break; + } + } + if (found_index < 0) { + return USBD_REQ_NOTSUPP; + } + } + + usbd_dev->current_config = found_index + 1; + + if (usbd_dev->current_config > 0) { + cfg = &usbd_dev->config[usbd_dev->current_config - 1]; + + /* reset all alternate settings configuration */ + for (i = 0; i < cfg->bNumInterfaces; i++) { + if (cfg->interface[i].cur_altsetting) { + *cfg->interface[i].cur_altsetting = 0; + } + } + } + + /* Reset all endpoints. */ + usbd_dev->driver->ep_reset(usbd_dev); + + if (usbd_dev->user_callback_set_config[0]) { + /* + * Flush control callbacks. These will be reregistered + * by the user handler. + */ + for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) { + usbd_dev->user_control_callback[i].cb = NULL; + } + + for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) { + if (usbd_dev->user_callback_set_config[i]) { + usbd_dev->user_callback_set_config[i](usbd_dev, + req->wValue); + } + } + } + + return 1; +} + +static int usb_standard_get_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)req; + + if (*len > 1) { + *len = 1; + } + if (usbd_dev->current_config > 0) { + const struct usb_config_descriptor *cfg = + &usbd_dev->config[usbd_dev->current_config - 1]; + (*buf)[0] = cfg->bConfigurationValue; + } else { + (*buf)[0] = 0; + } + + return 1; +} + +static int usb_standard_set_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + const struct usb_config_descriptor *cfx = + &usbd_dev->config[usbd_dev->current_config - 1]; + const struct usb_interface *iface; + + (void)buf; + + if (req->wIndex >= cfx->bNumInterfaces) { + return USBD_REQ_NOTSUPP; + } + + iface = &cfx->interface[req->wIndex]; + + if (req->wValue >= iface->num_altsetting) { + return USBD_REQ_NOTSUPP; + } + + if (iface->cur_altsetting) { + *iface->cur_altsetting = req->wValue; + } else if (req->wValue > 0) { + return USBD_REQ_NOTSUPP; + } + + if (usbd_dev->user_callback_set_altsetting) { + usbd_dev->user_callback_set_altsetting(usbd_dev, + req->wIndex, + req->wValue); + } + + *len = 0; + + return USBD_REQ_HANDLED; +} + +static int usb_standard_get_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + uint8_t *cur_altsetting; + const struct usb_config_descriptor *cfx = + &usbd_dev->config[usbd_dev->current_config - 1]; + + if (req->wIndex >= cfx->bNumInterfaces) { + return USBD_REQ_NOTSUPP; + } + + *len = 1; + cur_altsetting = cfx->interface[req->wIndex].cur_altsetting; + (*buf)[0] = (cur_altsetting) ? *cur_altsetting : 0; + + return USBD_REQ_HANDLED; +} + +static int usb_standard_device_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + + /* bit 0: self powered */ + /* bit 1: remote wakeup */ + if (*len > 2) { + *len = 2; + } + (*buf)[0] = 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_interface_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)usbd_dev; + (void)req; + /* not defined */ + + if (*len > 2) { + *len = 2; + } + (*buf)[0] = 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_endpoint_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)req; + + if (*len > 2) { + *len = 2; + } + (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0; + (*buf)[1] = 0; + + return 1; +} + +static int usb_standard_endpoint_stall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)buf; + (void)len; + + usbd_ep_stall_set(usbd_dev, req->wIndex, 1); + + return 1; +} + +static int usb_standard_endpoint_unstall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + (void)buf; + (void)len; + + usbd_ep_stall_set(usbd_dev, req->wIndex, 0); + + return 1; +} + +/* Do not appear to belong to the API, so are omitted from docs */ +/**@}*/ + +int _usbd_standard_request_device(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (req->wValue == USB_FEAT_DEVICE_REMOTE_WAKEUP) { + /* Device wakeup code goes here. */ + } + + if (req->wValue == USB_FEAT_TEST_MODE) { + /* Test mode code goes here. */ + } + + break; + case USB_REQ_SET_ADDRESS: + /* + * SET ADDRESS is an exception. + * It is only processed at STATUS stage. + */ + command = usb_standard_set_address; + break; + case USB_REQ_SET_CONFIGURATION: + command = usb_standard_set_configuration; + break; + case USB_REQ_GET_CONFIGURATION: + command = usb_standard_get_configuration; + break; + case USB_REQ_GET_DESCRIPTOR: + command = usb_standard_get_descriptor; + break; + case USB_REQ_GET_STATUS: + /* + * GET_STATUS always responds with zero reply. + * The application may override this behaviour. + */ + command = usb_standard_device_get_status; + break; + case USB_REQ_SET_DESCRIPTOR: + /* SET_DESCRIPTOR is optional and not implemented. */ + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + /* not defined */ + break; + case USB_REQ_GET_INTERFACE: + command = usb_standard_get_interface; + break; + case USB_REQ_SET_INTERFACE: + command = usb_standard_set_interface; + break; + case USB_REQ_GET_STATUS: + command = usb_standard_interface_get_status; + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request_endpoint(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) +{ + int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; + + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + if (req->wValue == USB_FEAT_ENDPOINT_HALT) { + command = usb_standard_endpoint_unstall; + } + break; + case USB_REQ_SET_FEATURE: + if (req->wValue == USB_FEAT_ENDPOINT_HALT) { + command = usb_standard_endpoint_stall; + } + break; + case USB_REQ_GET_STATUS: + command = usb_standard_endpoint_get_status; + break; + case USB_REQ_SET_SYNCH_FRAME: + /* FIXME: SYNCH_FRAME is not implemented. */ + /* + * SYNCH_FRAME is used for synchronization of isochronous + * endpoints which are not yet implemented. + */ + break; + } + + if (!command) { + return 0; + } + + return command(usbd_dev, req, buf, len); +} + +int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) +{ + /* FIXME: Have class/vendor requests as well. */ + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return 0; + } + + switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) { + case USB_REQ_TYPE_DEVICE: + return _usbd_standard_request_device(usbd_dev, req, buf, len); + case USB_REQ_TYPE_INTERFACE: + return _usbd_standard_request_interface(usbd_dev, req, + buf, len); + case USB_REQ_TYPE_ENDPOINT: + return _usbd_standard_request_endpoint(usbd_dev, req, buf, len); + default: + return 0; + } +} + diff --git a/util.c b/util.c index 575127421c..7d32092a8f 100644 --- a/util.c +++ b/util.c @@ -17,6 +17,7 @@ * along with this library. If not, see . */ +#include "rng.h" #include "util.h" inline void delay(uint32_t wait) @@ -24,6 +25,24 @@ inline void delay(uint32_t wait) while (--wait > 0) __asm__("nop"); } +void wait_random(void) +{ + int wait = random32() & 0xff; + volatile int i = 0; + volatile int j = wait; + while (i < wait) { + if (i + j != wait) { + shutdown(); + } + ++i; + --j; + } + // Double-check loop completion. + if (i != wait || j != 0) { + shutdown(); + } +} + static const char *hexdigits = "0123456789ABCDEF"; void uint32hex(uint32_t num, char *str) diff --git a/util.h b/util.h index bd95099082..31003ed69e 100644 --- a/util.h +++ b/util.h @@ -30,11 +30,14 @@ #endif // Statement expressions make these macros side-effect safe +#define MIN_8bits(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? (_a & 0xFF) : (_b & 0xFF); }) #define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) #define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) void delay(uint32_t wait); +void wait_random(void); + // converts uint32 to hexa (8 digits) void uint32hex(uint32_t num, char *str); diff --git a/webusb.c b/webusb.c index 7106187810..21c6d3b5e7 100644 --- a/webusb.c +++ b/webusb.c @@ -53,6 +53,8 @@ static int webusb_control_vendor_request(usbd_device *usbd_dev, (void)complete; (void)usbd_dev; + wait_random(); + if (req->bRequest != WEBUSB_VENDOR_CODE) { return USBD_REQ_NEXT_CALLBACK; } @@ -72,7 +74,7 @@ static int webusb_control_vendor_request(usbd_device *usbd_dev, url->bDescriptorType = WEBUSB_DT_URL; url->bScheme = WEBUSB_URL_SCHEME_HTTPS; memcpy(&url->URL, webusb_https_url, url_len); - *len = MIN(*len, url->bLength); + *len = MIN_8bits(*len, url->bLength); status = USBD_REQ_HANDLED; } else { // TODO: stall instead? diff --git a/winusb.c b/winusb.c index afdaf8b706..06321fd3dd 100644 --- a/winusb.c +++ b/winusb.c @@ -82,6 +82,8 @@ static int winusb_descriptor_request(usbd_device *usbd_dev, (void)complete; (void)usbd_dev; + wait_random(); + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { return USBD_REQ_NEXT_CALLBACK; } @@ -89,7 +91,7 @@ static int winusb_descriptor_request(usbd_device *usbd_dev, if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { *buf = (uint8_t*)(&winusb_string_descriptor); - *len = MIN(*len, winusb_string_descriptor.bLength); + *len = MIN_8bits(*len, winusb_string_descriptor.bLength); return USBD_REQ_HANDLED; } } @@ -103,6 +105,8 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev, (void)complete; (void)usbd_dev; + wait_random(); + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { return USBD_REQ_NEXT_CALLBACK; } @@ -111,7 +115,7 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev, if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { *buf = (uint8_t*)(&winusb_wcid); - *len = MIN(*len, winusb_wcid.header.dwLength); + *len = MIN_8bits(*len, winusb_wcid.header.dwLength); status = USBD_REQ_HANDLED; } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && @@ -119,7 +123,7 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev, (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { *buf = (uint8_t*)(&guid); - *len = MIN(*len, guid.header.dwLength); + *len = MIN_8bits(*len, guid.header.dwLength); status = USBD_REQ_HANDLED; } else { From d9841c29e4b7c280f71b719a93d54be27af37e4d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 12:44:29 +0100 Subject: [PATCH 1118/1154] vendor: update trezor-crypto --- vendor/trezor-crypto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-crypto b/vendor/trezor-crypto index 21391dc5be..4211ce389f 160000 --- a/vendor/trezor-crypto +++ b/vendor/trezor-crypto @@ -1 +1 @@ -Subproject commit 21391dc5be9917bc32a518cf98376f79103727af +Subproject commit 4211ce389f6795d844809b0ba66a84082038ca04 From b26e90daf986a21fc25eb2432c84b41ecfd23a82 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 14:23:34 +0100 Subject: [PATCH 1119/1154] firmware: add bootloader 1.8.0 to whitelist --- firmware/bl_check.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 5ca0a41c34..9be60836b5 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -44,6 +44,7 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 + if (0 == memcmp(hash, "\x53\xdd\xee\xef\x09\xb9\x0d\x36\xf6\x3a\x12\x85\xd0\x6d\xf2\xd3\x9d\xbf\x06\x83\x78\x30\x90\x3d\x57\x96\xbc\x2b\x3b\xa7\x36\x56", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 return 0; } From fe39d10211c53f81379b5cfd0f565e97cf94b27b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 14:51:45 +0100 Subject: [PATCH 1120/1154] vendor: update trezor-storage --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index d715873ee6..9100a3ee64 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit d715873ee62d776ddc0f85028f7622374d4e0fe7 +Subproject commit 9100a3ee640c6466d8638dd9ea2e906978b6e474 From 07231d936e41335b3ec44c4c6eb336be006890d0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 27 Jan 2019 11:58:30 +0100 Subject: [PATCH 1121/1154] introduce new memory layout firmware header is now stored with code, not within the storage sectors --- Makefile.include | 4 +- bootloader/bootloader.c | 80 +++--- bootloader/bootloader.h | 14 +- bootloader/firmware_align.py | 2 +- bootloader/firmware_sign.py | 133 +++++---- bootloader/firmware_sign_split.py | 8 +- bootloader/signatures.c | 120 +++++++- bootloader/signatures.h | 41 ++- bootloader/usb.c | 462 +++++++++++------------------- bootloader/usb.h | 2 +- bootloader/usb_desc.h | 75 +++++ bootloader/usb_erase.h | 44 +++ bootloader/usb_send.h | 86 ++++++ emulator/memory.c | 3 +- firmware/Makefile | 3 +- firmware/config.c | 11 +- firmware/header.S | 33 +++ firmware/trezor.h | 5 +- firmware/version.h | 7 + memory.c | 4 +- memory.h | 81 +++--- memory_app_1.8.0.ld | 31 ++ setup.c | 2 +- supervise.c | 6 +- 24 files changed, 774 insertions(+), 483 deletions(-) create mode 100644 bootloader/usb_desc.h create mode 100644 bootloader/usb_erase.h create mode 100644 bootloader/usb_send.h create mode 100644 firmware/header.S create mode 100644 firmware/version.h create mode 100644 memory_app_1.8.0.ld diff --git a/Makefile.include b/Makefile.include index fdf6b5fca5..029dddae7d 100644 --- a/Makefile.include +++ b/Makefile.include @@ -134,8 +134,10 @@ endif ifeq ($(MEMORY_PROTECT), 0) CFLAGS += -DMEMORY_PROTECT=0 +$(info MEMORY_PROTECT=0) else CFLAGS += -DMEMORY_PROTECT=1 +$(info MEMORY_PROTECT=1) endif ifeq ($(DEBUG_RNG), 1) @@ -159,7 +161,7 @@ flash: $(NAME).bin $(OPENOCD) -c "init; reset halt; flash write_image erase $(NAME).bin 0x8000000; exit" upload: sign - trezorctl firmware_update -f $(NAME).bin + trezorctl firmware_update -f $(NAME).bin -s sign: $(NAME).bin $(PYTHON) ../bootloader/firmware_sign.py -f $(NAME).bin diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 292632db29..4c561783f5 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -24,6 +24,7 @@ #include #include "bootloader.h" +#include "signatures.h" #include "buttons.h" #include "setup.h" #include "usb.h" @@ -33,8 +34,9 @@ #include "layout.h" #include "rng.h" #include "timer.h" +#include "memory.h" -void layoutFirmwareHash(const uint8_t *hash) +void layoutFirmwareFingerprint(const uint8_t *hash) { char str[4][17]; for (int i = 0; i < 4; i++) { @@ -43,40 +45,41 @@ void layoutFirmwareHash(const uint8_t *hash) layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); } -void show_halt(void) +bool get_button_response(void) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL); + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + return button.YesUp; +} + +static void show_halt(void) +{ + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); shutdown(); } -void show_unofficial_warning(const uint8_t *hash) +static void show_unofficial_warning(const uint8_t *hash) { layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - - if (button.NoUp) { - show_halt(); // no button was pressed -> halt + bool but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt(); } - layoutFirmwareHash(hash); + layoutFirmwareFingerprint(hash); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - - if (button.NoUp) { - show_halt(); // no button was pressed -> halt + but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt(); } // everything is OK, user pressed 2x Continue -> continue program } -void __attribute__((noreturn)) load_app(int signed_firmware) +static void __attribute__((noreturn)) load_app(int signed_firmware) { // zero out SRAM memset_reg(_ram_start, _ram_end, 0); @@ -84,27 +87,11 @@ void __attribute__((noreturn)) load_app(int signed_firmware) jump_to_firmware((const vector_table_t *) FLASH_PTR(FLASH_APP_START), signed_firmware); } -bool firmware_present(void) -{ -#ifndef APPVER - if (memcmp(FLASH_PTR(FLASH_META_MAGIC), "TRZR", 4)) { // magic does not match - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 4096) { // firmware reports smaller size than 4kB - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size - return false; - } -#endif - return true; -} - -void bootloader_loop(void) +static void bootloader_loop(void) { oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); - if (firmware_present()) { + if (firmware_present_new()) { oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); oledDrawStringCenter(90, 50, VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); @@ -115,7 +102,7 @@ void bootloader_loop(void) } oledRefresh(); - usbLoop(firmware_present()); + usbLoop(); } int main(void) @@ -136,19 +123,26 @@ int main(void) uint16_t state = gpio_port_read(BTN_PORT); int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); - if (firmware_present() && unpressed) { + if (firmware_present_new() && unpressed) { oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); - uint8_t hash[32]; - int signed_firmware = signatures_ok(hash); + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + + uint8_t fingerprint[32]; + int signed_firmware = signatures_new_ok(hdr, fingerprint); if (SIG_OK != signed_firmware) { - show_unofficial_warning(hash); + show_unofficial_warning(fingerprint); timer_init(); } + if (SIG_OK != check_firmware_hashes(hdr)) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware", "detected.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); + shutdown(); + } + mpu_config_off(); load_app(signed_firmware); } diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index c7f214f080..6f70df2278 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,20 +21,20 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 6 -#define VERSION_PATCH 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x06" -#define VERSION_PATCH_CHAR "\x01" +#define VERSION_MINOR_CHAR "\x08" +#define VERSION_PATCH_CHAR "\x00" +#include #include -#include "memory.h" -void layoutFirmwareHash(const uint8_t *hash); -bool firmware_present(void); +void layoutFirmwareFingerprint(const uint8_t *hash); +bool get_button_response(void); #endif diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index 3d766862fc..ab5b1c6bf4 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import os diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 2b3a2c17ef..a7b8e13cf6 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -7,10 +7,6 @@ import struct import ecdsa -try: - raw_input -except: - raw_input = input SLOTS = 3 @@ -22,8 +18,9 @@ pubkeys = { 5: "047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45", } -INDEXES_START = len("TRZR") + struct.calcsize(" size: + raise ValueError("Chunk too big already") + if len(data) == size: + return data + return data + b"\xFF" * (size - len(data)) - meta = b"TRZR" # magic - if data[:4] == b"TRZR": - meta += data[4 : 4 + struct.calcsize(" 0: + chunk = pad_to_size(sector, end - start) + hashes.append(hashlib.sha256(chunk).digest()) + else: + hashes.append(b"\x00" * 32) + start = end + end += 64 * 1024 + return hashes + + +def check_hashes(data): + expected_hashes = data[0x20 : 0x20 + 16 * 32] + hashes = b"" + for h in prepare_hashes(data[FWHEADER_SIZE:]): + hashes += h + + if expected_hashes == hashes: + print("HASHES OK") else: - meta += struct.pack(" SLOTS: raise Exception("Invalid slot") @@ -145,28 +171,28 @@ def sign(data, is_pem): print("(blank private key removes the signature on given index)") pem_key = "" while True: - key = raw_input() + key = input() pem_key += key + "\n" if key == "": break if pem_key.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, "\x00" * 64) + return modify(data, slot, 0, b"\x00" * 64) key = ecdsa.SigningKey.from_pem(pem_key) else: print("Paste SECEXP (in hex) and press Enter:") print("(blank private key removes the signature on given index)") - secexp = raw_input() + secexp = input() if secexp.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, "\x00" * 64) + return modify(data, slot, 0, b"\x00" * 64) key = ecdsa.SigningKey.from_secret_exponent( secexp=int(secexp, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256, ) - to_sign = prepare(data)[256:] # without meta + to_sign = get_header(data, zero_signatures=True) # Locate proper index of current signing key pubkey = "04" + key.get_verifying_key().to_string().hex() @@ -207,20 +233,21 @@ def main(args): data = open(args.path, "rb").read() assert len(data) % 4 == 0 - if data[:4] != b"TRZR": - print("Metadata has been added...") - data = prepare(data) - - if data[:4] != b"TRZR": + if data[:4] != b"TRZF": raise Exception("Firmware header expected") + data = update_hashes_in_header(data) + print("Firmware size %d bytes" % len(data)) + check_size(data) check_signatures(data) + check_hashes(data) if args.sign: data = sign(data, args.pem) check_signatures(data) + check_hashes(data) fp = open(args.path, "wb") fp.write(data) diff --git a/bootloader/firmware_sign_split.py b/bootloader/firmware_sign_split.py index 47b18e497a..25c4b341fd 100755 --- a/bootloader/firmware_sign_split.py +++ b/bootloader/firmware_sign_split.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 import hashlib import os import subprocess @@ -7,10 +6,7 @@ import ecdsa from binascii import hexlify, unhexlify print('master secret:', end='') -try: - h = raw_input() -except: - h = input() +h = input() if h: h = unhexlify(h).encode('ascii') else: diff --git a/bootloader/signatures.c b/bootloader/signatures.c index e178ecec7a..512117de57 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ -#include #include #include "signatures.h" @@ -25,6 +24,11 @@ #include "secp256k1.h" #include "sha2.h" #include "bootloader.h" +#include "memory.h" +#include "memzero.h" + +const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR +const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF #define PUBKEYS 5 @@ -38,19 +42,45 @@ static const uint8_t * const pubkey[PUBKEYS] = { #define SIGNATURES 3 -int signatures_ok(uint8_t *store_hash) +#define FLASH_META_START 0x08008000 +#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) +#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) +#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) +#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) +#define FLASH_OLD_APP_START 0x08010000 +#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) +#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) +#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) + +bool firmware_present_old(void) +{ + if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 8192) { // firmware reports smaller size than 8192 + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_APP_LEN) { // firmware reports bigger size than flash size + return false; + } + + return true; +} + +int signatures_old_ok(void) { const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3); - uint8_t hash[32]; - sha256_Raw((const uint8_t *)FLASH_APP_START, codelen, hash); - if (store_hash) { - memcpy(store_hash, hash, 32); + if (codelen > FLASH_APP_LEN) { + return false; } + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash); + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index @@ -71,3 +101,81 @@ int signatures_ok(uint8_t *store_hash) return SIG_OK; } + +void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) +{ + image_header copy; + memcpy(©, hdr, sizeof(image_header)); + memzero(copy.sig1, sizeof(copy.sig1)); + memzero(copy.sig2, sizeof(copy.sig2)); + memzero(copy.sig3, sizeof(copy.sig3)); + copy.sigindex1 = 0; + copy.sigindex2 = 0; + copy.sigindex3 = 0; + sha256_Raw((const uint8_t *)©, sizeof(image_header), hash); +} + +bool firmware_present_new(void) +{ + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; + if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; + if (hdr->codelen > FLASH_APP_LEN) return false; + if (hdr->codelen < 4096) return false; + + return true; +} + +int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) +{ + uint8_t hash[32]; + compute_firmware_fingerprint(hdr, hash); + + if (store_fingerprint) { + memcpy(store_fingerprint, hash, 32); + } + + if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index + if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index + if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index + + if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use + if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use + if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use + + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], hdr->sig1, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1], hdr->sig2, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], hdr->sig3, hash)) { // failure + return SIG_FAIL; + } + + return SIG_OK; +} + +int check_firmware_hashes(const image_header *hdr) +{ + uint8_t hash[32]; + // check hash of the first code chunk + sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); + if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL; + // check remaining used chunks + uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen; + int used_chunks = total_len / FW_CHUNK_SIZE; + if (total_len % FW_CHUNK_SIZE > 0) { + used_chunks++; + } + for (int i = 1; i < used_chunks; i++) { + sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, hash); + if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; + } + // check unused chunks + for (int i = used_chunks; i < 16; i++) { + if (0 != memcmp(hdr->hashes + 32 * i, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) return SIG_FAIL; + } + // all OK + return SIG_OK; +} diff --git a/bootloader/signatures.h b/bootloader/signatures.h index 01b5f308c1..ea4f8c2caf 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -20,9 +20,48 @@ #ifndef __SIGNATURES_H__ #define __SIGNATURES_H__ +#include +#include + +extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR +extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF + #define SIG_OK 0x5A3CA5C3 #define SIG_FAIL 0x00000000 -int signatures_ok(uint8_t *store_hash); +bool firmware_present_old(void); +int signatures_old_ok(void); + +// we use the same structure as T2 firmware header +// but we don't use the field sig +// and rather introduce fields sig1, sig2, sig3 +// immediately following the chunk hashes + +typedef struct { + uint32_t magic; + uint32_t hdrlen; + uint32_t expiry; + uint32_t codelen; + uint32_t version; + uint32_t fix_version; + uint8_t __reserved1[8]; + uint8_t hashes[512]; + uint8_t sig1[64]; + uint8_t sig2[64]; + uint8_t sig3[64]; + uint8_t sigindex1; + uint8_t sigindex2; + uint8_t sigindex3; + uint8_t __reserved2[220]; + uint8_t __sigmask; + uint8_t __sig[64]; +} __attribute__((packed)) image_header; + +#define FW_CHUNK_SIZE 65536 + +bool firmware_present_new(void); +void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]); +int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]); +int check_firmware_hashes(const image_header *hdr); #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 4532b6a1da..6af381606f 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -34,91 +34,15 @@ #include "ecdsa.h" #include "secp256k1.h" #include "memzero.h" +#include "memory.h" #include "usb21_standard.h" #include "webusb.h" #include "winusb.h" -#define FIRMWARE_MAGIC "TRZR" - -#define USB_INTERFACE_INDEX_MAIN 0 - -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) - -static bool brand_new_firmware; -static bool old_was_unsigned; - -static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x1209, - .idProduct = 0x53c0, - .bcdDevice = 0x0100, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, -}; - -static const struct usb_endpoint_descriptor endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = endpoints, - .extra = NULL, - .extralen = 0, -}}; - -static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = iface, -}}; - -static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, -}; - -static const char *usb_strings[] = { - "SatoshiLabs", - "TREZOR", - "000000000000000000000000", -}; +#include "usb_desc.h" +#include "usb_send.h" +#include "usb_erase.h" enum { STATE_READY, @@ -130,121 +54,77 @@ enum { }; static uint32_t flash_pos = 0, flash_len = 0; +static uint32_t chunk_idx = 0; static char flash_state = STATE_READY; -static uint8_t flash_anim = 0; -static uint16_t msg_id = 0xFFFF; -static uint32_t msg_size = 0; -static uint8_t meta_backup[FLASH_META_LEN]; +static uint32_t FW_HEADER[FLASH_FWHEADER_LEN/sizeof(uint32_t)]; +static uint32_t FW_CHUNK[FW_CHUNK_SIZE/sizeof(uint32_t)]; -static void send_msg_success(usbd_device *dev) +static void check_and_write_chunk(void) { - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Success message (id 2), payload len 0 - memcpy(response, - // header - "?##" - // msg_id - "\x00\x02" - // msg_size - "\x00\x00\x00\x00", - 9); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} - -static void send_msg_failure(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Failure message (id 3), payload len 2 - // - code = 99 (Failure_FirmwareError) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x03" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x63", - 11); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} - -static void send_msg_features(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Features message (id 17), payload len 25 - // - vendor = "trezor.io" - // - major_version = VERSION_MAJOR - // - minor_version = VERSION_MINOR - // - patch_version = VERSION_PATCH - // - bootloader_mode = True - // - firmware_present = True/False - // - model = "1" - memcpy(response, - // header - "?##" - // msg_id - "\x00\x11" - // msg_size - "\x00\x00\x00\x16" - // data - "\x0a" "\x09" "trezor.io" - "\x10" VERSION_MAJOR_CHAR - "\x18" VERSION_MINOR_CHAR - "\x20" VERSION_PATCH_CHAR - "\x28" "\x01" - "\x90\x01" "\x00" - "\xaa" "\x01" "1", - 34); - response[30] = brand_new_firmware ? 0x01 : 0x00; - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} - -static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: ButtonRequest message (id 26), payload len 2 - // - code = ButtonRequest_FirmwareCheck (9) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x1a" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x09", - 11 - ); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} - -static void backup_metadata(uint8_t *backup) -{ - memcpy(backup, FLASH_PTR(FLASH_META_START), FLASH_META_LEN); -} - -static void restore_metadata(const uint8_t *backup) -{ - flash_unlock(); - for (int i = 0; i < FLASH_META_LEN / 4; i++) { - const uint32_t *w = (const uint32_t *)(backup + i * 4); - flash_program_word(FLASH_META_START + i * 4, *w); + uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; + uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; + if (chunk_pos == 0) { + chunk_pos = FW_CHUNK_SIZE; } + uint8_t hash[32]; + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset); + if (chunk_pos < 64 * 1024) { + // pad with FF + for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) { + sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4); + } + } + sha256_Final(&ctx, hash); + + const image_header *hdr = (const image_header *)FW_HEADER; + // invalid chunk sent + if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) { + // erase storage + erase_storage(); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } + + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]); + } + flash_wait_for_last_operation(); flash_lock(); + + // all done + if (flash_len == flash_pos) { + // check remaining chunks if any + for (uint32_t i = chunk_idx + 1; i < 16; i++) { + // hash should be empty if the chunk is unused + if (0 != memcmp(hdr->hashes + i * 32, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) { + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } + } + } + + memzero(FW_CHUNK, sizeof(FW_CHUNK)); + chunk_idx++; } static void rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; + static uint16_t msg_id = 0xFFFF; static uint8_t buf[64] __attribute__((aligned(4))); - static uint8_t towrite[4] __attribute__((aligned(4))); + static uint32_t w; static int wi; + static int old_was_signed; if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; @@ -258,7 +138,6 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } // struct.unpack(">HL") => msg, size msg_id = (buf[3] << 8) + buf[4]; - msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; } if (flash_state == STATE_READY || flash_state == STATE_OPEN) { @@ -277,26 +156,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } if (msg_id == 0x0005) { // WipeDevice message (id 5) layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - if (button.YesUp) { - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // erase metadata area - for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // erase code area - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_wait_for_last_operation(); - flash_lock(); + bool but = get_button_response(); + if (but) { + erase_storage_code_progress(); flash_state = STATE_END; layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); send_msg_success(dev); @@ -311,59 +173,31 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_OPEN) { if (msg_id == 0x0006) { // FirmwareErase message (id 6) - if (!brand_new_firmware) { + bool proceed = false; + if (firmware_present_new()) { layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); + proceed = get_button_response(); + } else { + proceed = true; } - if (brand_new_firmware || button.YesUp) { - // check whether current firmware is signed - if (!brand_new_firmware && SIG_OK == signatures_ok(NULL)) { - old_was_unsigned = false; - // backup metadata - backup_metadata(meta_backup); + if (proceed) { + // check whether the current firmware is signed (old or new method) + if (firmware_present_new()) { + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + old_was_signed = (SIG_OK == signatures_new_ok(hdr, NULL)) && (SIG_OK == check_firmware_hashes(hdr)); + } else if (firmware_present_old()) { + old_was_signed = signatures_old_ok(); } else { - old_was_unsigned = true; + old_was_signed = SIG_FAIL; } - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // erase metadata area - for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // erase code area - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - layoutProgress("INSTALLING ... Please wait", 0); - flash_wait_for_last_operation(); - flash_lock(); - - // check that metadata was succesfully erased - // flash status register should show now error and - // the config block should contain only \xff. - uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_META_START), FLASH_META_LEN, hash); - if ((FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) != 0 - || memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { - send_msg_failure(dev); - flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - return; - } - + erase_code_progress(); send_msg_success(dev); flash_state = STATE_FLASHSTART; - return; + } else { + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); } - send_msg_failure(dev); - flash_state = STATE_END; - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); return; } return; @@ -375,41 +209,47 @@ static void rx_callback(usbd_device *dev, uint8_t ep) send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); return; } // read payload length const uint8_t *p = buf + 10; flash_len = readprotobufint(&p); - if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big + if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too small.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + return; + } + if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } // check firmware magic - if (memcmp(p, FIRMWARE_MAGIC, 4) != 0) { + if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Wrong firmware header.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } + memzero(FW_HEADER, sizeof(FW_HEADER)); + memzero(FW_CHUNK, sizeof(FW_CHUNK)); flash_state = STATE_FLASHING; - p += 4; // Don't flash firmware header yet. - flash_pos = 4; - wi = 0; - flash_unlock(); + flash_pos = 0; + chunk_idx = 0; + w = 0; while (p < buf + 64) { - towrite[wi] = *p; + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w wi++; if (wi == 4) { - const uint32_t *w = (uint32_t *)towrite; - flash_program_word(FLASH_META_START + flash_pos, *w); + FW_HEADER[flash_pos / 4] = w; flash_pos += 4; wi = 0; } p++; } - flash_lock(); return; } return; @@ -420,34 +260,44 @@ static void rx_callback(usbd_device *dev, uint8_t ep) send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); return; } - const uint8_t *p = buf + 1; + + static uint8_t flash_anim = 0; if (flash_anim % 32 == 4) { layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); } flash_anim++; - flash_unlock(); + + const uint8_t *p = buf + 1; while (p < buf + 64 && flash_pos < flash_len) { - towrite[wi] = *p; + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w wi++; if (wi == 4) { - const uint32_t *w = (const uint32_t *)towrite; - if (flash_pos < FLASH_META_DESC_LEN) { - flash_program_word(FLASH_META_START + flash_pos, *w); // the first 256 bytes of firmware is metadata descriptor + if (flash_pos < FLASH_FWHEADER_LEN) { + FW_HEADER[flash_pos / 4] = w; } else { - flash_program_word(FLASH_APP_START + (flash_pos - FLASH_META_DESC_LEN), *w); // the rest is code + FW_CHUNK[(flash_pos % FW_CHUNK_SIZE)/ 4] = w; } flash_pos += 4; wi = 0; + // finished the whole chunk + if (flash_pos % FW_CHUNK_SIZE == 0) { + check_and_write_chunk(); + } } p++; } - flash_lock(); // flashing done if (flash_pos == flash_len) { + // flush remaining data in the last chunk + if (flash_pos % FW_CHUNK_SIZE > 0) { + check_and_write_chunk(); + } flash_state = STATE_CHECK; - if (!brand_new_firmware) { + const image_header *hdr = (const image_header *)FW_HEADER; + if (SIG_OK != signatures_new_ok(hdr, NULL)) { send_msg_buttonrequest_firmwarecheck(dev); return; } @@ -458,55 +308,69 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_CHECK) { - if (!brand_new_firmware) { + // use the firmware header from RAM + const image_header *hdr = (const image_header *)FW_HEADER; + + bool hash_check_ok; + // show fingerprint of unsigned firmware + if (SIG_OK != signatures_new_ok(hdr, NULL)) { if (msg_id != 0x001B) { // ButtonAck message (id 27) return; } uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_APP_START), flash_len - FLASH_META_DESC_LEN, hash); - layoutFirmwareHash(hash); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); + compute_firmware_fingerprint(hdr, hash); + layoutFirmwareFingerprint(hash); + hash_check_ok = get_button_response(); + } else { + hash_check_ok = true; } - bool hash_check_ok = brand_new_firmware || button.YesUp; - layoutProgress("INSTALLING ... Please wait", 1000); - uint8_t flags = *FLASH_PTR(FLASH_META_FLAGS); // wipe storage if: - // 0) there was no firmware - // 1) old firmware was unsigned - // 2) firmware restore flag isn't set - // 3) signatures are not ok - if (brand_new_firmware || old_was_unsigned || (flags & 0x01) == 0 || SIG_OK != signatures_ok(NULL)) { - memzero(meta_backup, sizeof(meta_backup)); + // 1) old firmware was unsigned or not present + // 2) signatures are not OK + // 3) hashes are not OK + if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || SIG_OK != check_firmware_hashes(hdr)) { + // erase storage + erase_storage(); + // check erasure + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); + if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { + send_msg_failure(dev); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } } - // copy new firmware header - memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); - // write "TRZR" in header only when hash was confirmed + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // write firmware header only when hash was confirmed if (hash_check_ok) { - memcpy(meta_backup, FIRMWARE_MAGIC, 4); + for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), FW_HEADER[i]); + } } else { - memzero(meta_backup, 4); + for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0); + } } - - // no need to erase, because we are not changing any already flashed byte. - restore_metadata(meta_backup); - memzero(meta_backup, sizeof(meta_backup)); + flash_wait_for_last_operation(); + flash_lock(); flash_state = STATE_END; if (hash_check_ok) { layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); send_msg_success(dev); + shutdown(); } else { layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); send_msg_failure(dev); + shutdown(); } return; } - } static void set_config(usbd_device *dev, uint16_t wValue) @@ -531,7 +395,7 @@ static const struct usb_bos_descriptor bos_descriptor = { .capabilities = capabilities }; -void usbInit(void) +static void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, set_config); @@ -540,7 +404,7 @@ void usbInit(void) winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } -void checkButtons(void) +static void checkButtons(void) { static bool btn_left = false, btn_right = false, btn_final = false; if (btn_final) { @@ -569,13 +433,13 @@ void checkButtons(void) } } -void usbLoop(bool firmware_present) +void usbLoop(void) { - brand_new_firmware = !firmware_present; + bool firmware_present = firmware_present_new(); usbInit(); for (;;) { usbd_poll(usbd_dev); - if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { + if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { checkButtons(); } } diff --git a/bootloader/usb.h b/bootloader/usb.h index fea6e680e7..da506471ac 100644 --- a/bootloader/usb.h +++ b/bootloader/usb.h @@ -20,6 +20,6 @@ #ifndef __USB_H__ #define __USB_H__ -void usbLoop(bool firmware_present); +void usbLoop(void); #endif diff --git a/bootloader/usb_desc.h b/bootloader/usb_desc.h new file mode 100644 index 0000000000..d4044b9300 --- /dev/null +++ b/bootloader/usb_desc.h @@ -0,0 +1,75 @@ +#define USB_INTERFACE_INDEX_MAIN 0 + +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) + +static const struct usb_device_descriptor dev_descr = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0210, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x53c0, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +static const struct usb_endpoint_descriptor endpoints[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SatoshiLabs", + "TREZOR", + "000000000000000000000000", +}; diff --git a/bootloader/usb_erase.h b/bootloader/usb_erase.h new file mode 100644 index 0000000000..cadcf45730 --- /dev/null +++ b/bootloader/usb_erase.h @@ -0,0 +1,44 @@ +static void erase_storage_code_progress(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // erase storage area + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // erase code area + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); +} + +static void erase_code_progress(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_CODE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + layoutProgress("INSTALLING ... Please wait", 0); + flash_wait_for_last_operation(); + flash_lock(); +} + +static void erase_storage(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); +} diff --git a/bootloader/usb_send.h b/bootloader/usb_send.h new file mode 100644 index 0000000000..ed73fbe08b --- /dev/null +++ b/bootloader/usb_send.h @@ -0,0 +1,86 @@ +static void send_msg_success(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Success message (id 2), payload len 0 + memcpy(response, + // header + "?##" + // msg_id + "\x00\x02" + // msg_size + "\x00\x00\x00\x00", + 9); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_failure(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Failure message (id 3), payload len 2 + // - code = 99 (Failure_FirmwareError) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x03" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x63", + 11); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_features(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Features message (id 17), payload len 25 + // - vendor = "trezor.io" + // - major_version = VERSION_MAJOR + // - minor_version = VERSION_MINOR + // - patch_version = VERSION_PATCH + // - bootloader_mode = True + // - firmware_present = True/False + // - model = "1" + memcpy(response, + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x16" + // data + "\x0a" "\x09" "trezor.io" + "\x10" VERSION_MAJOR_CHAR + "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" "\x01" + "\x90\x01" "\x00" + "\xaa" "\x01" "1", + 34); + response[30] = firmware_present_new() ? 0x01 : 0x00; + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: ButtonRequest message (id 26), payload len 2 + // - code = ButtonRequest_FirmwareCheck (9) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x1a" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x09", + 11 + ); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} diff --git a/emulator/memory.c b/emulator/memory.c index 02b2a4ec71..4bcda38863 100644 --- a/emulator/memory.c +++ b/emulator/memory.c @@ -128,8 +128,7 @@ void svc_flash_program(uint32_t size) { } void svc_flash_erase_sector(uint16_t sector) { assert (!flash_locked); - assert (sector >= FLASH_META_SECTOR_FIRST && - sector <= FLASH_META_SECTOR_LAST); + assert (sector >= FLASH_STORAGE_SECTOR_FIRST && sector <= FLASH_STORAGE_SECTOR_LAST); flash_erase_sector(sector, 3); } uint32_t svc_flash_lock(void) { diff --git a/firmware/Makefile b/firmware/Makefile index 91e84acadc..a21f0cd26b 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,4 +1,4 @@ -APPVER = 1.0.0 +APPVER = 1.8.0 NAME = trezor @@ -8,6 +8,7 @@ else OBJS += usb.o OBJS += bl_check.o OBJS += otp.o +OBJS += header.o endif OBJS += u2f.o diff --git a/firmware/config.c b/firmware/config.c index b2042acbfa..6656b7f89a 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -197,12 +197,15 @@ static secbool config_get_uint32(uint16_t key, uint32_t *value) return sectrue; } +#define FLASH_META_START 0x08008000 +#define FLASH_META_LEN 0x100 + static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - if (memcmp(FLASH_PTR(FLASH_META_MAGIC), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || - memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || + memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic return secfalse; } @@ -210,8 +213,8 @@ static secbool config_upgrade_v10(void) Storage config __attribute__((aligned(4))); _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); - memcpy(config_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); - memcpy(&config, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); + memcpy(config_uuid, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); + memcpy(&config, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); // version 1: since 1.0.0 // version 2: since 1.2.1 diff --git a/firmware/header.S b/firmware/header.S new file mode 100644 index 0000000000..9333fb238c --- /dev/null +++ b/firmware/header.S @@ -0,0 +1,33 @@ + .syntax unified + +#include "version.h" + + .section .header, "a" + + .type g_header, %object + .size g_header, .-g_header + +g_header: + .byte 'T','R','Z','F' // magic + .word g_header_end - g_header // hdrlen + .word 0 // expiry + .word _codelen // codelen + .byte VERSION_MAJOR // vmajor + .byte VERSION_MINOR // vminor + .byte VERSION_PATCH // vpatch + .byte 0 // vbuild + .byte FIX_VERSION_MAJOR // fix_vmajor + .byte FIX_VERSION_MINOR // fix_vminor + .byte FIX_VERSION_PATCH // fix_vpatch + .byte 0 // fix_vbuild + . = . + 8 // reserved + . = . + 512 // hash1 ... hash16 + . = . + 64 // sig1 + . = . + 64 // sig2 + . = . + 64 // sig3 + .byte 0 // sigindex1 + .byte 0 // sigindex2 + .byte 0 // sigindex3 + . = . + 220 // reserved + . = . + 65 // reserved +g_header_end: diff --git a/firmware/trezor.h b/firmware/trezor.h index 65a5158904..9975a997b7 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,10 +21,7 @@ #define __TREZOR_H__ #include - -#define VERSION_MAJOR 1 -#define VERSION_MINOR 8 -#define VERSION_PATCH 0 +#include "version.h" #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/firmware/version.h b/firmware/version.h new file mode 100644 index 0000000000..1202e1b44f --- /dev/null +++ b/firmware/version.h @@ -0,0 +1,7 @@ +#define VERSION_MAJOR 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 + +#define FIX_VERSION_MAJOR 1 +#define FIX_VERSION_MINOR 8 +#define FIX_VERSION_PATCH 0 diff --git a/memory.c b/memory.c index 11c550b6e6..b11e046b20 100644 --- a/memory.c +++ b/memory.c @@ -34,7 +34,9 @@ void memory_protect(void) if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { return; // already set up correctly - bail out } - + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } flash_unlock_option_bytes(); // Section 2.8.6 Flash option control register (FLASH_OPTCR) // Bits 31:28 Reserved, must be kept cleared. diff --git a/memory.h b/memory.h index eac09efa5f..e47fc29172 100644 --- a/memory.h +++ b/memory.h @@ -24,43 +24,37 @@ /* - flash memory layout: + Flash memory layout: name | range | size | function -----------+-------------------------+---------+------------------ - Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader code - Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader code + Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader + Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader -----------+-------------------------+---------+------------------ - Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | metadata area - Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | metadata area + Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | storage area + Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | storage area -----------+-------------------------+---------+------------------ - Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | application code - Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | application code - Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | application code - Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | application code -===========+=========================+============================ - Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | application code - Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | application code - Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | application code - Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | application code + Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | firmware + Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | firmware + Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | firmware + Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | firmware + Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | firmware + Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | firmware + Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | firmware + Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | firmware - metadata area: + firmware header (occupies first 1 KB of the firmware) + - very similar to trezor-core firmware header described in: + https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md#firmware-header + - differences: + * we don't use sigmask or sig field (these are reserved and set to zero) + * we introduce new fields immediately following the hash16 field: + - sig1[64], sig2[64], sig3[64] + - sigindex1[1], sigindex2[1], sigindex3[1] + * reserved[415] area is reduced to reserved[220] + - see signatures.c for more details - offset | type/length | description ---------+-------------+------------------------------- - 0x0000 | 4 bytes | magic = 'TRZR' - 0x0004 | uint32 | length of the code (codelen) - 0x0008 | uint8 | signature index #1 - 0x0009 | uint8 | signature index #2 - 0x000A | uint8 | signature index #3 - 0x000B | uint8 | flags - 0x000C | 52 bytes | reserved - 0x0040 | 64 bytes | signature #1 - 0x0080 | 64 bytes | signature #2 - 0x00C0 | 64 bytes | signature #3 - 0x0100 | 32K-256 B | persistent storage - - flags & 0x01 -> restore storage after flashing (if signatures are ok) + We pad the firmware chunks with zeroes if they are shorted. */ @@ -78,31 +72,20 @@ extern uint8_t *emulator_flash_base; #define FLASH_BOOT_START (FLASH_ORIGIN) #define FLASH_BOOT_LEN (0x8000) -#define FLASH_META_START (FLASH_BOOT_START + FLASH_BOOT_LEN) -#define FLASH_META_LEN (0x8000) +#define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN) +#define FLASH_STORAGE_LEN (0x8000) -#define FLASH_APP_START (FLASH_META_START + FLASH_META_LEN) +#define FLASH_FWHEADER_START (FLASH_STORAGE_START + FLASH_STORAGE_LEN) +#define FLASH_FWHEADER_LEN (0x400) -#define FLASH_META_MAGIC (FLASH_META_START) -#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) -#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) -#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) -#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) -#define FLASH_META_FLAGS (FLASH_META_START + 0x000B) -#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) -#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) -#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) - -#define FLASH_META_DESC_LEN (0x100) - -#define FLASH_STORAGE_START (FLASH_META_START + FLASH_META_DESC_LEN) -#define FLASH_STORAGE_LEN (FLASH_APP_START - FLASH_STORAGE_START) +#define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN) +#define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) #define FLASH_BOOT_SECTOR_FIRST 0 #define FLASH_BOOT_SECTOR_LAST 1 -#define FLASH_META_SECTOR_FIRST 2 -#define FLASH_META_SECTOR_LAST 3 +#define FLASH_STORAGE_SECTOR_FIRST 2 +#define FLASH_STORAGE_SECTOR_LAST 3 #define FLASH_CODE_SECTOR_FIRST 4 #define FLASH_CODE_SECTOR_LAST 11 diff --git a/memory_app_1.8.0.ld b/memory_app_1.8.0.ld new file mode 100644 index 0000000000..77a3ec2a0c --- /dev/null +++ b/memory_app_1.8.0.ld @@ -0,0 +1,31 @@ +/* STM32F205RG - 1024K Flash, 128K RAM */ +/* program starts at 0x08010100 */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +SECTIONS +{ + .confidential (NOLOAD) : { + *(confidential) + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + } >ram + + .header : ALIGN(4) { + KEEP(*(.header)); + } >rom AT>rom +} + +INCLUDE libopencm3_stm32f2.ld + +_codelen = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.exidx); + +_ram_start = ORIGIN(ram); +_ram_end = ORIGIN(ram) + LENGTH(ram); +_stack = _ram_end - 8; +__stack_chk_guard = _ram_end - 8; +system_millis = _ram_end - 4; + +_data_size = SIZEOF(.data); diff --git a/setup.c b/setup.c index e554ad17a9..e1fab1020b 100644 --- a/setup.c +++ b/setup.c @@ -33,7 +33,7 @@ uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever + shutdown(); } void __attribute__((noreturn)) __stack_chk_fail(void) { diff --git a/supervise.c b/supervise.c index 7669cc5ed0..5a86db884c 100644 --- a/supervise.c +++ b/supervise.c @@ -45,9 +45,9 @@ static void svhandler_flash_program(uint32_t psize) { } static void svhandler_flash_erase_sector(uint16_t sector) { - /* we only allow erasing meta sectors 2 and 3. */ - if (sector < FLASH_META_SECTOR_FIRST || - sector > FLASH_META_SECTOR_LAST) { + /* we only allow erasing storage sectors 2 and 3. */ + if (sector < FLASH_STORAGE_SECTOR_FIRST || + sector > FLASH_STORAGE_SECTOR_LAST) { return; } flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); From 400ac968730e94d2868e4f54058e7e4ff1e1d33d Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 15:18:00 +0100 Subject: [PATCH 1122/1154] bootloader: refactor to save space --- bootloader/bootloader.c | 8 ++++---- bootloader/bootloader.h | 1 + bootloader/firmware_align.py | 9 ++++++--- bootloader/signatures.c | 10 +++++++++- bootloader/signatures.h | 2 ++ bootloader/usb.c | 23 +++++++++-------------- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 4c561783f5..85baf84333 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -54,9 +54,9 @@ bool get_button_response(void) return button.YesUp; } -static void show_halt(void) +void show_halt(const char *line1, const char *line2) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); shutdown(); } @@ -66,14 +66,14 @@ static void show_unofficial_warning(const uint8_t *hash) bool but = get_button_response(); if (!but) { // no button was pressed -> halt - show_halt(); + show_halt("Unofficial firmware", "aborted."); } layoutFirmwareFingerprint(hash); but = get_button_response(); if (!but) { // no button was pressed -> halt - show_halt(); + show_halt("Unofficial firmware", "aborted."); } // everything is OK, user pressed 2x Continue -> continue program diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 6f70df2278..1217569b5a 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -34,6 +34,7 @@ #include #include +void show_halt(const char *line1, const char *line2); void layoutFirmwareFingerprint(const uint8_t *hash); bool get_button_response(void); diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index ab5b1c6bf4..3c1434987e 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -2,10 +2,13 @@ import sys import os +TOTALSIZE = 32768 +MAXSIZE = TOTALSIZE - 32 + fn = sys.argv[1] fs = os.stat(fn).st_size -if fs > 32768: - raise Exception('bootloader has to be smaller than 32768 bytes') +if fs > MAXSIZE: + raise Exception('bootloader has to be smaller than %d bytes (current size is %d)' % (MAXSIZE, fs)) with open(fn, 'ab') as f: - f.write(b'\x00' * (32768 - fs)) + f.write(b'\x00' * (TOTALSIZE - fs)) f.close() diff --git a/bootloader/signatures.c b/bootloader/signatures.c index 512117de57..37e5f67b8c 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -156,6 +156,14 @@ int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) return SIG_OK; } +int mem_is_empty(const uint8_t *src, uint32_t len) +{ + for (uint32_t i = 0; i < len; i++) { + if (src[i]) return 0; + } + return 1; +} + int check_firmware_hashes(const image_header *hdr) { uint8_t hash[32]; @@ -174,7 +182,7 @@ int check_firmware_hashes(const image_header *hdr) } // check unused chunks for (int i = used_chunks; i < 16; i++) { - if (0 != memcmp(hdr->hashes + 32 * i, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) return SIG_FAIL; + if (!mem_is_empty(hdr->hashes + 32 * i, 32)) return SIG_FAIL; } // all OK return SIG_OK; diff --git a/bootloader/signatures.h b/bootloader/signatures.h index ea4f8c2caf..6d3c00f969 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -64,4 +64,6 @@ void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]); int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]); int check_firmware_hashes(const image_header *hdr); +int mem_is_empty(const uint8_t *src, uint32_t len); + #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 6af381606f..efedcef72b 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -85,8 +85,7 @@ static void check_and_write_chunk(void) // erase storage erase_storage(); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - shutdown(); + show_halt("Error installing", "firmware."); return; } @@ -104,10 +103,9 @@ static void check_and_write_chunk(void) // check remaining chunks if any for (uint32_t i = chunk_idx + 1; i < 16; i++) { // hash should be empty if the chunk is unused - if (0 != memcmp(hdr->hashes + i * 32, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) { + if (!mem_is_empty(hdr->hashes + 32 * i, 32)) { flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - shutdown(); + show_halt("Error installing", "firmware."); return; } } @@ -208,8 +206,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (buf[9] != 0x0a) { // invalid contents send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - shutdown(); + show_halt("Error installing", "firmware."); return; } // read payload length @@ -218,20 +215,20 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too small.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + show_halt("Firmware is too small.", NULL); return; } if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + show_halt("Firmware is too big.", NULL); return; } // check firmware magic if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Wrong firmware header.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + show_halt("Wrong firmware header.", NULL); return; } memzero(FW_HEADER, sizeof(FW_HEADER)); @@ -259,8 +256,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (buf[0] != '?') { // invalid contents send_msg_failure(dev); flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - shutdown(); + show_halt("Error installing", "firmware."); return; } @@ -338,8 +334,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { send_msg_failure(dev); - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - shutdown(); + show_halt("Error installing", "firmware."); return; } } From 80840b23212bc87254bba2bc1e2c7fd6089be0cb Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 17:24:58 +0100 Subject: [PATCH 1123/1154] firmware: change bootloader 1.8.0 hash in the whitelist --- firmware/bl_check.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 9be60836b5..50c8ac488a 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -44,7 +44,7 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 - if (0 == memcmp(hash, "\x53\xdd\xee\xef\x09\xb9\x0d\x36\xf6\x3a\x12\x85\xd0\x6d\xf2\xd3\x9d\xbf\x06\x83\x78\x30\x90\x3d\x57\x96\xbc\x2b\x3b\xa7\x36\x56", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 + if (0 == memcmp(hash, "\xaf\x19\x47\x7b\xf1\x4c\x33\x81\x34\x78\xd3\x29\x46\x58\x3b\x5d\xcf\xb2\x13\xc5\xba\x92\x81\x1e\x46\x50\x8e\xd0\x14\xb7\xa6\x14", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 return 0; } From 08b462b2b94d6b4c907a0a3be08a8f0df40ccc3c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 17:42:36 +0100 Subject: [PATCH 1124/1154] vendor: update trezor-storage --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 9100a3ee64..a109cc26c0 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 9100a3ee640c6466d8638dd9ea2e906978b6e474 +Subproject commit a109cc26c066e4bbd72dd69dc0a5db05be67491e From 276cd4b44addf6fc1295c1d0823530c3f4904a8b Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 21 Feb 2019 20:39:44 +0100 Subject: [PATCH 1125/1154] firmware: set NORCOW_HEADER_LEN to 0 --- norcow_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/norcow_config.h b/norcow_config.h index ba57dfb4b2..1ea894c2b5 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -29,7 +29,7 @@ /* * The length of the sector header in bytes. The header is preserved between sector erasures. */ -#define NORCOW_HEADER_LEN (0x100) +#define NORCOW_HEADER_LEN (0) /* * Current storage version. From a7a9eab4454e2f3756ca4bb0d42028c0691412df Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 22 Feb 2019 13:33:18 +0100 Subject: [PATCH 1126/1154] config: Fix pointer arithmetic in config_upgrade_v10(). --- firmware/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/config.c b/firmware/config.c index 6656b7f89a..0e6715e2fd 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -255,7 +255,7 @@ static secbool config_upgrade_v10(void) // Erase newly added fields. if (old_config_size != sizeof(Storage)) { - memzero(&config + old_config_size, sizeof(Storage) - old_config_size); + memzero((char*)&config + old_config_size, sizeof(Storage) - old_config_size); } const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; From 99c6777c7c45fa02230fe6590c423313f3340bb5 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Feb 2019 13:47:43 +0100 Subject: [PATCH 1127/1154] vendor: update trezor-storage --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index a109cc26c0..24df1ca2b7 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit a109cc26c066e4bbd72dd69dc0a5db05be67491e +Subproject commit 24df1ca2b768d62162e9ab95602698d26c371746 From 806f943116f4df8a666b6bd7182bfcbe5cf3c13a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 22 Feb 2019 15:47:34 +0100 Subject: [PATCH 1128/1154] bootloader: require only left button to start the bootloader --- bootloader/bootloader.c | 6 ++---- buttons.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 85baf84333..2497b13856 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -119,11 +119,9 @@ int main(void) mpu_config_bootloader(); #ifndef APPVER - // at least one button is unpressed - uint16_t state = gpio_port_read(BTN_PORT); - int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); + bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0; - if (firmware_present_new() && unpressed) { + if (firmware_present_new() && !left_pressed) { oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); diff --git a/buttons.c b/buttons.c index a6e64b5ad6..f416736c38 100644 --- a/buttons.c +++ b/buttons.c @@ -29,10 +29,9 @@ uint16_t buttonRead(void) { void buttonUpdate() { - uint16_t state; static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; - state = buttonRead(); + uint16_t state = buttonRead(); if ((state & BTN_PIN_YES) == 0) { // Yes button is down if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down From ae0395f0f417f1e4c72a924e3ac0e1d948613f77 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Fri, 22 Feb 2019 18:48:04 +0100 Subject: [PATCH 1129/1154] protect: Update protectPinUiCallback() to show arbitrary message. --- firmware/protect.c | 4 ++-- firmware/protect.h | 2 +- vendor/trezor-storage | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/protect.c b/firmware/protect.c index 99223ae332..0616aca64a 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -147,7 +147,7 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } -secbool protectPinUiCallback(uint32_t wait, uint32_t progress) +secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message) { // Convert wait to secstr string. char secstrbuf[] = _("________0 seconds"); @@ -163,7 +163,7 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) secstrbuf[16] = 0; } oledClear(); - oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, _("Verifying PIN"), FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), FONT_STANDARD); diff --git a/firmware/protect.h b/firmware/protect.h index bcabdac674..fb269468fc 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -25,7 +25,7 @@ #include "secbool.h" bool protectButton(ButtonRequestType type, bool confirm_only); -secbool protectPinUiCallback(uint32_t wait, uint32_t progress); +secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message); bool protectPin(bool use_cached); bool protectChangePin(bool removal); bool protectPassphrase(void); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 24df1ca2b7..0e897f673a 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 24df1ca2b768d62162e9ab95602698d26c371746 +Subproject commit 0e897f673a2150607bae553e21604b253352644e From 2482e111126821273cf4a6782305dddd3fbdc5e3 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 23 Feb 2019 02:00:16 +0100 Subject: [PATCH 1130/1154] protect: check old PIN before requesting new PIN --- firmware/protect.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/firmware/protect.c b/firmware/protect.c index 0616aca64a..5f7135d4e5 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -225,6 +225,18 @@ bool protectChangePin(bool removal) fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } + + // If removing, defer the check to config_changePin(). + if (!removal) { + usbTiny(1); + bool ret = config_containsPin(pin); + usbTiny(0); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; + } + } + strlcpy(old_pin, pin, sizeof(old_pin)); } From db47ff4e515bcd3c28abffa955393a8743744e88 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 23 Feb 2019 02:11:13 +0100 Subject: [PATCH 1131/1154] config: Auto-unlock storage if no PIN is set. Update trezor-storage with improved ui_callback() reporting. --- firmware/config.c | 5 +++++ vendor/trezor-storage | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/firmware/config.c b/firmware/config.c index 0e6715e2fd..799cc09736 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -365,6 +365,11 @@ void config_init(void) } else { config_wipe(); } + + // Auto-unlock storage if no PIN is set. + if (storage_is_unlocked() == secfalse && storage_has_pin() == secfalse) { + storage_unlock(PIN_EMPTY); + } } void session_clear(bool lock) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 0e897f673a..511fc205b2 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 0e897f673a2150607bae553e21604b253352644e +Subproject commit 511fc205b284605651348512c5c5c2c95a642fa1 From b62ab43b952d902a63998d0cd9b554a336ee7c7e Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 23 Feb 2019 03:02:24 +0100 Subject: [PATCH 1132/1154] config: Avoid wiping storage twice. --- firmware/config.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 799cc09736..b3b6df500a 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -359,17 +359,19 @@ void config_init(void) storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); - uint16_t len = 0; - if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { - data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); - } else { - config_wipe(); - } - // Auto-unlock storage if no PIN is set. if (storage_is_unlocked() == secfalse && storage_has_pin() == secfalse) { storage_unlock(PIN_EMPTY); } + + uint16_t len = 0; + // If UUID is not set, then the config is uninitialized. + if (sectrue != storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) || len != sizeof(config_uuid)) { + random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + } + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); } void session_clear(bool lock) From f05664fdf30239f1715bb081e14c2f30d7a10ee7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 23 Feb 2019 03:20:34 +0100 Subject: [PATCH 1133/1154] config: Avoid unlocking storage after wipe. --- firmware/config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/firmware/config.c b/firmware/config.c index b3b6df500a..f631b8e24e 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -908,7 +908,9 @@ void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) void config_wipe(void) { storage_wipe(); - storage_unlock(PIN_EMPTY); + if (storage_is_unlocked() != sectrue) { + storage_unlock(PIN_EMPTY); + } random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); autoLockDelayMsCached = secfalse; From 91d9bd28c2b70ca0beeb3e5e46e562a49c417487 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 23 Feb 2019 19:02:27 +0100 Subject: [PATCH 1134/1154] build: don't try to sign emulator build --- script/cibuild | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/script/cibuild b/script/cibuild index 2c2382a8e7..b02691b702 100755 --- a/script/cibuild +++ b/script/cibuild @@ -22,4 +22,8 @@ fi make -C vendor/nanopb/generator/proto make -C firmware/protob -make -C firmware sign +make -C firmware + +if [ "$EMULATOR" != 1 ]; then + make -C firmware sign +fi From 6cda903a1d08cdbf1b6fe9dfc2be3685525536e3 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 23 Feb 2019 20:47:49 +0100 Subject: [PATCH 1135/1154] setup: change mpu definition for bootloader, fix typo --- memory_app_1.8.0.ld | 2 +- setup.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/memory_app_1.8.0.ld b/memory_app_1.8.0.ld index 77a3ec2a0c..8767a33e29 100644 --- a/memory_app_1.8.0.ld +++ b/memory_app_1.8.0.ld @@ -1,5 +1,5 @@ /* STM32F205RG - 1024K Flash, 128K RAM */ -/* program starts at 0x08010100 */ +/* program starts at 0x08010400 */ MEMORY { rom (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K diff --git a/setup.c b/setup.c index e1fab1020b..1353013007 100644 --- a/setup.c +++ b/setup.c @@ -153,6 +153,7 @@ void setupApp(void) #define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4GB (0x1FUL << MPU_RASR_SIZE_LSB) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html #define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) @@ -177,9 +178,10 @@ void mpu_config_bootloader(void) MPU_CTRL = 0; // Note: later entries overwrite previous ones - // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-write) - MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRW_URW; + + // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) + MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB | MPU_RASR_ATTR_AP_PRW_URW; // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) MPU_RBAR = (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); @@ -218,6 +220,7 @@ void mpu_config_firmware(void) MPU_CTRL = 0; // Note: later entries overwrite previous ones + // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRO_URO; From 7baa8c29fc8c306d577e88a7b0013d3b7d608bca Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Feb 2019 12:23:49 +0100 Subject: [PATCH 1136/1154] bootloader: move timer_init to jump_to_firmware --- bootloader/bootloader.c | 2 -- util.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 2497b13856..6525ca283b 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -33,7 +33,6 @@ #include "signatures.h" #include "layout.h" #include "rng.h" -#include "timer.h" #include "memory.h" void layoutFirmwareFingerprint(const uint8_t *hash) @@ -133,7 +132,6 @@ int main(void) int signed_firmware = signatures_new_ok(hdr, fingerprint); if (SIG_OK != signed_firmware) { show_unofficial_warning(fingerprint); - timer_init(); } if (SIG_OK != check_firmware_hashes(hdr)) { diff --git a/util.h b/util.h index 31003ed69e..c96a79b6e5 100644 --- a/util.h +++ b/util.h @@ -27,6 +27,7 @@ #if !EMULATOR #include #include +#include "timer.h" #endif // Statement expressions make these macros side-effect safe @@ -68,6 +69,7 @@ static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table // Set stack pointer __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); } else { // untrusted firmware + timer_init(); mpu_config_firmware(); // * configure MPU for the firmware __asm__ volatile("msr msp, %0" :: "r" (_stack)); } From 222c9ea46c7574cb52d4713c481438a32b85e692 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Feb 2019 12:23:49 +0100 Subject: [PATCH 1137/1154] bootloader: compatibility with old bootloaders --- bootloader/signatures.c | 6 +++++- firmware/bl_check.c | 4 ++-- firmware/header.S | 2 +- startup.s | 10 ++++++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/bootloader/signatures.c b/bootloader/signatures.c index 37e5f67b8c..ec6ca3af62 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -119,7 +119,11 @@ bool firmware_present_new(void) { const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; - if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; + // we need to ignore hdrlen for now + // because we keep reset_handler ptr there + // for compatibility with older bootloaders + // after this is no longer necessary, let's uncomment the line below: + // if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; if (hdr->codelen > FLASH_APP_LEN) return false; if (hdr->codelen < 4096) return false; diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 50c8ac488a..04cd8644bb 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -26,7 +26,7 @@ #include "gettext.h" #include "util.h" -int known_bootloader(int r, const uint8_t *hash) { +static int known_bootloader(int r, const uint8_t *hash) { if (r != 32) return 0; if (0 == memcmp(hash, "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98", 32)) return 1; // 1.2.0a if (0 == memcmp(hash, "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e", 32)) return 1; // 1.2.0b @@ -44,7 +44,7 @@ int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 - if (0 == memcmp(hash, "\xaf\x19\x47\x7b\xf1\x4c\x33\x81\x34\x78\xd3\x29\x46\x58\x3b\x5d\xcf\xb2\x13\xc5\xba\x92\x81\x1e\x46\x50\x8e\xd0\x14\xb7\xa6\x14", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 + if (0 == memcmp(hash, "\xd2\xe7\x5b\x31\xaa\x66\x88\x74\x90\x3a\x30\x9e\x65\xc9\x4d\x0b\x36\x6b\x1d\xc8\xca\x8d\xda\x37\xba\x6f\x16\x6e\x50\x82\xae\xda", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 return 0; } diff --git a/firmware/header.S b/firmware/header.S index 9333fb238c..46e4aa3751 100644 --- a/firmware/header.S +++ b/firmware/header.S @@ -9,7 +9,7 @@ g_header: .byte 'T','R','Z','F' // magic - .word g_header_end - g_header // hdrlen + .word reset_handler // reset handler, replace later with : .word g_header_end - g_header // hdrlen .word 0 // expiry .word _codelen // codelen .byte VERSION_MAJOR // vmajor diff --git a/startup.s b/startup.s index 59a87e1af0..ce75ba1a7a 100644 --- a/startup.s +++ b/startup.s @@ -19,6 +19,16 @@ memset_reg: .global reset_handler .type reset_handler, STT_FUNC reset_handler: +// we need to perform this in case an old bootloader +// is starting the new firmware, these will be set incorrectly + ldr r0, =0xE000ED08 // r0 = VTOR address + ldr r1, =0x08010400 // r1 = FLASH_APP_START + str r1, [r0] // assign + ldr r0, =_stack // r0 = stack pointer + msr msp, r0 // set stack pointer + dsb + isb + ldr r0, =_ram_start // r0 - point to beginning of SRAM ldr r1, =_ram_end // r1 - point to byte after the end of SRAM ldr r2, =0 // r2 - the byte-sized value to be written From 964a622bb512aa85cfcc3e451fc70729cc15bb4f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 24 Feb 2019 17:35:16 +0100 Subject: [PATCH 1138/1154] bootloader: fix typo --- bootloader/usb.c | 2 +- firmware/bl_check.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootloader/usb.c b/bootloader/usb.c index efedcef72b..84885e8513 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -182,7 +182,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) // check whether the current firmware is signed (old or new method) if (firmware_present_new()) { const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); - old_was_signed = (SIG_OK == signatures_new_ok(hdr, NULL)) && (SIG_OK == check_firmware_hashes(hdr)); + old_was_signed = signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr); } else if (firmware_present_old()) { old_was_signed = signatures_old_ok(); } else { diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 04cd8644bb..45238a5def 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -44,7 +44,7 @@ static int known_bootloader(int r, const uint8_t *hash) { if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 - if (0 == memcmp(hash, "\xd2\xe7\x5b\x31\xaa\x66\x88\x74\x90\x3a\x30\x9e\x65\xc9\x4d\x0b\x36\x6b\x1d\xc8\xca\x8d\xda\x37\xba\x6f\x16\x6e\x50\x82\xae\xda", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 + if (0 == memcmp(hash, "\xf7\xfa\x16\x5b\xe6\xd7\x80\xf3\xe1\xaf\x00\xab\xc0\x7d\xf8\xb3\x07\x6b\xcd\xad\x72\xd7\x0d\xa2\x2a\x63\xd8\x89\x6b\x63\x91\xd8", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 return 0; } From b457797c555d1bc1a0620d8eae5f27354b4dbf20 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 25 Feb 2019 12:44:38 +0100 Subject: [PATCH 1139/1154] changelog: update --- firmware/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firmware/ChangeLog b/firmware/ChangeLog index 8f31e2f6d3..be72340c89 100644 --- a/firmware/ChangeLog +++ b/firmware/ChangeLog @@ -1,5 +1,10 @@ Version 1.8.0 * Stable release, optional update +* Security improvements +* Upgraded to new storage format +* Stellar and NEM fixes +* New coins: ATS, KMD, XPM, XSN, ZCL +* New ETH tokens Version 1.7.3 * Stable release, optional update From b65f61650a8249c4af3c85e8f6b74e699d69bfbd Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 25 Feb 2019 13:54:44 +0100 Subject: [PATCH 1140/1154] config: Set usbTiny whenever there is a possibility that protectPinUiCallback() may be called. --- firmware/config.c | 16 ++++++++++++++-- firmware/config.h | 3 +-- firmware/protect.c | 8 ++------ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index f631b8e24e..73bed8fac9 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -297,6 +297,7 @@ static secbool config_upgrade_v10(void) if (config.has_pin) { storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); } + while (pin_wait != 0) { storage_pin_fails_increase(); pin_wait >>= 1; @@ -354,6 +355,8 @@ static secbool config_upgrade_v10(void) void config_init(void) { + char oldTiny = usbTiny(1); + config_upgrade_v10(); storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); @@ -372,6 +375,8 @@ void config_init(void) storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); } data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + + usbTiny(oldTiny); } void session_clear(bool lock) @@ -719,9 +724,12 @@ bool config_containsMnemonic(const char *mnemonic) /* Check whether pin matches storage. The pin must be * a null-terminated string with at most 9 characters. */ -bool config_containsPin(const char *pin) +bool config_unlock(const char *pin) { - return sectrue == storage_unlock(pin_to_int(pin)); + char oldTiny = usbTiny(1); + secbool ret = storage_unlock(pin_to_int(pin)); + usbTiny(oldTiny); + return sectrue == ret; } bool config_hasPin(void) @@ -736,7 +744,9 @@ bool config_changePin(const char *old_pin, const char *new_pin) return false; } + char oldTiny = usbTiny(1); secbool ret = storage_change_pin(pin_to_int(old_pin), new_pin_int); + usbTiny(oldTiny); #if DEBUG_LINK if (sectrue == ret) { @@ -907,10 +917,12 @@ void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) void config_wipe(void) { + char oldTiny = usbTiny(1); storage_wipe(); if (storage_is_unlocked() != sectrue) { storage_unlock(PIN_EMPTY); } + usbTiny(oldTiny); random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); autoLockDelayMsCached = secfalse; diff --git a/firmware/config.h b/firmware/config.h index 636becec3c..8f8b1bfe32 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -120,9 +120,8 @@ bool config_dumpNode(HDNodeType *node); bool config_getPin(char *dest, uint16_t dest_size); #endif -bool config_containsPin(const char *pin); +bool config_unlock(const char *pin); bool config_hasPin(void); -void config_setPin(const char *pin); bool config_changePin(const char *old_pin, const char *new_pin); bool session_isUnlocked(void); diff --git a/firmware/protect.c b/firmware/protect.c index 5f7135d4e5..548504b8bd 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -204,9 +204,7 @@ bool protectPin(bool use_cached) } } - usbTiny(1); - bool ret = config_containsPin(pin); - usbTiny(0); + bool ret = config_unlock(pin); if (!ret) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); } @@ -229,7 +227,7 @@ bool protectChangePin(bool removal) // If removing, defer the check to config_changePin(). if (!removal) { usbTiny(1); - bool ret = config_containsPin(pin); + bool ret = config_unlock(pin); usbTiny(0); if (ret == false) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); @@ -265,9 +263,7 @@ bool protectChangePin(bool removal) } } - usbTiny(1); bool ret = config_changePin(old_pin, new_pin); - usbTiny(0); memzero(old_pin, sizeof(old_pin)); memzero(new_pin, sizeof(new_pin)); if (ret == false) { From f40219dbb609ed468aa74db25d1295fed826e547 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 28 Feb 2019 16:38:48 +0100 Subject: [PATCH 1141/1154] fsm: correctly set node in EthereumPublicKey response --- firmware/fsm_msg_ethereum.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index bc32f46f98..2a9290772a 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -44,6 +44,7 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) } } + resp->has_node = true; resp->node.depth = node->depth; resp->node.fingerprint = fingerprint; resp->node.child_num = node->child_num; @@ -53,8 +54,8 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) resp->node.has_public_key = true; resp->node.public_key.size = 33; memcpy(resp->node.public_key.bytes, node->public_key, 33); - resp->has_xpub = true; + resp->has_xpub = true; hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); msg_write(MessageType_MessageType_EthereumPublicKey, resp); From cbde3f4fdbf528cb6502dd71f09990b6b0c71083 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 9 Mar 2019 18:24:49 +0100 Subject: [PATCH 1142/1154] firmware: refactor U2F known apps, add WebAuthn entries --- common.c | 1 + firmware/layout2.c | 7 +- firmware/layout2.h | 2 +- firmware/u2f.c | 14 +-- firmware/u2f_knownapps.h | 174 ++++++++++++++++++---------------- gen/bitmaps.c | 22 +---- gen/bitmaps.h | 11 +-- gen/bitmaps/generate.py | 3 +- gen/bitmaps/u2f_bitbucket.png | Bin 292 -> 0 bytes gen/bitmaps/u2f_bitfinex.png | Bin 285 -> 0 bytes gen/bitmaps/u2f_dropbox.png | Bin 263 -> 0 bytes gen/bitmaps/u2f_fastmail.png | Bin 226 -> 0 bytes gen/bitmaps/u2f_gandi.png | Bin 250 -> 0 bytes gen/bitmaps/u2f_github.png | Bin 236 -> 0 bytes gen/bitmaps/u2f_gitlab.png | Bin 229 -> 0 bytes gen/bitmaps/u2f_google.png | Bin 240 -> 0 bytes gen/bitmaps/u2f_slushpool.png | Bin 214 -> 0 bytes gen/bitmaps/u2f_yubico.png | Bin 253 -> 0 bytes gen/bitmaps/webauthn.png | Bin 0 -> 1076 bytes gen/fonts/generate.py | 3 +- shell.nix | 2 +- 21 files changed, 108 insertions(+), 131 deletions(-) delete mode 100644 gen/bitmaps/u2f_bitbucket.png delete mode 100644 gen/bitmaps/u2f_bitfinex.png delete mode 100644 gen/bitmaps/u2f_dropbox.png delete mode 100644 gen/bitmaps/u2f_fastmail.png delete mode 100644 gen/bitmaps/u2f_gandi.png delete mode 100644 gen/bitmaps/u2f_github.png delete mode 100644 gen/bitmaps/u2f_gitlab.png delete mode 100644 gen/bitmaps/u2f_google.png delete mode 100644 gen/bitmaps/u2f_slushpool.png delete mode 100644 gen/bitmaps/u2f_yubico.png create mode 100644 gen/bitmaps/webauthn.png diff --git a/common.c b/common.c index 2c2e31c09c..ae7230613e 100644 --- a/common.c +++ b/common.c @@ -23,6 +23,7 @@ #include "layout.h" #include "oled.h" #include "util.h" +#include "bitmaps.h" #include "firmware/usb.h" uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; diff --git a/firmware/layout2.c b/firmware/layout2.c index 0ca71faf97..b61a467902 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -756,11 +756,8 @@ void layoutDecryptIdentity(const IdentityType *identity) NULL); } -void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon) { - if (!appicon) { - appicon = &bmp_icon_question; - } - layoutDialog(appicon, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); +void layoutU2FDialog(const char *verb, const char *appname) { + layoutDialog(&bmp_webauthn, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); } void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address) { diff --git a/firmware/layout2.h b/firmware/layout2.h index 954832bdf9..f3935f4094 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -59,7 +59,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); -void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon); +void layoutU2FDialog(const char *verb, const char *appname); void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); diff --git a/firmware/u2f.c b/firmware/u2f.c index 6cb05914db..1b856aa707 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -441,13 +441,12 @@ void u2f_version(const APDU *a) send_u2f_msg(version_response, sizeof(version_response)); } -static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) { +static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname) { static char buf[8+2+8+1]; for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { *appname = u2f_well_known[i].appname; - *appicon = u2f_well_known[i].appicon; return; } } @@ -456,7 +455,6 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a buf[8] = buf[9] = '.'; data2hex(appid + (U2F_APPID_SIZE - 4), 4, &buf[10]); *appname = buf; - *appicon = NULL; } static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) @@ -575,9 +573,8 @@ void u2f_register(const APDU *a) layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL, _("Another U2F device"), _("was used to register"), _("in this application."), NULL, NULL, NULL); } else { const char *appname; - const BITMAP *appicon; - getReadableAppId(req->appId, &appname, &appicon); - layoutU2FDialog(_("Register"), appname, appicon); + getReadableAppId(req->appId, &appname); + layoutU2FDialog(_("Register"), appname); } last_req_state = REG; } @@ -709,9 +706,8 @@ void u2f_authenticate(const APDU *a) // error: testof-user-presence is required buttonUpdate(); // Clear button state const char *appname; - const BITMAP *appicon; - getReadableAppId(req->appId, &appname, &appicon); - layoutU2FDialog(_("Authenticate"), appname, appicon); + getReadableAppId(req->appId, &appname); + layoutU2FDialog(_("Authenticate"), appname); last_req_state = AUTH; } diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index a6a25ea858..2f945e9373 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -22,115 +22,127 @@ #include #include "u2f/u2f.h" -#include "bitmaps.h" typedef struct { const uint8_t appid[U2F_APPID_SIZE]; const char *appname; - const BITMAP *appicon; } U2FWellKnown; +// contents generated via script in +// trezor-common/defs/webauthn/gen.py +// do not edit manually + static const U2FWellKnown u2f_well_known[] = { { - // https://www.gstatic.com/securitykey/origins.json - { 0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, - 0xe1, 0x51, 0xed, 0x8d, 0x4d, 0x3c, 0x76, 0x7a, - 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, 0x79, 0x4e, - 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd }, - "Google", - &bmp_u2f_google + // U2F: https://bitbucket.org + { 0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, 0x11, 0x35, 0xe4, 0x1f, 0xde, 0xdd, 0x4a, 0x84, 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, 0x32, 0xa9, 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e }, + "Bitbucket" }, { - // https://github.com/u2f/trusted_facets - { 0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, - 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, - 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, - 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 }, - "GitHub", - &bmp_u2f_github + // U2F: https://www.bitfinex.com + { 0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, 0xfe, 0xbb, 0x30, 0xe7, 0x32, 0x69, 0xec, 0xa5, 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, 0x0b, 0xf7, 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63 }, + "Bitfinex" }, { - // https://www.dropbox.com/u2f-app-id.json - { 0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, - 0x2e, 0x7a, 0x50, 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, - 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, 0xc0, 0xcd, - 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81 }, - "Dropbox", - &bmp_u2f_dropbox + // U2F: https://vault.bitwarden.com/app-id.json + { 0xa3, 0x4d, 0x30, 0x9f, 0xfa, 0x28, 0xc1, 0x24, 0x14, 0xb8, 0xba, 0x6c, 0x07, 0xee, 0x1e, 0xfa, 0xe1, 0xa8, 0x5e, 0x8a, 0x04, 0x61, 0x48, 0x59, 0xa6, 0x7c, 0x04, 0x93, 0xb6, 0x95, 0x61, 0x90 }, + "Bitwarden" }, { - // https://slushpool.com/static/security/u2f.json - { 0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, - 0x66, 0x84, 0x93, 0xcb, 0x36, 0xcd, 0xcc, 0x4f, - 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, 0x8b, 0x73, - 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97 }, - "Slush Pool", - &bmp_u2f_slushpool + // U2F: https://www.dashlane.com + { 0x68, 0x20, 0x19, 0x15, 0xd7, 0x4c, 0xb4, 0x2a, 0xf5, 0xb3, 0xcc, 0x5c, 0x95, 0xb9, 0x55, 0x3e, 0x3e, 0x3a, 0x83, 0xb4, 0xd2, 0xa9, 0x3b, 0x45, 0xfb, 0xad, 0xaa, 0x84, 0x69, 0xff, 0x8e, 0x6e }, + "Dashlane" }, { - // https://bitbucket.org - { 0x12, 0x74, 0x3b, 0x92, 0x12, 0x97, 0xb7, 0x7f, - 0x11, 0x35, 0xe4, 0x1f, 0xde, 0xdd, 0x4a, 0x84, - 0x6a, 0xfe, 0x82, 0xe1, 0xf3, 0x69, 0x32, 0xa9, - 0x91, 0x2f, 0x3b, 0x0d, 0x8d, 0xfb, 0x7d, 0x0e }, - "Bitbucket", - &bmp_u2f_bitbucket + // U2F: https://www.dropbox.com/u2f-app-id.json + { 0xc5, 0x0f, 0x8a, 0x7b, 0x70, 0x8e, 0x92, 0xf8, 0x2e, 0x7a, 0x50, 0xe2, 0xbd, 0xc5, 0x5d, 0x8f, 0xd9, 0x1a, 0x22, 0xfe, 0x6b, 0x29, 0xc0, 0xcd, 0xf7, 0x80, 0x55, 0x30, 0x84, 0x2a, 0xf5, 0x81 }, + "Dropbox" }, { - // https://gitlab.com - { 0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, - 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, - 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, - 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, - "GitLab", - &bmp_u2f_gitlab + // WebAuthn: www.dropbox.com + { 0x82, 0xf4, 0xa8, 0xc9, 0x5f, 0xec, 0x94, 0xb2, 0x6b, 0xaf, 0x9e, 0x37, 0x25, 0x0e, 0x95, 0x63, 0xd9, 0xa3, 0x66, 0xc7, 0xbe, 0x26, 0x1c, 0xa4, 0xdd, 0x01, 0x01, 0xf4, 0xd5, 0xef, 0xcb, 0x83 }, + "Dropbox" }, { - // https://www.fastmail.com - { 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, - 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, - 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, - 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, - "FastMail", - &bmp_u2f_fastmail + // U2F: https://api-9dcf9b83.duosecurity.com + { 0xf3, 0xe2, 0x04, 0x2f, 0x94, 0x60, 0x7d, 0xa0, 0xa9, 0xc1, 0xf3, 0xb9, 0x5e, 0x0d, 0x2f, 0x2b, 0xb2, 0xe0, 0x69, 0xc5, 0xbb, 0x4f, 0xa7, 0x64, 0xaf, 0xfa, 0x64, 0x7d, 0x84, 0x7b, 0x7e, 0xd6 }, + "Duo" }, { - // https://account.gandi.net/api/u2f/trusted_facets.json - { 0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, - 0x12, 0x89, 0x50, 0x11, 0x39, 0x89, 0xfc, 0x45, - 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, 0x75, 0x60, - 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96 }, - "Gandi", - &bmp_u2f_gandi, + // U2F: https://www.fastmail.com + { 0x69, 0x66, 0xab, 0xe3, 0x67, 0x4e, 0xa2, 0xf5, 0x30, 0x79, 0xeb, 0x71, 0x01, 0x97, 0x84, 0x8c, 0x9b, 0xe6, 0xf3, 0x63, 0x99, 0x2f, 0xd0, 0x29, 0xe9, 0x89, 0x84, 0x47, 0xcb, 0x9f, 0x00, 0x84 }, + "FastMail" }, { - // https://www.bitfinex.com - { 0x30, 0x2f, 0xd5, 0xb4, 0x49, 0x2a, 0x07, 0xb9, - 0xfe, 0xbb, 0x30, 0xe7, 0x32, 0x69, 0xec, 0xa5, - 0x01, 0x20, 0x5c, 0xcf, 0xe0, 0xc2, 0x0b, 0xf7, - 0xb4, 0x72, 0xfa, 0x2d, 0x31, 0xe2, 0x1e, 0x63 }, - "Bitfinex", - &bmp_u2f_bitfinex + // U2F: https://id.fedoraproject.org/u2f-origins.json + { 0x9d, 0x61, 0x44, 0x2f, 0x5c, 0xe1, 0x33, 0xbd, 0x46, 0x54, 0x4f, 0xc4, 0x2f, 0x0a, 0x6d, 0x54, 0xc0, 0xde, 0xb8, 0x88, 0x40, 0xca, 0xc2, 0xb6, 0xae, 0xfa, 0x65, 0x14, 0xf8, 0x93, 0x49, 0xe9 }, + "Fedora" }, { - // https://demo.yubico.com - { 0x55, 0x67, 0x3b, 0x51, 0x38, 0xcc, 0x90, 0xd3, - 0xb7, 0xf3, 0x2b, 0xfd, 0xad, 0x6a, 0x38, 0xa8, - 0xed, 0xd7, 0xb3, 0x55, 0xb7, 0x7a, 0xb9, 0x79, - 0x21, 0x96, 0xf1, 0x06, 0xd1, 0x6c, 0xa3, 0x12 }, - "Yubico U2F Demo", - &bmp_u2f_yubico + // U2F: https://account.gandi.net/api/u2f/trusted_facets.json + { 0xa4, 0xe2, 0x2d, 0xca, 0xfe, 0xa7, 0xe9, 0x0e, 0x12, 0x89, 0x50, 0x11, 0x39, 0x89, 0xfc, 0x45, 0x97, 0x8d, 0xc9, 0xfb, 0x87, 0x76, 0x75, 0x60, 0x51, 0x6c, 0x1c, 0x69, 0xdf, 0xdf, 0xd1, 0x96 }, + "Gandi" }, { - // https://u2f.bin.coffee - { - 0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, - 0xb4, 0xc2, 0x89, 0xdc, 0x16, 0x74, 0x6b, 0xcc, - 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, 0xe1, 0x32, - 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68 }, - "u2f.bin.coffee", - NULL - } + // U2F: https://github.com/u2f/trusted_facets + { 0x70, 0x61, 0x7d, 0xfe, 0xd0, 0x65, 0x86, 0x3a, 0xf4, 0x7c, 0x15, 0x55, 0x6c, 0x91, 0x79, 0x88, 0x80, 0x82, 0x8c, 0xc4, 0x07, 0xfd, 0xf7, 0x0a, 0xe8, 0x50, 0x11, 0x56, 0x94, 0x65, 0xa0, 0x75 }, + "GitHub" + }, + { + // U2F: https://gitlab.com + { 0xe7, 0xbe, 0x96, 0xa5, 0x1b, 0xd0, 0x19, 0x2a, 0x72, 0x84, 0x0d, 0x2e, 0x59, 0x09, 0xf7, 0x2b, 0xa8, 0x2a, 0x2f, 0xe9, 0x3f, 0xaa, 0x62, 0x4f, 0x03, 0x39, 0x6b, 0x30, 0xe4, 0x94, 0xc8, 0x04 }, + "GitLab" + }, + { + // U2F: https://www.gstatic.com/securitykey/origins.json + { 0xa5, 0x46, 0x72, 0xb2, 0x22, 0xc4, 0xcf, 0x95, 0xe1, 0x51, 0xed, 0x8d, 0x4d, 0x3c, 0x76, 0x7a, 0x6c, 0xc3, 0x49, 0x43, 0x59, 0x43, 0x79, 0x4e, 0x88, 0x4f, 0x3d, 0x02, 0x3a, 0x82, 0x29, 0xfd }, + "Google" + }, + { + // U2F: https://keepersecurity.com + { 0x53, 0xa1, 0x5b, 0xa4, 0x2a, 0x7c, 0x03, 0x25, 0xb8, 0xdb, 0xee, 0x28, 0x96, 0x34, 0xa4, 0x8f, 0x58, 0xae, 0xa3, 0x24, 0x66, 0x45, 0xd5, 0xff, 0x41, 0x8f, 0x9b, 0xb8, 0x81, 0x98, 0x85, 0xa9 }, + "Keeper" + }, + { + // U2F: https://lastpass.com + { 0xd7, 0x55, 0xc5, 0x27, 0xa8, 0x6b, 0xf7, 0x84, 0x45, 0xc2, 0x82, 0xe7, 0x13, 0xdc, 0xb8, 0x6d, 0x46, 0xff, 0x8b, 0x3c, 0xaf, 0xcf, 0xb7, 0x3b, 0x2e, 0x8c, 0xbe, 0x6c, 0x08, 0x84, 0xcb, 0x24 }, + "LastPass" + }, + { + // U2F: https://slushpool.com/static/security/u2f.json + { 0x08, 0xb2, 0xa3, 0xd4, 0x19, 0x39, 0xaa, 0x31, 0x66, 0x84, 0x93, 0xcb, 0x36, 0xcd, 0xcc, 0x4f, 0x16, 0xc4, 0xd9, 0xb4, 0xc8, 0x23, 0x8b, 0x73, 0xc2, 0xf6, 0x72, 0xc0, 0x33, 0x00, 0x71, 0x97 }, + "Slush Pool" + }, + { + // U2F: https://dashboard.stripe.com + { 0x2a, 0xc6, 0xad, 0x09, 0xa6, 0xd0, 0x77, 0x2c, 0x44, 0xda, 0x73, 0xa6, 0x07, 0x2f, 0x9d, 0x24, 0x0f, 0xc6, 0x85, 0x4a, 0x70, 0xd7, 0x9c, 0x10, 0x24, 0xff, 0x7c, 0x75, 0x59, 0x59, 0x32, 0x92 }, + "Stripe" + }, + { + // U2F: https://u2f.bin.coffee + { 0x1b, 0x3c, 0x16, 0xdd, 0x2f, 0x7c, 0x46, 0xe2, 0xb4, 0xc2, 0x89, 0xdc, 0x16, 0x74, 0x6b, 0xcc, 0x60, 0xdf, 0xcf, 0x0f, 0xb8, 0x18, 0xe1, 0x32, 0x15, 0x52, 0x6e, 0x14, 0x08, 0xe7, 0xf4, 0x68 }, + "u2f.bin.coffee" + }, + { + // WebAuthn: webauthn.bin.coffee + { 0xa6, 0x42, 0xd2, 0x1b, 0x7c, 0x6d, 0x55, 0xe1, 0xce, 0x23, 0xc5, 0x39, 0x98, 0x28, 0xd2, 0xc7, 0x49, 0xbf, 0x6a, 0x6e, 0xf2, 0xfe, 0x03, 0xcc, 0x9e, 0x10, 0xcd, 0xf4, 0xed, 0x53, 0x08, 0x8b }, + "webauthn.bin.coffee" + }, + { + // WebAuthn: webauthn.io + { 0x74, 0xa6, 0xea, 0x92, 0x13, 0xc9, 0x9c, 0x2f, 0x74, 0xb2, 0x24, 0x92, 0xb3, 0x20, 0xcf, 0x40, 0x26, 0x2a, 0x94, 0xc1, 0xa9, 0x50, 0xa0, 0x39, 0x7f, 0x29, 0x25, 0x0b, 0x60, 0x84, 0x1e, 0xf0 }, + "WebAuthn.io" + }, + { + // WebAuthn: webauthn.me + { 0xf9, 0x5b, 0xc7, 0x38, 0x28, 0xee, 0x21, 0x0f, 0x9f, 0xd3, 0xbb, 0xe7, 0x2d, 0x97, 0x90, 0x80, 0x13, 0xb0, 0xa3, 0x75, 0x9e, 0x9a, 0xea, 0x3d, 0x0a, 0xe3, 0x18, 0x76, 0x6c, 0xd2, 0xe1, 0xad }, + "WebAuthn.me" + }, + { + // WebAuthn: demo.yubico.com + { 0xc4, 0x6c, 0xef, 0x82, 0xad, 0x1b, 0x54, 0x64, 0x77, 0x59, 0x1d, 0x00, 0x8b, 0x08, 0x75, 0x9e, 0xc3, 0xe6, 0xd2, 0xec, 0xb4, 0xf3, 0x94, 0x74, 0xbf, 0xea, 0x69, 0x69, 0x92, 0x5d, 0x03, 0xb7 }, + "demo.yubico.com" + }, }; #endif // U2F_KNOWNAPPS_INCLUDED diff --git a/gen/bitmaps.c b/gen/bitmaps.c index 49a8691647..5d60730d1a 100644 --- a/gen/bitmaps.c +++ b/gen/bitmaps.c @@ -23,16 +23,7 @@ const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x20, 0x3c, 0x04, 0x00, 0x00, 0x20, 0xc3, 0x04, 0x00, 0x00, 0x21, 0x00, 0x84, 0x00, 0x00, 0x41, 0x00, 0x82, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x42, 0x00, 0x0f, 0xc3, 0xff, 0xc3, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x7f, 0xff, 0xfe, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x30, 0x00, 0x0c, 0x10, 0x08, 0x0c, 0x00, 0x30, 0x10, 0x08, 0x03, 0x00, 0xc0, 0x10, 0x0c, 0x00, 0xc3, 0x00, 0x30, 0x03, 0x00, 0x3c, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x00, 0x0c, 0x00, 0x30, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xf0, 0x0f, 0xfc, 0x00, 0x00, 0x3f, 0xe0, 0x07, 0xfc, 0x00, 0x00, 0x3f, 0xc0, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x00, 0x7f, 0x80, 0x01, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x1f, 0xfe, 0x00, 0x00, 0x7f, 0xf8, 0x1f, 0xff, 0x80, 0x01, 0xff, 0xf8, 0x1f, 0xff, 0xe0, 0x07, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0x1f, 0xff, 0xf8, 0x07, 0xff, 0xfe, 0x7f, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x07, 0xe0, 0x10, 0x00, 0x00, 0x10, 0x08, 0x10, 0x08, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x20, 0x20, 0x04, 0x04, 0x00, 0x00, 0x20, 0x40, 0x02, 0x04, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x1f, 0xc0, 0xff, 0xff, 0x03, 0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3f, 0xff, 0xff, 0xfc, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x18, 0x00, 0x00, 0x18, 0x08, 0x10, 0x06, 0x00, 0x00, 0x60, 0x08, 0x10, 0x01, 0x80, 0x01, 0x80, 0x08, 0x10, 0x00, 0x60, 0x06, 0x00, 0x08, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x06, 0x00, 0x06, 0x60, 0x00, 0x60, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_bitbucket_data[] = { 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0x00, 0x01, 0xf8, 0x3c, 0x00, 0x00, 0x78, 0x3f, 0x00, 0x01, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f, 0xe3, 0x8f, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x1f, 0xe7, 0xcf, 0xf0, 0x0f, 0xe3, 0x8f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x00, 0x04, 0x3f, 0xf8, 0x40, 0x07, 0x00, 0x01, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x0f, 0xe0, 0x00, }; -const uint8_t bmp_u2f_bitfinex_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xa0, 0x00, 0x0f, 0xff, 0x20, 0x00, 0x3f, 0xff, 0x60, 0x00, 0x7f, 0xfe, 0xe0, 0x00, 0xff, 0xfc, 0xe0, 0x01, 0xff, 0xf1, 0xe0, 0x01, 0xff, 0xe3, 0xe0, 0x03, 0xff, 0xc7, 0xe0, 0x03, 0xff, 0x8f, 0xc0, 0x07, 0xfe, 0x0f, 0xc0, 0x07, 0xfc, 0x1f, 0xc0, 0x07, 0xf0, 0x7f, 0x80, 0x07, 0x80, 0xff, 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_fastmail_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x4f, 0xff, 0xff, 0xf2, 0x67, 0xff, 0xff, 0xe6, 0x73, 0xff, 0xff, 0xce, 0x79, 0xff, 0xff, 0x9e, 0x7c, 0xff, 0xff, 0x3e, 0x7e, 0x7f, 0xfe, 0x7e, 0x7f, 0x3f, 0xfc, 0xfe, 0x7f, 0x9f, 0xf9, 0xfe, 0x7f, 0xcf, 0xf3, 0xfe, 0x7f, 0xe7, 0xe7, 0xfe, 0x7f, 0xf3, 0xcf, 0xfe, 0x7f, 0xf8, 0x1f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_gandi_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x01, 0x8f, 0xe1, 0x00, 0x03, 0xc7, 0xc3, 0x80, 0x03, 0xe0, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x30, 0x00, 0x00, 0xf0, 0xfc, 0x00, 0x00, 0xf1, 0xfe, 0x00, 0x00, 0xf3, 0xff, 0x00, 0x00, 0xf1, 0xcf, 0x00, 0x00, 0xf0, 0x8f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_gitlab_data[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x60, 0x07, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0x80, 0x01, 0xf8, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xc0, 0x03, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, }; -const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -const uint8_t bmp_u2f_yubico_data[] = { 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xfc, 0x3f, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x0f, 0x80, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0x78, 0x3e, 0x00, 0x00, 0x3c, 0x3c, 0x7c, 0x1f, 0x3c, 0x78, 0x7c, 0x1f, 0x1e, 0x78, 0x7c, 0x3e, 0x0e, 0xf0, 0x3e, 0x3e, 0x0f, 0xf0, 0x3e, 0x3c, 0x0f, 0xf0, 0x1f, 0x7c, 0x0f, 0xe0, 0x1f, 0x7c, 0x07, 0xe0, 0x1f, 0x78, 0x07, 0xe0, 0x0f, 0xf8, 0x07, 0xe0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x0f, 0x78, 0x03, 0xe0, 0x0e, 0x78, 0x07, 0xc0, 0x1e, 0x3c, 0x07, 0xc0, 0x3e, 0x3c, 0x0f, 0xc0, 0x3c, 0x1e, 0x0f, 0x80, 0x78, 0x0f, 0x8f, 0x81, 0xf0, 0x07, 0xc0, 0x03, 0xe0, 0x03, 0xfc, 0x3f, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00, }; +const uint8_t bmp_webauthn_data[] = { 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x03, 0xfe, 0x1c, 0x00, 0x03, 0xfc, 0x0c, 0x00, 0x07, 0xf8, 0x06, 0x00, 0x07, 0xf8, 0x06, 0x00, 0x0f, 0xf8, 0x06, 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x0f, 0xfc, 0x0f, 0x00, 0x0f, 0xfe, 0x1f, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xdf, 0x80, 0x03, 0xff, 0x80, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, }; const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data}; const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data}; @@ -57,13 +48,4 @@ const BITMAP bmp_logo48 = {40, 48, bmp_logo48_data}; const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data}; const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data}; const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data}; -const BITMAP bmp_u2f_bitbucket = {32, 32, bmp_u2f_bitbucket_data}; -const BITMAP bmp_u2f_bitfinex = {32, 32, bmp_u2f_bitfinex_data}; -const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data}; -const BITMAP bmp_u2f_fastmail = {32, 32, bmp_u2f_fastmail_data}; -const BITMAP bmp_u2f_gandi = {32, 32, bmp_u2f_gandi_data}; -const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data}; -const BITMAP bmp_u2f_gitlab = {32, 32, bmp_u2f_gitlab_data}; -const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data}; -const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data}; -const BITMAP bmp_u2f_yubico = {32, 32, bmp_u2f_yubico_data}; +const BITMAP bmp_webauthn = {32, 32, bmp_webauthn_data}; diff --git a/gen/bitmaps.h b/gen/bitmaps.h index 29f7b5b064..c06351db07 100644 --- a/gen/bitmaps.h +++ b/gen/bitmaps.h @@ -31,15 +31,6 @@ extern const BITMAP bmp_logo48; extern const BITMAP bmp_logo48_empty; extern const BITMAP bmp_logo64; extern const BITMAP bmp_logo64_empty; -extern const BITMAP bmp_u2f_bitbucket; -extern const BITMAP bmp_u2f_bitfinex; -extern const BITMAP bmp_u2f_dropbox; -extern const BITMAP bmp_u2f_fastmail; -extern const BITMAP bmp_u2f_gandi; -extern const BITMAP bmp_u2f_github; -extern const BITMAP bmp_u2f_gitlab; -extern const BITMAP bmp_u2f_google; -extern const BITMAP bmp_u2f_slushpool; -extern const BITMAP bmp_u2f_yubico; +extern const BITMAP bmp_webauthn; #endif diff --git a/gen/bitmaps/generate.py b/gen/bitmaps/generate.py index 21d72a6def..d0005427ce 100755 --- a/gen/bitmaps/generate.py +++ b/gen/bitmaps/generate.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 import glob import os from PIL import Image diff --git a/gen/bitmaps/u2f_bitbucket.png b/gen/bitmaps/u2f_bitbucket.png deleted file mode 100644 index 895f1399056fd7bb7fb60b6822395639e1c7bb97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={W*pj^6T^Rm@;DWu&Cj&(|3p^r= z85p>QL70(Y)*K0-AbW|YuPgflHYs5t%iyPC-9Vv@o-U3d9>?E?dGZ}l;1D_Vf4`4^ zZq(^@$ChZOCnO}eWGpk>{FZ^C&)FzLde;`ND7$zs@SJOL;vKO}gS!2b5|gef&9}CSSluku iwlOE5y8DrnCBw)0nZ}crbj1K2&*16m=d#Wzp$Pyje{vuI diff --git a/gen/bitmaps/u2f_bitfinex.png b/gen/bitmaps/u2f_bitfinex.png deleted file mode 100644 index 48a1048456d5dea18014964b630db2f0e6a4cd9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7a$D;Kb?2i11Zh|kH}&M z25w;xW@MN(M*=9wUgGKN%Kng>kz0=MA8QXinf?Q%OpAXxT-~~C=FWKytT(DySG{7JA3E=y!{P#k3LfJJ^$GrUD+OH-`Z9IgQr=m#>eEy;wxGS?8M?AF8q-~@{TL31 z<;XVZDZAZkk^8VIHXyQemcv)I5@843pD*+}ejN^L5fqY4=JGw*!}F@`g2cZ5lga^t Z@{3KwY*#I_ivhZt!PC{xWt~$(6977sWiS8$ diff --git a/gen/bitmaps/u2f_dropbox.png b/gen/bitmaps/u2f_dropbox.png deleted file mode 100644 index 9d78cadb004addcb8344a54cd62690849256c0cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263 zcmV+i0r>ujP)*Bi47H{Zla*jJXXUhY zYcWW{RwfmHc!A-Oego-^_%8hk?*_|yOZ N002ovPDHLkV1l8qa>4)r diff --git a/gen/bitmaps/u2f_fastmail.png b/gen/bitmaps/u2f_fastmail.png deleted file mode 100644 index 20d05d163046417c8516776966dd1c7fd378501d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJm7Xq+ArXh)PInY)P~dPq`0-!( zHqo;g84g^!1y{FJuAlUumvMpP11*6)K?*SoF1cp!s}>aeZSG)h^Kd(Z?cR14!;Z*f z{slovE%s&)JvsT#`5ol!l&rC8vsMlJkjnRFLPhg_wu|DNoH0{c#5gr$WR6O4^2S_c z72?#5iFMQFc0Nobmr@l`|iP1`cJp8K)x*E!)pu0PHPKHFHZi9cH($>qWw ZGvi;Fn|RBFsX#|Fc)I$ztaD0e0swITP%8ic diff --git a/gen/bitmaps/u2f_gandi.png b/gen/bitmaps/u2f_gandi.png deleted file mode 100644 index 12abe0ff114a8075d60d926035e4f71b01137394..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 250 zcmVl}sKSjKh{yvs6Z-vK^GUCCruz_mSPGJnA68?>)Wgxs5+|TS>}@oPLy-~rXzC^* z(*d4Q5u8QKrfCx0AaDk8*{}1CAO=iPdJwO3(Q=LpD^#|ix=P)hV{vK>!Cy;AzF6RiKIsgCw07*qoM6N<$g8VOK A&j0`b diff --git a/gen/bitmaps/u2f_github.png b/gen/bitmaps/u2f_github.png deleted file mode 100644 index 9f9be253e30c34e220ea3cac2145152b0189a3f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmVo5iB zVHX|v@n&##lix2uQx+Oi6Fuc1qx{`OzJt8-je~Zd6Z)`{3Iz_vCY>b16WJl0gM-LS zU`2leD-9CL996ouil7PSdzpLq*buDeM=4xCVsx m4V^P)lnh~P}IH05!RFv&zDRA?A|5Q)ueRRzisWGR74`S(Y# z!g@vUB-acQ%h~TC7$%^}<-uU}SFXSjd7<10Ryns6^mhSEh5lR30cNg6(EbUtNwmVz zFJuP4D3CF9?uvwUy&mh|2>%E@0;RuOGDMYdLURs0< flZlRTA&9gS9LG;4emS$N00000NkvXXu0mjfu5n@$ diff --git a/gen/bitmaps/u2f_google.png b/gen/bitmaps/u2f_google.png deleted file mode 100644 index 864f4e18667bf0153e49dc59bf1a8a74141cc1dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmV+jBA_UP z8z^byR*3WzXoUmk=$ylI)vebB6!&?fF?3)o-6!@+L3{e`YG+&_w%ixRA9df%M#;b- zZn-@y?2s|1P>Rbt9UMtAY=VT>is-kjq45^o5a0000RmFP;X;f6Ka+7>t=K<}%hC+Am>L`_^2;*j|5iR4LG* N44$rjF6*2UngASlQk?(* diff --git a/gen/bitmaps/u2f_yubico.png b/gen/bitmaps/u2f_yubico.png deleted file mode 100644 index c4bc1f0a280ddee04f59b57898c707ecede0425d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253 zcmVCz?)ilsvs_|?z(PRu*NGgGS^ z#zRDh20DqTSAVT=q+?d~9>yw+(x@gU_FBuG=SyQX?J+iHYJH4NckruYrU|iDU=000000NkvXXu0mjf D(wu7= diff --git a/gen/bitmaps/webauthn.png b/gen/bitmaps/webauthn.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1b595abfb99b2ff016691b37755f579724cfdf GIT binary patch literal 1076 zcmV-41k3x0P) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3vbmZTsIhTpS_SprE2f#q;LXLc~lpP-i2Qx~;s zT26^#BtQ8QEa-oJ5BOyVCKthr#*jjAcKGBIWxI&(e)O$h$I$uZd^>PEBfNY-*0c4z z4yxat@-}|64|{JDy?B7~@B;5{=&NJR+c-J;N73-RkNa}A-xw{9(bv^wA1n-EUDWCV zZqt}yu_*EKTCk?}6T8->C2P@TSJAuXsw>tiCM0Ax&|?G4IIv^0zG5|vo;s=ZM3s0M zi>#EWvSVaF8xB%V+&D6ErOwPAn076=_)UwyiqSkbG*d#G4DFS}24@CW+8EVYj1X=0 zxW&qJ5ls#_!^rb&W(EYu#!Z$0-`ak_7qDyuWeIb%1!h;)DT?4dw|GeaHaoF?%`en8 zsnL=p-h7LRK{f;~APWX`N~DOMDH@<`%85M{BY+~*OeA^cU~Ho0k@>cF6c<|(TF0$a zjE`_&H8zQ}!SY@#f7D0Ip)4$3M1rV9Ns=LO@IgWd8fML9W%Vi=R5fbS969jl5Ias6MrCP{WNHEu^NM?$m5lbxyQQ zfpedc$;^n6M6WtGxBk26V?FF?qcfz_5TdQ!!)Uj2cJ?}A7%oc1~FFxu^AHyz3w5@htJNL%6 z*w&gynO;}(xZEwn59aWpmd(#y1RN`0Jg<^gL0|8-g{@}rukg>K1>3CWy55;=3gIsC zIGATWJO=F`vKztIZs3W*Qy8ylgoAZoRJfvoYgw{;c*_<}Xk5)qo9IOe-0qGbJZigA zBG0+}!Vtb+@UQv7`6hAA4O|PQJDm$Y^Z(q#2W9$l`Ec3q8MQB)*QHpz3kCd4sITwY zrzqev|5uB)T;729@`1gYKGyO+M&H`jZaD}4@d-LC+5(G*xSb76wh(Nyr;MLa|sa z=UjOJJi|ai3o;<0n=+u#uUVI{-I*4*)jhGb=q>%`U`spzLItuV?re<$o?S_PgzQX| zG=)#hJp;lXs5=<`n<9?hb&EW?>lL^MLXOs$5Isp5V*+aL_fJ?6h==7UF1pO2U uq8|dI@9o$%_3!G>=Xwq5%y$*cFR%fnpI05&HMG9~0000 {}; let - myPython = python3.withPackages(p: [p.trezor p.Mako p.munch]); + myPython = python3.withPackages(p: [p.trezor p.Mako p.munch p.pillow]); in stdenv.mkDerivation { name = "trezor-mcu-dev"; From a4668bedb4e6a649fba78588468748b2a11f06dc Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 12 Mar 2019 15:00:49 +0100 Subject: [PATCH 1143/1154] vendor: update trezor-common --- firmware/protob/Makefile | 2 +- vendor/trezor-common | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/protob/Makefile b/firmware/protob/Makefile index 1838454bc4..e456572d5f 100644 --- a/firmware/protob/Makefile +++ b/firmware/protob/Makefile @@ -26,7 +26,7 @@ messages_%_pb2.py: messages-%.proto $(Q)protoc -I/usr/include -I. $< --python_out=. messages_map.h messages_map_limits.h: messages_map.py messages_pb2.py - $(Q)$(PYTHON) $< Cardano Tezos Ripple Monero DebugMonero Ontology Tron Eos + $(Q)$(PYTHON) $< Cardano Tezos Ripple Monero DebugMonero Ontology Tron Eos Binance clean: rm -f *.pb *.o *.d *.pb.c *.pb.h *_pb2.py messages_map.h messages_map_limits.h diff --git a/vendor/trezor-common b/vendor/trezor-common index 0735c7d6f5..c5e54d7535 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 0735c7d6f524b4c5108d201c789612aad7ce7920 +Subproject commit c5e54d7535c8772b9a75ff90c506a28526f94267 From 57423c9f542a5fee83a044d540b0d0d6f803f29f Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 12 Mar 2019 15:10:45 +0100 Subject: [PATCH 1144/1154] firmware: set bitcoin's has_node The field has been changed to optional in https://github.com/trezor/trezor-common/commit/84f5a0e39376409863c58a9ede1b61403306894b . --- firmware/fsm_msg_coin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 3357ade4ba..7e07cadcce 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -48,6 +48,7 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) } } + resp->has_node = true; resp->node.depth = node->depth; resp->node.fingerprint = fingerprint; resp->node.child_num = node->child_num; @@ -61,8 +62,8 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) /* ed25519 public key */ resp->node.public_key.bytes[0] = 0; } - resp->has_xpub = true; + resp->has_xpub = true; if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) { hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); } else From 2646c0901c6fc0bb0b03320153997deaab4ce4f6 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Tue, 12 Mar 2019 14:52:55 +0100 Subject: [PATCH 1145/1154] firmware: return mnemonic as bytes in debug link --- firmware/config.c | 17 +++++++++++++++++ firmware/config.h | 1 + firmware/fsm_msg_debug.h | 3 ++- firmware/protob/messages-debug.options | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 73bed8fac9..22293cdb98 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -172,6 +172,18 @@ static secbool config_get_bool(uint16_t key, bool *value) } } +static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size, uint16_t *real_size) +{ + if (dest_size == 0) { + return secfalse; + } + + if (sectrue != storage_get(key, dest, dest_size, real_size)) { + return secfalse; + } + return sectrue; +} + static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { if (dest_size == 0) { @@ -688,6 +700,11 @@ bool config_setMnemonic(const char *mnemonic) return true; } +bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size) +{ + return sectrue == config_get_bytes(KEY_MNEMONIC, dest, dest_size, real_size); +} + bool config_getMnemonic(char *dest, uint16_t dest_size) { return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); diff --git a/firmware/config.h b/firmware/config.h index 8f8b1bfe32..2f2c26da24 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -114,6 +114,7 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); bool config_getMnemonic(char *dest, uint16_t dest_size); +bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size); #if DEBUG_LINK bool config_dumpNode(HDNodeType *node); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index cf1973ddbd..e338d6eaa5 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -49,7 +49,8 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); + resp.has_mnemonic_secret = config_getMnemonicBytes(resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes), &resp.mnemonic_secret.size); + resp.mnemonic_type = 0; // BIP-39 resp.has_node = config_dumpNode(&(resp.node)); diff --git a/firmware/protob/messages-debug.options b/firmware/protob/messages-debug.options index 8e1e6617f8..0561336225 100644 --- a/firmware/protob/messages-debug.options +++ b/firmware/protob/messages-debug.options @@ -3,7 +3,7 @@ DebugLinkDecision.input max_size:33 DebugLinkState.layout max_size:1024 DebugLinkState.pin max_size:10 DebugLinkState.matrix max_size:10 -DebugLinkState.mnemonic max_size:241 +DebugLinkState.mnemonic_secret max_size:240 DebugLinkState.reset_word max_size:12 DebugLinkState.reset_entropy max_size:128 DebugLinkState.recovery_fake_word max_size:12 From d6d6416b50bae8544a4294ba12416cdd381c8412 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 13 Mar 2019 17:10:01 +0100 Subject: [PATCH 1146/1154] usb: Avoid segfault in usbSleep(), usbReconnect() and usbPoll() when USB is not initialized. --- firmware/usb.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index 356bd03650..4830da6628 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -332,7 +332,7 @@ static void set_config(usbd_device *dev, uint16_t wValue) hid_control_request); } -static usbd_device *usbd_dev; +static usbd_device *usbd_dev = NULL; static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); static const struct usb_device_capability_descriptor* capabilities[] = { @@ -360,6 +360,10 @@ void usbInit(void) void usbPoll(void) { + if (usbd_dev == NULL) { + return; + } + static const uint8_t *data; // poll read buffer usbd_poll(usbd_dev); @@ -383,9 +387,11 @@ void usbPoll(void) void usbReconnect(void) { - usbd_disconnect(usbd_dev, 1); - delay(1000); - usbd_disconnect(usbd_dev, 0); + if (usbd_dev != NULL) { + usbd_disconnect(usbd_dev, 1); + delay(1000); + usbd_disconnect(usbd_dev, 0); + } } char usbTiny(char set) @@ -400,6 +406,8 @@ void usbSleep(uint32_t millis) uint32_t start = timer_ms(); while ((timer_ms() - start) < millis) { - usbd_poll(usbd_dev); + if (usbd_dev != NULL) { + usbd_poll(usbd_dev); + } } } From eba242b80690e702eb1be9aa570c42c2fa5def87 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Mar 2019 17:10:31 +0100 Subject: [PATCH 1147/1154] format: start using clang-format with style=Google --- .clang-format | 2 + bootloader/bootloader.c | 179 +- bootloader/bootloader.h | 2 +- bootloader/signatures.c | 266 +-- bootloader/signatures.h | 42 +- bootloader/usb.c | 752 ++++----- bootloader/usb_desc.h | 116 +- bootloader/usb_erase.h | 83 +- bootloader/usb_send.h | 164 +- buttons.c | 81 +- buttons.h | 14 +- common.c | 82 +- common.h | 13 +- demo/demo.c | 428 ++--- emulator/buttons.c | 18 +- emulator/memory.c | 133 +- emulator/oled.c | 160 +- emulator/rng.c | 14 +- emulator/setup.c | 81 +- emulator/strl.c | 18 +- emulator/timer.c | 8 +- emulator/udp.c | 130 +- firmware/bl_check.c | 223 ++- firmware/coins.c | 96 +- firmware/coins.h | 52 +- firmware/config.c | 1410 ++++++++-------- firmware/config.h | 96 +- firmware/crypto.c | 836 +++++----- firmware/crypto.h | 43 +- firmware/debug.c | 63 +- firmware/debug.h | 10 +- firmware/ethereum.c | 1199 +++++++------- firmware/ethereum.h | 5 +- firmware/fsm.c | 387 ++--- firmware/fsm.h | 27 +- firmware/fsm_msg_coin.h | 503 +++--- firmware/fsm_msg_common.h | 632 ++++---- firmware/fsm_msg_crypto.h | 427 ++--- firmware/fsm_msg_debug.h | 124 +- firmware/fsm_msg_ethereum.h | 244 +-- firmware/fsm_msg_lisk.h | 166 +- firmware/fsm_msg_nem.h | 488 +++--- firmware/fsm_msg_stellar.h | 385 +++-- firmware/layout2.c | 1595 +++++++++--------- firmware/layout2.h | 44 +- firmware/lisk.c | 554 +++---- firmware/lisk.h | 3 +- firmware/messages.c | 492 +++--- firmware/messages.h | 2 +- firmware/nem2.c | 1216 +++++++------- firmware/nem2.h | 149 +- firmware/otp.c | 74 +- firmware/otp.h | 14 +- firmware/pinmatrix.c | 86 +- firmware/protect.c | 491 +++--- firmware/protect.h | 3 +- firmware/recovery-table.h | 1 + firmware/recovery.c | 770 ++++----- firmware/recovery.h | 7 +- firmware/reset.c | 287 ++-- firmware/reset.h | 9 +- firmware/signing.c | 2429 ++++++++++++++------------- firmware/signing.h | 5 +- firmware/stellar.c | 3066 +++++++++++++++++------------------ firmware/stellar.h | 58 +- firmware/transaction.c | 1455 +++++++++-------- firmware/transaction.h | 82 +- firmware/trezor.c | 201 +-- firmware/u2f.c | 1136 +++++++------ firmware/u2f.h | 12 +- firmware/u2f/u2f_keys.h | 58 +- firmware/u2f_knownapps.h | 8 +- firmware/udp.c | 56 +- firmware/usb.c | 590 +++---- flash.c | 185 +-- flash.h | 9 +- layout.c | 173 +- layout.h | 7 +- memory.c | 71 +- memory.h | 38 +- norcow_config.h | 8 +- oled.c | 544 +++---- oled.h | 12 +- rng.c | 21 +- secbool.h | 4 +- setup.c | 397 ++--- shell.nix | 2 +- supervise.c | 98 +- supervise.h | 34 +- timer.c | 47 +- usb21_standard.c | 109 +- usb21_standard.h | 27 +- usb_private.h | 1 + usb_standard.c | 1 + util.c | 101 +- util.h | 82 +- webusb.c | 131 +- webusb.h | 6 +- webusb_defs.h | 35 +- winusb.c | 223 ++- winusb.h | 4 +- winusb_defs.h | 67 +- 102 files changed, 14020 insertions(+), 13572 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..58d4b3b682 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +--- +BasedOnStyle: Google diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 6525ca283b..e30cc99399 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -19,132 +19,135 @@ #include -#include -#include #include +#include +#include #include "bootloader.h" -#include "signatures.h" #include "buttons.h" -#include "setup.h" -#include "usb.h" -#include "oled.h" -#include "util.h" -#include "signatures.h" #include "layout.h" -#include "rng.h" #include "memory.h" +#include "oled.h" +#include "rng.h" +#include "setup.h" +#include "signatures.h" +#include "usb.h" +#include "util.h" -void layoutFirmwareFingerprint(const uint8_t *hash) -{ - char str[4][17]; - for (int i = 0; i < 4; i++) { - data2hex(hash + i * 8, 8, str[i]); - } - layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); +void layoutFirmwareFingerprint(const uint8_t *hash) { + char str[4][17]; + for (int i = 0; i < 4; i++) { + data2hex(hash + i * 8, 8, str[i]); + } + layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", + str[0], str[1], str[2], str[3], NULL, NULL); } -bool get_button_response(void) -{ - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - return button.YesUp; +bool get_button_response(void) { + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + return button.YesUp; } -void show_halt(const char *line1, const char *line2) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); - shutdown(); +void show_halt(const char *line1, const char *line2) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL, + "Unplug your TREZOR,", "reinstall firmware.", NULL); + shutdown(); } -static void show_unofficial_warning(const uint8_t *hash) -{ - layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); +static void show_unofficial_warning(const uint8_t *hash) { + layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, + "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, + NULL); - bool but = get_button_response(); - if (!but) { // no button was pressed -> halt - show_halt("Unofficial firmware", "aborted."); - } + bool but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt("Unofficial firmware", "aborted."); + } - layoutFirmwareFingerprint(hash); + layoutFirmwareFingerprint(hash); - but = get_button_response(); - if (!but) { // no button was pressed -> halt - show_halt("Unofficial firmware", "aborted."); - } + but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt("Unofficial firmware", "aborted."); + } - // everything is OK, user pressed 2x Continue -> continue program + // everything is OK, user pressed 2x Continue -> continue program } -static void __attribute__((noreturn)) load_app(int signed_firmware) -{ - // zero out SRAM - memset_reg(_ram_start, _ram_end, 0); +static void __attribute__((noreturn)) load_app(int signed_firmware) { + // zero out SRAM + memset_reg(_ram_start, _ram_end, 0); - jump_to_firmware((const vector_table_t *) FLASH_PTR(FLASH_APP_START), signed_firmware); + jump_to_firmware((const vector_table_t *)FLASH_PTR(FLASH_APP_START), + signed_firmware); } -static void bootloader_loop(void) -{ - oledClear(); - oledDrawBitmap(0, 0, &bmp_logo64); - if (firmware_present_new()) { - oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); - oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); - oledDrawStringCenter(90, 50, VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); - } else { - oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD); - oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD); - oledDrawStringCenter(90, 50, "trezor.io/start", FONT_STANDARD); - } - oledRefresh(); +static void bootloader_loop(void) { + oledClear(); + oledDrawBitmap(0, 0, &bmp_logo64); + if (firmware_present_new()) { + oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); + oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); + oledDrawStringCenter(90, 50, + VERSTR(VERSION_MAJOR) "." VERSTR( + VERSION_MINOR) "." VERSTR(VERSION_PATCH), + FONT_STANDARD); + } else { + oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD); + oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD); + oledDrawStringCenter(90, 50, "trezor.io/start", FONT_STANDARD); + } + oledRefresh(); - usbLoop(); + usbLoop(); } -int main(void) -{ +int main(void) { #ifndef APPVER - setup(); + setup(); #endif - __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks #ifndef APPVER - memory_protect(); - oledInit(); + memory_protect(); + oledInit(); #endif - mpu_config_bootloader(); + mpu_config_bootloader(); #ifndef APPVER - bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0; + bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0; - if (firmware_present_new() && !left_pressed) { + if (firmware_present_new() && !left_pressed) { + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64_empty); + oledRefresh(); - oledClear(); - oledDrawBitmap(40, 0, &bmp_logo64_empty); - oledRefresh(); + const image_header *hdr = + (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); - const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + uint8_t fingerprint[32]; + int signed_firmware = signatures_new_ok(hdr, fingerprint); + if (SIG_OK != signed_firmware) { + show_unofficial_warning(fingerprint); + } - uint8_t fingerprint[32]; - int signed_firmware = signatures_new_ok(hdr, fingerprint); - if (SIG_OK != signed_firmware) { - show_unofficial_warning(fingerprint); - } + if (SIG_OK != check_firmware_hashes(hdr)) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware", + "detected.", NULL, "Unplug your TREZOR,", + "reinstall firmware.", NULL); + shutdown(); + } - if (SIG_OK != check_firmware_hashes(hdr)) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware", "detected.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); - shutdown(); - } - - mpu_config_off(); - load_app(signed_firmware); - } + mpu_config_off(); + load_app(signed_firmware); + } #endif - bootloader_loop(); + bootloader_loop(); - return 0; + return 0; } diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index 1217569b5a..b967c7f0b9 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -31,8 +31,8 @@ #define VERSION_MINOR_CHAR "\x08" #define VERSION_PATCH_CHAR "\x00" -#include #include +#include void show_halt(const char *line1, const char *line2); void layoutFirmwareFingerprint(const uint8_t *hash); diff --git a/bootloader/signatures.c b/bootloader/signatures.c index ec6ca3af62..7e98247571 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -19,16 +19,16 @@ #include -#include "signatures.h" -#include "ecdsa.h" -#include "secp256k1.h" -#include "sha2.h" #include "bootloader.h" +#include "ecdsa.h" #include "memory.h" #include "memzero.h" +#include "secp256k1.h" +#include "sha2.h" +#include "signatures.h" -const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR -const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF +const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR +const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF #define PUBKEYS 5 @@ -42,152 +42,162 @@ static const uint8_t * const pubkey[PUBKEYS] = { #define SIGNATURES 3 -#define FLASH_META_START 0x08008000 -#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) -#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) -#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) -#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) -#define FLASH_OLD_APP_START 0x08010000 -#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) -#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) -#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) +#define FLASH_META_START 0x08008000 +#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) +#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) +#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) +#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) +#define FLASH_OLD_APP_START 0x08010000 +#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) +#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) +#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) -bool firmware_present_old(void) -{ - if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 8192) { // firmware reports smaller size than 8192 - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_APP_LEN) { // firmware reports bigger size than flash size - return false; - } +bool firmware_present_old(void) { + if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, + 4)) { // magic does not match + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < + 8192) { // firmware reports smaller size than 8192 + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > + FLASH_APP_LEN) { // firmware reports bigger size than flash size + return false; + } - return true; + return true; } -int signatures_old_ok(void) -{ - const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); - const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); - const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); - const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3); +int signatures_old_ok(void) { + const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); + const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); + const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); + const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3); - if (codelen > FLASH_APP_LEN) { - return false; - } + if (codelen > FLASH_APP_LEN) { + return false; + } - uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash); + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash); - if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index - if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index - if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index + if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index + if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index - if (sigindex1 == sigindex2) return SIG_FAIL; // duplicate use - if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use - if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use + if (sigindex1 == sigindex2) return SIG_FAIL; // duplicate use + if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use + if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash)) { // failure - return SIG_FAIL; - } - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash)) { // failure - return SIG_FAIL; - } - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash)) { // failture - return SIG_FAIL; - } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], + (const uint8_t *)FLASH_META_SIG1, + hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], + (const uint8_t *)FLASH_META_SIG2, + hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], + (const uint8_t *)FLASH_META_SIG3, + hash)) { // failture + return SIG_FAIL; + } - return SIG_OK; + return SIG_OK; } -void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) -{ - image_header copy; - memcpy(©, hdr, sizeof(image_header)); - memzero(copy.sig1, sizeof(copy.sig1)); - memzero(copy.sig2, sizeof(copy.sig2)); - memzero(copy.sig3, sizeof(copy.sig3)); - copy.sigindex1 = 0; - copy.sigindex2 = 0; - copy.sigindex3 = 0; - sha256_Raw((const uint8_t *)©, sizeof(image_header), hash); +void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) { + image_header copy; + memcpy(©, hdr, sizeof(image_header)); + memzero(copy.sig1, sizeof(copy.sig1)); + memzero(copy.sig2, sizeof(copy.sig2)); + memzero(copy.sig3, sizeof(copy.sig3)); + copy.sigindex1 = 0; + copy.sigindex2 = 0; + copy.sigindex3 = 0; + sha256_Raw((const uint8_t *)©, sizeof(image_header), hash); } -bool firmware_present_new(void) -{ - const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); - if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; - // we need to ignore hdrlen for now - // because we keep reset_handler ptr there - // for compatibility with older bootloaders - // after this is no longer necessary, let's uncomment the line below: - // if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; - if (hdr->codelen > FLASH_APP_LEN) return false; - if (hdr->codelen < 4096) return false; +bool firmware_present_new(void) { + const image_header *hdr = + (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; + // we need to ignore hdrlen for now + // because we keep reset_handler ptr there + // for compatibility with older bootloaders + // after this is no longer necessary, let's uncomment the line below: + // if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; + if (hdr->codelen > FLASH_APP_LEN) return false; + if (hdr->codelen < 4096) return false; - return true; + return true; } -int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) -{ - uint8_t hash[32]; - compute_firmware_fingerprint(hdr, hash); +int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) { + uint8_t hash[32]; + compute_firmware_fingerprint(hdr, hash); - if (store_fingerprint) { - memcpy(store_fingerprint, hash, 32); - } + if (store_fingerprint) { + memcpy(store_fingerprint, hash, 32); + } - if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index - if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index - if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index + if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) + return SIG_FAIL; // invalid index + if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) + return SIG_FAIL; // invalid index + if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) + return SIG_FAIL; // invalid index - if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use - if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use - if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use + if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use + if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use + if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], hdr->sig1, hash)) { // failure - return SIG_FAIL; - } - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1], hdr->sig2, hash)) { // failure - return SIG_FAIL; - } - if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], hdr->sig3, hash)) { // failure - return SIG_FAIL; - } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], + hdr->sig1, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1], + hdr->sig2, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], + hdr->sig3, hash)) { // failure + return SIG_FAIL; + } - return SIG_OK; + return SIG_OK; } -int mem_is_empty(const uint8_t *src, uint32_t len) -{ - for (uint32_t i = 0; i < len; i++) { - if (src[i]) return 0; - } - return 1; +int mem_is_empty(const uint8_t *src, uint32_t len) { + for (uint32_t i = 0; i < len; i++) { + if (src[i]) return 0; + } + return 1; } -int check_firmware_hashes(const image_header *hdr) -{ - uint8_t hash[32]; - // check hash of the first code chunk - sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); - if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL; - // check remaining used chunks - uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen; - int used_chunks = total_len / FW_CHUNK_SIZE; - if (total_len % FW_CHUNK_SIZE > 0) { - used_chunks++; - } - for (int i = 1; i < used_chunks; i++) { - sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, hash); - if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; - } - // check unused chunks - for (int i = used_chunks; i < 16; i++) { - if (!mem_is_empty(hdr->hashes + 32 * i, 32)) return SIG_FAIL; - } - // all OK - return SIG_OK; +int check_firmware_hashes(const image_header *hdr) { + uint8_t hash[32]; + // check hash of the first code chunk + sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); + if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL; + // check remaining used chunks + uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen; + int used_chunks = total_len / FW_CHUNK_SIZE; + if (total_len % FW_CHUNK_SIZE > 0) { + used_chunks++; + } + for (int i = 1; i < used_chunks; i++) { + sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, + hash); + if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; + } + // check unused chunks + for (int i = used_chunks; i < 16; i++) { + if (!mem_is_empty(hdr->hashes + 32 * i, 32)) return SIG_FAIL; + } + // all OK + return SIG_OK; } diff --git a/bootloader/signatures.h b/bootloader/signatures.h index 6d3c00f969..c47e325e40 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -23,11 +23,11 @@ #include #include -extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR -extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF +extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR +extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF -#define SIG_OK 0x5A3CA5C3 -#define SIG_FAIL 0x00000000 +#define SIG_OK 0x5A3CA5C3 +#define SIG_FAIL 0x00000000 bool firmware_present_old(void); int signatures_old_ok(void); @@ -38,23 +38,23 @@ int signatures_old_ok(void); // immediately following the chunk hashes typedef struct { - uint32_t magic; - uint32_t hdrlen; - uint32_t expiry; - uint32_t codelen; - uint32_t version; - uint32_t fix_version; - uint8_t __reserved1[8]; - uint8_t hashes[512]; - uint8_t sig1[64]; - uint8_t sig2[64]; - uint8_t sig3[64]; - uint8_t sigindex1; - uint8_t sigindex2; - uint8_t sigindex3; - uint8_t __reserved2[220]; - uint8_t __sigmask; - uint8_t __sig[64]; + uint32_t magic; + uint32_t hdrlen; + uint32_t expiry; + uint32_t codelen; + uint32_t version; + uint32_t fix_version; + uint8_t __reserved1[8]; + uint8_t hashes[512]; + uint8_t sig1[64]; + uint8_t sig2[64]; + uint8_t sig3[64]; + uint8_t sigindex1; + uint8_t sigindex2; + uint8_t sigindex3; + uint8_t __reserved2[220]; + uint8_t __sigmask; + uint8_t __sig[64]; } __attribute__((packed)) image_header; #define FW_CHUNK_SIZE 65536 diff --git a/bootloader/usb.c b/bootloader/usb.c index 84885e8513..8af36b7c94 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -17,425 +17,451 @@ * along with this library. If not, see . */ -#include #include +#include #include -#include "buttons.h" #include "bootloader.h" +#include "buttons.h" +#include "ecdsa.h" +#include "layout.h" +#include "memory.h" +#include "memzero.h" #include "oled.h" #include "rng.h" -#include "usb.h" -#include "layout.h" -#include "util.h" -#include "signatures.h" -#include "sha2.h" -#include "ecdsa.h" #include "secp256k1.h" -#include "memzero.h" -#include "memory.h" +#include "sha2.h" +#include "signatures.h" +#include "usb.h" +#include "util.h" #include "usb21_standard.h" #include "webusb.h" #include "winusb.h" #include "usb_desc.h" -#include "usb_send.h" #include "usb_erase.h" +#include "usb_send.h" enum { - STATE_READY, - STATE_OPEN, - STATE_FLASHSTART, - STATE_FLASHING, - STATE_CHECK, - STATE_END, + STATE_READY, + STATE_OPEN, + STATE_FLASHSTART, + STATE_FLASHING, + STATE_CHECK, + STATE_END, }; static uint32_t flash_pos = 0, flash_len = 0; static uint32_t chunk_idx = 0; static char flash_state = STATE_READY; -static uint32_t FW_HEADER[FLASH_FWHEADER_LEN/sizeof(uint32_t)]; -static uint32_t FW_CHUNK[FW_CHUNK_SIZE/sizeof(uint32_t)]; +static uint32_t FW_HEADER[FLASH_FWHEADER_LEN / sizeof(uint32_t)]; +static uint32_t FW_CHUNK[FW_CHUNK_SIZE / sizeof(uint32_t)]; -static void check_and_write_chunk(void) -{ - uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; - uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; - if (chunk_pos == 0) { - chunk_pos = FW_CHUNK_SIZE; - } - uint8_t hash[32]; - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset); - if (chunk_pos < 64 * 1024) { - // pad with FF - for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) { - sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4); - } - } - sha256_Final(&ctx, hash); +static void check_and_write_chunk(void) { + uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; + uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; + if (chunk_pos == 0) { + chunk_pos = FW_CHUNK_SIZE; + } + uint8_t hash[32]; + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset); + if (chunk_pos < 64 * 1024) { + // pad with FF + for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) { + sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4); + } + } + sha256_Final(&ctx, hash); - const image_header *hdr = (const image_header *)FW_HEADER; - // invalid chunk sent - if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) { - // erase storage - erase_storage(); - flash_state = STATE_END; - show_halt("Error installing", "firmware."); - return; - } + const image_header *hdr = (const image_header *)FW_HEADER; + // invalid chunk sent + if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) { + // erase storage + erase_storage(); + flash_state = STATE_END; + show_halt("Error installing", "firmware."); + return; + } - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) { - flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]); - } - flash_wait_for_last_operation(); - flash_lock(); + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (uint32_t i = offset / sizeof(uint32_t); i < chunk_pos / sizeof(uint32_t); + i++) { + flash_program_word( + FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), + FW_CHUNK[i]); + } + flash_wait_for_last_operation(); + flash_lock(); - // all done - if (flash_len == flash_pos) { - // check remaining chunks if any - for (uint32_t i = chunk_idx + 1; i < 16; i++) { - // hash should be empty if the chunk is unused - if (!mem_is_empty(hdr->hashes + 32 * i, 32)) { - flash_state = STATE_END; - show_halt("Error installing", "firmware."); - return; - } - } - } + // all done + if (flash_len == flash_pos) { + // check remaining chunks if any + for (uint32_t i = chunk_idx + 1; i < 16; i++) { + // hash should be empty if the chunk is unused + if (!mem_is_empty(hdr->hashes + 32 * i, 32)) { + flash_state = STATE_END; + show_halt("Error installing", "firmware."); + return; + } + } + } - memzero(FW_CHUNK, sizeof(FW_CHUNK)); - chunk_idx++; + memzero(FW_CHUNK, sizeof(FW_CHUNK)); + chunk_idx++; } -static void rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static uint16_t msg_id = 0xFFFF; - static uint8_t buf[64] __attribute__((aligned(4))); - static uint32_t w; - static int wi; - static int old_was_signed; +static void rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static uint16_t msg_id = 0xFFFF; + static uint8_t buf[64] __attribute__((aligned(4))); + static uint32_t w; + static int wi; + static int old_was_signed; - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; - if (flash_state == STATE_END) { - return; - } + if (flash_state == STATE_END) { + return; + } - if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) { - if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard - return; - } - // struct.unpack(">HL") => msg, size - msg_id = (buf[3] << 8) + buf[4]; - } + if (flash_state == STATE_READY || flash_state == STATE_OPEN || + flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) { + if (buf[0] != '?' || buf[1] != '#' || + buf[2] != '#') { // invalid start - discard + return; + } + // struct.unpack(">HL") => msg, size + msg_id = (buf[3] << 8) + buf[4]; + } - if (flash_state == STATE_READY || flash_state == STATE_OPEN) { - if (msg_id == 0x0000) { // Initialize message (id 0) - send_msg_features(dev); - flash_state = STATE_OPEN; - return; - } - if (msg_id == 0x0037) { // GetFeatures message (id 55) - send_msg_features(dev); - return; - } - if (msg_id == 0x0001) { // Ping message (id 1) - send_msg_success(dev); - return; - } - if (msg_id == 0x0005) { // WipeDevice message (id 5) - layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); - bool but = get_button_response(); - if (but) { - erase_storage_code_progress(); - flash_state = STATE_END; - layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); - send_msg_success(dev); - } else { - flash_state = STATE_END; - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); - send_msg_failure(dev); - } - return; - } - } + if (flash_state == STATE_READY || flash_state == STATE_OPEN) { + if (msg_id == 0x0000) { // Initialize message (id 0) + send_msg_features(dev); + flash_state = STATE_OPEN; + return; + } + if (msg_id == 0x0037) { // GetFeatures message (id 55) + send_msg_features(dev); + return; + } + if (msg_id == 0x0001) { // Ping message (id 1) + send_msg_success(dev); + return; + } + if (msg_id == 0x0005) { // WipeDevice message (id 5) + layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, + "Do you really want to", "wipe the device?", NULL, + "All data will be lost.", NULL, NULL); + bool but = get_button_response(); + if (but) { + erase_storage_code_progress(); + flash_state = STATE_END; + layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", + "successfully wiped.", NULL, "You may now", + "unplug your TREZOR.", NULL); + send_msg_success(dev); + } else { + flash_state = STATE_END; + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe", + "aborted.", NULL, "You may now", "unplug your TREZOR.", + NULL); + send_msg_failure(dev); + } + return; + } + } - if (flash_state == STATE_OPEN) { - if (msg_id == 0x0006) { // FirmwareErase message (id 6) - bool proceed = false; - if (firmware_present_new()) { - layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); - proceed = get_button_response(); - } else { - proceed = true; - } - if (proceed) { - // check whether the current firmware is signed (old or new method) - if (firmware_present_new()) { - const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); - old_was_signed = signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr); - } else if (firmware_present_old()) { - old_was_signed = signatures_old_ok(); - } else { - old_was_signed = SIG_FAIL; - } - erase_code_progress(); - send_msg_success(dev); - flash_state = STATE_FLASHSTART; - } else { - send_msg_failure(dev); - flash_state = STATE_END; - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); - } - return; - } - return; - } + if (flash_state == STATE_OPEN) { + if (msg_id == 0x0006) { // FirmwareErase message (id 6) + bool proceed = false; + if (firmware_present_new()) { + layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, + "Install new", "firmware?", NULL, "Never do this without", + "your recovery card!", NULL); + proceed = get_button_response(); + } else { + proceed = true; + } + if (proceed) { + // check whether the current firmware is signed (old or new method) + if (firmware_present_new()) { + const image_header *hdr = + (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + old_was_signed = + signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr); + } else if (firmware_present_old()) { + old_was_signed = signatures_old_ok(); + } else { + old_was_signed = SIG_FAIL; + } + erase_code_progress(); + send_msg_success(dev); + flash_state = STATE_FLASHSTART; + } else { + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, + "Firmware installation", "aborted.", NULL, "You may now", + "unplug your TREZOR.", NULL); + } + return; + } + return; + } - if (flash_state == STATE_FLASHSTART) { - if (msg_id == 0x0007) { // FirmwareUpload message (id 7) - if (buf[9] != 0x0a) { // invalid contents - send_msg_failure(dev); - flash_state = STATE_END; - show_halt("Error installing", "firmware."); - return; - } - // read payload length - const uint8_t *p = buf + 10; - flash_len = readprotobufint(&p); - if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small - send_msg_failure(dev); - flash_state = STATE_END; - show_halt("Firmware is too small.", NULL); - return; - } - if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big - send_msg_failure(dev); - flash_state = STATE_END; - show_halt("Firmware is too big.", NULL); - return; - } - // check firmware magic - if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { - send_msg_failure(dev); - flash_state = STATE_END; - show_halt("Wrong firmware header.", NULL); - return; - } - memzero(FW_HEADER, sizeof(FW_HEADER)); - memzero(FW_CHUNK, sizeof(FW_CHUNK)); - flash_state = STATE_FLASHING; - flash_pos = 0; - chunk_idx = 0; - w = 0; - while (p < buf + 64) { - w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w - wi++; - if (wi == 4) { - FW_HEADER[flash_pos / 4] = w; - flash_pos += 4; - wi = 0; - } - p++; - } - return; - } - return; - } + if (flash_state == STATE_FLASHSTART) { + if (msg_id == 0x0007) { // FirmwareUpload message (id 7) + if (buf[9] != 0x0a) { // invalid contents + send_msg_failure(dev); + flash_state = STATE_END; + show_halt("Error installing", "firmware."); + return; + } + // read payload length + const uint8_t *p = buf + 10; + flash_len = readprotobufint(&p); + if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small + send_msg_failure(dev); + flash_state = STATE_END; + show_halt("Firmware is too small.", NULL); + return; + } + if (flash_len > + FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big + send_msg_failure(dev); + flash_state = STATE_END; + show_halt("Firmware is too big.", NULL); + return; + } + // check firmware magic + if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { + send_msg_failure(dev); + flash_state = STATE_END; + show_halt("Wrong firmware header.", NULL); + return; + } + memzero(FW_HEADER, sizeof(FW_HEADER)); + memzero(FW_CHUNK, sizeof(FW_CHUNK)); + flash_state = STATE_FLASHING; + flash_pos = 0; + chunk_idx = 0; + w = 0; + while (p < buf + 64) { + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w + wi++; + if (wi == 4) { + FW_HEADER[flash_pos / 4] = w; + flash_pos += 4; + wi = 0; + } + p++; + } + return; + } + return; + } - if (flash_state == STATE_FLASHING) { - if (buf[0] != '?') { // invalid contents - send_msg_failure(dev); - flash_state = STATE_END; - show_halt("Error installing", "firmware."); - return; - } + if (flash_state == STATE_FLASHING) { + if (buf[0] != '?') { // invalid contents + send_msg_failure(dev); + flash_state = STATE_END; + show_halt("Error installing", "firmware."); + return; + } - static uint8_t flash_anim = 0; - if (flash_anim % 32 == 4) { - layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); - } - flash_anim++; + static uint8_t flash_anim = 0; + if (flash_anim % 32 == 4) { + layoutProgress("INSTALLING ... Please wait", + 1000 * flash_pos / flash_len); + } + flash_anim++; - const uint8_t *p = buf + 1; - while (p < buf + 64 && flash_pos < flash_len) { - w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w - wi++; - if (wi == 4) { - if (flash_pos < FLASH_FWHEADER_LEN) { - FW_HEADER[flash_pos / 4] = w; - } else { - FW_CHUNK[(flash_pos % FW_CHUNK_SIZE)/ 4] = w; - } - flash_pos += 4; - wi = 0; - // finished the whole chunk - if (flash_pos % FW_CHUNK_SIZE == 0) { - check_and_write_chunk(); - } - } - p++; - } - // flashing done - if (flash_pos == flash_len) { - // flush remaining data in the last chunk - if (flash_pos % FW_CHUNK_SIZE > 0) { - check_and_write_chunk(); - } - flash_state = STATE_CHECK; - const image_header *hdr = (const image_header *)FW_HEADER; - if (SIG_OK != signatures_new_ok(hdr, NULL)) { - send_msg_buttonrequest_firmwarecheck(dev); - return; - } - } else { - return; - } - } + const uint8_t *p = buf + 1; + while (p < buf + 64 && flash_pos < flash_len) { + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w + wi++; + if (wi == 4) { + if (flash_pos < FLASH_FWHEADER_LEN) { + FW_HEADER[flash_pos / 4] = w; + } else { + FW_CHUNK[(flash_pos % FW_CHUNK_SIZE) / 4] = w; + } + flash_pos += 4; + wi = 0; + // finished the whole chunk + if (flash_pos % FW_CHUNK_SIZE == 0) { + check_and_write_chunk(); + } + } + p++; + } + // flashing done + if (flash_pos == flash_len) { + // flush remaining data in the last chunk + if (flash_pos % FW_CHUNK_SIZE > 0) { + check_and_write_chunk(); + } + flash_state = STATE_CHECK; + const image_header *hdr = (const image_header *)FW_HEADER; + if (SIG_OK != signatures_new_ok(hdr, NULL)) { + send_msg_buttonrequest_firmwarecheck(dev); + return; + } + } else { + return; + } + } - if (flash_state == STATE_CHECK) { + if (flash_state == STATE_CHECK) { + // use the firmware header from RAM + const image_header *hdr = (const image_header *)FW_HEADER; - // use the firmware header from RAM - const image_header *hdr = (const image_header *)FW_HEADER; + bool hash_check_ok; + // show fingerprint of unsigned firmware + if (SIG_OK != signatures_new_ok(hdr, NULL)) { + if (msg_id != 0x001B) { // ButtonAck message (id 27) + return; + } + uint8_t hash[32]; + compute_firmware_fingerprint(hdr, hash); + layoutFirmwareFingerprint(hash); + hash_check_ok = get_button_response(); + } else { + hash_check_ok = true; + } - bool hash_check_ok; - // show fingerprint of unsigned firmware - if (SIG_OK != signatures_new_ok(hdr, NULL)) { - if (msg_id != 0x001B) { // ButtonAck message (id 27) - return; - } - uint8_t hash[32]; - compute_firmware_fingerprint(hdr, hash); - layoutFirmwareFingerprint(hash); - hash_check_ok = get_button_response(); - } else { - hash_check_ok = true; - } + layoutProgress("INSTALLING ... Please wait", 1000); + // wipe storage if: + // 1) old firmware was unsigned or not present + // 2) signatures are not OK + // 3) hashes are not OK + if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || + SIG_OK != check_firmware_hashes(hdr)) { + // erase storage + erase_storage(); + // check erasure + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); + if (memcmp(hash, + "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20" + "\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40" + "\x76\xbc", + 32) != 0) { + send_msg_failure(dev); + show_halt("Error installing", "firmware."); + return; + } + } + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // write firmware header only when hash was confirmed + if (hash_check_ok) { + for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), + FW_HEADER[i]); + } + } else { + for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0); + } + } + flash_wait_for_last_operation(); + flash_lock(); - layoutProgress("INSTALLING ... Please wait", 1000); - // wipe storage if: - // 1) old firmware was unsigned or not present - // 2) signatures are not OK - // 3) hashes are not OK - if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || SIG_OK != check_firmware_hashes(hdr)) { - // erase storage - erase_storage(); - // check erasure - uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); - if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { - send_msg_failure(dev); - show_halt("Error installing", "firmware."); - return; - } - } - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // write firmware header only when hash was confirmed - if (hash_check_ok) { - for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { - flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), FW_HEADER[i]); - } - } else { - for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { - flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0); - } - } - flash_wait_for_last_operation(); - flash_lock(); - - flash_state = STATE_END; - if (hash_check_ok) { - layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); - send_msg_success(dev); - shutdown(); - } else { - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); - send_msg_failure(dev); - shutdown(); - } - return; - } + flash_state = STATE_END; + if (hash_check_ok) { + layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", + "successfully installed.", NULL, "You may now", + "unplug your TREZOR.", NULL); + send_msg_success(dev); + shutdown(); + } else { + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", + "aborted.", NULL, "You need to repeat", "the procedure with", + "the correct firmware."); + send_msg_failure(dev); + shutdown(); + } + return; + } } -static void set_config(usbd_device *dev, uint16_t wValue) -{ - (void)wValue; +static void set_config(usbd_device *dev, uint16_t wValue) { + (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, + rx_callback); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); +static uint8_t usbd_control_buffer[256] __attribute__((aligned(2))); -static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +static const struct usb_device_capability_descriptor *capabilities[] = { + (const struct usb_device_capability_descriptor + *)&webusb_platform_capability_descriptor, }; static const struct usb_bos_descriptor bos_descriptor = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), - .capabilities = capabilities -}; + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]), + .capabilities = capabilities}; -static void usbInit(void) -{ - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config); - usb21_setup(usbd_dev, &bos_descriptor); - webusb_setup(usbd_dev, "trezor.io/start"); - winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); +static void usbInit(void) { + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, + sizeof(usb_strings) / sizeof(const char *), + usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + webusb_setup(usbd_dev, "trezor.io/start"); + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } -static void checkButtons(void) -{ - static bool btn_left = false, btn_right = false, btn_final = false; - if (btn_final) { - return; - } - uint16_t state = gpio_port_read(BTN_PORT); - if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { - if ((state & BTN_PIN_NO) != BTN_PIN_NO) { - btn_left = true; - } - if ((state & BTN_PIN_YES) != BTN_PIN_YES) { - btn_right = true; - } - } - if (btn_left) { - oledBox(0, 0, 3, 3, true); - } - if (btn_right) { - oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true); - } - if (btn_left || btn_right) { - oledRefresh(); - } - if (btn_left && btn_right) { - btn_final = true; - } +static void checkButtons(void) { + static bool btn_left = false, btn_right = false, btn_final = false; + if (btn_final) { + return; + } + uint16_t state = gpio_port_read(BTN_PORT); + if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { + if ((state & BTN_PIN_NO) != BTN_PIN_NO) { + btn_left = true; + } + if ((state & BTN_PIN_YES) != BTN_PIN_YES) { + btn_right = true; + } + } + if (btn_left) { + oledBox(0, 0, 3, 3, true); + } + if (btn_right) { + oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true); + } + if (btn_left || btn_right) { + oledRefresh(); + } + if (btn_left && btn_right) { + btn_final = true; + } } -void usbLoop(void) -{ - bool firmware_present = firmware_present_new(); - usbInit(); - for (;;) { - usbd_poll(usbd_dev); - if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { - checkButtons(); - } - } +void usbLoop(void) { + bool firmware_present = firmware_present_new(); + usbInit(); + for (;;) { + usbd_poll(usbd_dev); + if (!firmware_present && + (flash_state == STATE_READY || flash_state == STATE_OPEN)) { + checkButtons(); + } + } } diff --git a/bootloader/usb_desc.h b/bootloader/usb_desc.h index d4044b9300..e23edbe7e0 100644 --- a/bootloader/usb_desc.h +++ b/bootloader/usb_desc.h @@ -1,75 +1,77 @@ #define USB_INTERFACE_INDEX_MAIN 0 -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x1209, - .idProduct = 0x53c0, - .bcdDevice = 0x0100, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0210, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x53c0, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, }; -static const struct usb_endpoint_descriptor endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor endpoints[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = endpoints, - .extra = NULL, - .extralen = 0, + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, }}; static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = iface, + .num_altsetting = 1, + .altsetting = iface, }}; static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, }; static const char *usb_strings[] = { - "SatoshiLabs", - "TREZOR", - "000000000000000000000000", + "SatoshiLabs", + "TREZOR", + "000000000000000000000000", }; diff --git a/bootloader/usb_erase.h b/bootloader/usb_erase.h index cadcf45730..d5ebba0b1d 100644 --- a/bootloader/usb_erase.h +++ b/bootloader/usb_erase.h @@ -1,44 +1,49 @@ -static void erase_storage_code_progress(void) -{ - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // erase storage area - for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { - layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // erase code area - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_wait_for_last_operation(); - flash_lock(); +static void erase_storage_code_progress(void) { + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // erase storage area + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; + i++) { + layoutProgress("WIPING ... Please wait", + 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / + (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // erase code area + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("WIPING ... Please wait", + 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / + (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); } -static void erase_code_progress(void) -{ - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_CODE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - layoutProgress("INSTALLING ... Please wait", 0); - flash_wait_for_last_operation(); - flash_lock(); +static void erase_code_progress(void) { + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("PREPARING ... Please wait", + 1000 * (i - FLASH_CODE_SECTOR_FIRST) / + (FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + layoutProgress("INSTALLING ... Please wait", 0); + flash_wait_for_last_operation(); + flash_lock(); } -static void erase_storage(void) -{ - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_wait_for_last_operation(); - flash_lock(); +static void erase_storage(void) { + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; + i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); } diff --git a/bootloader/usb_send.h b/bootloader/usb_send.h index ed73fbe08b..7f94ef9d8a 100644 --- a/bootloader/usb_send.h +++ b/bootloader/usb_send.h @@ -1,86 +1,92 @@ -static void send_msg_success(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Success message (id 2), payload len 0 - memcpy(response, - // header - "?##" - // msg_id - "\x00\x02" - // msg_size - "\x00\x00\x00\x00", - 9); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +static void send_msg_success(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Success message (id 2), payload len 0 + memcpy(response, + // header + "?##" + // msg_id + "\x00\x02" + // msg_size + "\x00\x00\x00\x00", + 9); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) { + } } -static void send_msg_failure(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Failure message (id 3), payload len 2 - // - code = 99 (Failure_FirmwareError) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x03" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x63", - 11); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +static void send_msg_failure(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Failure message (id 3), payload len 2 + // - code = 99 (Failure_FirmwareError) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x03" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" + "\x63", + 11); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) { + } } -static void send_msg_features(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Features message (id 17), payload len 25 - // - vendor = "trezor.io" - // - major_version = VERSION_MAJOR - // - minor_version = VERSION_MINOR - // - patch_version = VERSION_PATCH - // - bootloader_mode = True - // - firmware_present = True/False - // - model = "1" - memcpy(response, - // header - "?##" - // msg_id - "\x00\x11" - // msg_size - "\x00\x00\x00\x16" - // data - "\x0a" "\x09" "trezor.io" - "\x10" VERSION_MAJOR_CHAR - "\x18" VERSION_MINOR_CHAR - "\x20" VERSION_PATCH_CHAR - "\x28" "\x01" - "\x90\x01" "\x00" - "\xaa" "\x01" "1", - 34); - response[30] = firmware_present_new() ? 0x01 : 0x00; - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +static void send_msg_features(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Features message (id 17), payload len 25 + // - vendor = "trezor.io" + // - major_version = VERSION_MAJOR + // - minor_version = VERSION_MINOR + // - patch_version = VERSION_PATCH + // - bootloader_mode = True + // - firmware_present = True/False + // - model = "1" + memcpy(response, + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x16" + // data + "\x0a" + "\x09" + "trezor.io" + "\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" + "\x01" + "\x90\x01" + "\x00" + "\xaa" + "\x01" + "1", + 34); + response[30] = firmware_present_new() ? 0x01 : 0x00; + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) { + } } -static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: ButtonRequest message (id 26), payload len 2 - // - code = ButtonRequest_FirmwareCheck (9) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x1a" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x09", - 11 - ); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) { + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: ButtonRequest message (id 26), payload len 2 + // - code = ButtonRequest_FirmwareCheck (9) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x1a" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" + "\x09", + 11); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) { + } } diff --git a/buttons.c b/buttons.c index f416736c38..0a86dbe61b 100644 --- a/buttons.c +++ b/buttons.c @@ -22,52 +22,49 @@ struct buttonState button; #if !EMULATOR -uint16_t buttonRead(void) { - return gpio_port_read(BTN_PORT); -} +uint16_t buttonRead(void) { return gpio_port_read(BTN_PORT); } #endif -void buttonUpdate() -{ - static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; +void buttonUpdate() { + static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; - uint16_t state = buttonRead(); + uint16_t state = buttonRead(); - if ((state & BTN_PIN_YES) == 0) { // Yes button is down - if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down - if (button.YesDown < 2000000000) button.YesDown++; - button.YesUp = false; - } else { // last Yes was up - button.YesDown = 0; - button.YesUp = false; - } - } else { // Yes button is up - if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down - button.YesDown = 0; - button.YesUp = true; - } else { // last Yes was up - button.YesDown = 0; - button.YesUp = false; - } - } + if ((state & BTN_PIN_YES) == 0) { // Yes button is down + if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down + if (button.YesDown < 2000000000) button.YesDown++; + button.YesUp = false; + } else { // last Yes was up + button.YesDown = 0; + button.YesUp = false; + } + } else { // Yes button is up + if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down + button.YesDown = 0; + button.YesUp = true; + } else { // last Yes was up + button.YesDown = 0; + button.YesUp = false; + } + } - if ((state & BTN_PIN_NO) == 0) { // No button is down - if ((last_state & BTN_PIN_NO) == 0) { // last No was down - if (button.NoDown < 2000000000) button.NoDown++; - button.NoUp = false; - } else { // last No was up - button.NoDown = 0; - button.NoUp = false; - } - } else { // No button is up - if ((last_state & BTN_PIN_NO) == 0) { // last No was down - button.NoDown = 0; - button.NoUp = true; - } else { // last No was up - button.NoDown = 0; - button.NoUp = false; - } - } + if ((state & BTN_PIN_NO) == 0) { // No button is down + if ((last_state & BTN_PIN_NO) == 0) { // last No was down + if (button.NoDown < 2000000000) button.NoDown++; + button.NoUp = false; + } else { // last No was up + button.NoDown = 0; + button.NoUp = false; + } + } else { // No button is up + if ((last_state & BTN_PIN_NO) == 0) { // last No was down + button.NoDown = 0; + button.NoUp = true; + } else { // last No was up + button.NoDown = 0; + button.NoUp = false; + } + } - last_state = state; + last_state = state; } diff --git a/buttons.h b/buttons.h index fb24d58dd7..48f3c99842 100644 --- a/buttons.h +++ b/buttons.h @@ -24,10 +24,10 @@ #include struct buttonState { - volatile bool YesUp; - volatile int YesDown; - volatile bool NoUp; - volatile int NoDown; + volatile bool YesUp; + volatile int YesDown; + volatile bool NoUp; + volatile int NoDown; }; extern struct buttonState button; @@ -36,15 +36,15 @@ uint16_t buttonRead(void); void buttonUpdate(void); #ifndef BTN_PORT -#define BTN_PORT GPIOC +#define BTN_PORT GPIOC #endif #ifndef BTN_PIN_YES -#define BTN_PIN_YES GPIO2 +#define BTN_PIN_YES GPIO2 #endif #ifndef BTN_PIN_NO -#define BTN_PIN_NO GPIO5 +#define BTN_PIN_NO GPIO5 #endif #endif diff --git a/common.c b/common.c index ae7230613e..0bd282ead3 100644 --- a/common.c +++ b/common.c @@ -17,63 +17,67 @@ * along with this program. If not, see . */ -#include #include "common.h" -#include "rng.h" -#include "layout.h" -#include "oled.h" -#include "util.h" +#include #include "bitmaps.h" #include "firmware/usb.h" +#include "layout.h" +#include "oled.h" +#include "rng.h" +#include "util.h" uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; -void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { - const BITMAP *icon = &bmp_icon_error; - char line[128] = {0}; - int y = icon->height + 3; - oledClear(); +void __attribute__((noreturn)) +__fatal_error(const char *expr, const char *msg, const char *file, int line_num, + const char *func) { + const BITMAP *icon = &bmp_icon_error; + char line[128] = {0}; + int y = icon->height + 3; + oledClear(); - oledDrawBitmap(0, 0, icon); - oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); + oledDrawBitmap(0, 0, icon); + oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT) / 2 + 1, + "FATAL ERROR", FONT_STANDARD); - snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); - oledDrawString(0, y, line, FONT_STANDARD); - y += FONT_HEIGHT + 1; + snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; - snprintf(line, sizeof(line), "Msg: %s", msg ? msg : "(null)"); - oledDrawString(0, y, line, FONT_STANDARD); - y += FONT_HEIGHT + 1; + snprintf(line, sizeof(line), "Msg: %s", msg ? msg : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; - const char *label = "File: "; - snprintf(line, sizeof(line), "%s:%d", file ? file : "(null)", line_num); - oledDrawStringRight(OLED_WIDTH - 1, y, line, FONT_STANDARD); - oledBox(0, y, oledStringWidth(label, FONT_STANDARD), y + FONT_HEIGHT, false); - oledDrawString(0, y, label, FONT_STANDARD); - y += FONT_HEIGHT + 1; + const char *label = "File: "; + snprintf(line, sizeof(line), "%s:%d", file ? file : "(null)", line_num); + oledDrawStringRight(OLED_WIDTH - 1, y, line, FONT_STANDARD); + oledBox(0, y, oledStringWidth(label, FONT_STANDARD), y + FONT_HEIGHT, false); + oledDrawString(0, y, label, FONT_STANDARD); + y += FONT_HEIGHT + 1; - snprintf(line, sizeof(line), "Func: %s", func ? func : "(null)"); - oledDrawString(0, y, line, FONT_STANDARD); - y += FONT_HEIGHT + 1; + snprintf(line, sizeof(line), "Func: %s", func ? func : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; - oledDrawString(0, y, "Contact TREZOR support.", FONT_STANDARD); - oledRefresh(); + oledDrawString(0, y, "Contact TREZOR support.", FONT_STANDARD); + oledRefresh(); - shutdown(); + shutdown(); } -void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, "Please unplug", "the device."); - shutdown(); +void __attribute__((noreturn)) +error_shutdown(const char *line1, const char *line2, const char *line3, + const char *line4) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, + "Please unplug", "the device."); + shutdown(); } #ifndef NDEBUG -void __assert_func(const char *file, int line, const char *func, const char *expr) { - __fatal_error(expr, "assert failed", file, line, func); +void __assert_func(const char *file, int line, const char *func, + const char *expr) { + __fatal_error(expr, "assert failed", file, line, func); } #endif -void hal_delay(uint32_t ms) -{ - usbSleep(ms); -} +void hal_delay(uint32_t ms) { usbSleep(ms); } diff --git a/common.h b/common.h index a4fd9886ef..1774bc7f02 100644 --- a/common.h +++ b/common.h @@ -26,10 +26,17 @@ #define HW_ENTROPY_LEN (12 + 32) extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; -void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); -void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); +void __attribute__((noreturn)) +__fatal_error(const char *expr, const char *msg, const char *file, int line, + const char *func); +void __attribute__((noreturn)) +error_shutdown(const char *line1, const char *line2, const char *line3, + const char *line4); -#define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) +#define ensure(expr, msg) \ + (((expr) == sectrue) \ + ? (void)0 \ + : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) void hal_delay(uint32_t ms); diff --git a/demo/demo.c b/demo/demo.c index b2bbe8f98f..4ece26d9bf 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -17,17 +17,17 @@ * along with this library. If not, see . */ -#include -#include #include +#include +#include #include "bitmaps.h" #include "buttons.h" +#include "hmac.h" #include "layout.h" #include "oled.h" -#include "setup.h" -#include "hmac.h" #include "pbkdf2.h" #include "rng.h" +#include "setup.h" const int states = 2; int state = 0; @@ -40,252 +40,270 @@ uint8_t *salt = (uint8_t *)"TREZOR"; uint32_t saltlen; static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x1209, - .idProduct = 0x53c1, - .bcdDevice = 0x0100, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x53c1, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, }; /* got via usbhid-dump from CP2110 */ static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, - 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, - 0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, - 0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, - 0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, - 0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, - 0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, - 0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, - 0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, - 0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, - 0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, - 0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, - 0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, - 0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, - 0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, - 0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, - 0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, - 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, - 0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, - 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, - 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, - 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, - 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, - 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, - 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, - 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, + 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, + 0x40, 0x26, 0xFF, 0x00, 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x95, 0x02, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x95, 0x06, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x95, 0x0A, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x95, 0x0E, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x95, 0x12, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x95, 0x16, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x95, 0x1A, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x95, 0x1E, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x95, 0x22, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x95, 0x26, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x95, 0x2A, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x95, 0x2E, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x95, 0x32, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x95, 0x36, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, 0x95, 0x3A, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, 0x95, 0x3E, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, + 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x41, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, + 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, 0x95, 0x01, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, + 0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x47, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, + 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, 0x95, 0x01, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, + 0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x62, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, + 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, 0x95, 0x3F, 0x09, 0x01, + 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, + 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, }; static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; + struct usb_hid_descriptor hid_descriptor; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report; +} __attribute__((packed)) +hid_function = {.hid_descriptor = + { + .bLength = sizeof(hid_function), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor), + }}; -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x81, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0x02, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor hid_endpoints[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor hid_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = hid_endpoints, + .extra = &hid_function, + .extralen = sizeof(hid_function), }}; static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = hid_iface, + .num_altsetting = 1, + .altsetting = hid_iface, }}; static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, }; static const char *usb_strings[] = { - "SatoshiLabs", - "TREZOR", - "01234567", + "SatoshiLabs", + "TREZOR", + "01234567", }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) -{ - (void)complete; - (void)dev; +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) { + (void)complete; + (void)dev; - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200)) + return 0; - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + /* Handle the HID report descriptor. */ + *buf = (uint8_t *)hid_report_descriptor; + *len = sizeof(hid_report_descriptor); - return 1; + return 1; } -static void hid_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)dev; - (void)ep; +static void hid_rx_callback(usbd_device *dev, uint8_t ep) { + (void)dev; + (void)ep; } -static void hid_set_config(usbd_device *dev, uint16_t wValue) -{ - (void)wValue; +static void hid_set_config(usbd_device *dev, uint16_t wValue) { + (void)wValue; - usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request); + usbd_register_control_callback( + dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request); } static usbd_device *usbd_dev; static uint8_t usbd_control_buffer[128]; -void usbInit(void) -{ - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); +void usbInit(void) { + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, + usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, hid_set_config); } -int main(void) -{ +int main(void) { #ifndef APPVER - setup(); - __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks - oledInit(); + setup(); + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks + oledInit(); #else - setupApp(); - __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks + setupApp(); + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks #endif - usbInit(); + usbInit(); - passlen = strlen((char *)pass); - saltlen = strlen((char *)salt); + passlen = strlen((char *)pass); + saltlen = strlen((char *)salt); - for (;;) { - frame = 0; - switch (state) { - case 0: - oledClear(); - oledDrawBitmap(40, 0, &bmp_logo64); - break; - } - oledRefresh(); + for (;;) { + frame = 0; + switch (state) { + case 0: + oledClear(); + oledDrawBitmap(40, 0, &bmp_logo64); + break; + } + oledRefresh(); - do { - usbd_poll(usbd_dev); - switch (state) { - case 1: - layoutProgress("WORKING", frame % 41 * 25); - pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64); - usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); - break; - } + do { + usbd_poll(usbd_dev); + switch (state) { + case 1: + layoutProgress("WORKING", frame % 41 * 25); + pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64); + usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); + break; + } - buttonUpdate(); - frame += 1; - } while (!button.YesUp && !button.NoUp); + buttonUpdate(); + frame += 1; + } while (!button.YesUp && !button.NoUp); - if (button.YesUp) { - state = (state + 1) % states; - oledSwipeLeft(); - } else { - state = (state + states - 1) % states; - oledSwipeRight(); - } - } + if (button.YesUp) { + state = (state + 1) % states; + oledSwipeLeft(); + } else { + state = (state + states - 1) % states; + oledSwipeRight(); + } + } - return 0; + return 0; } diff --git a/emulator/buttons.c b/emulator/buttons.c index 71b94a4426..2d456aafbb 100644 --- a/emulator/buttons.c +++ b/emulator/buttons.c @@ -24,17 +24,17 @@ #endif uint16_t buttonRead(void) { - uint16_t state = 0; + uint16_t state = 0; #if !HEADLESS - const uint8_t *scancodes = SDL_GetKeyboardState(NULL); - if (scancodes[SDL_SCANCODE_LEFT]) { - state |= BTN_PIN_NO; - } - if (scancodes[SDL_SCANCODE_RIGHT]) { - state |= BTN_PIN_YES; - } + const uint8_t *scancodes = SDL_GetKeyboardState(NULL); + if (scancodes[SDL_SCANCODE_LEFT]) { + state |= BTN_PIN_NO; + } + if (scancodes[SDL_SCANCODE_RIGHT]) { + state |= BTN_PIN_YES; + } #endif - return ~state; + return ~state; } diff --git a/emulator/memory.c b/emulator/memory.c index 4bcda38863..a1acac60c9 100644 --- a/emulator/memory.c +++ b/emulator/memory.c @@ -17,16 +17,14 @@ * along with this library. If not, see . */ -#include #include #include +#include #include #include "memory.h" -void flash_lock(void) { - sync(); -} +void flash_lock(void) { sync(); } void flash_unlock(void) {} @@ -35,105 +33,104 @@ void flash_clear_status_flags(void) {} void flash_lock_option_bytes(void) {} void flash_unlock_option_bytes(void) {} -void flash_program_option_bytes(uint32_t data) { - (void) data; -} +void flash_program_option_bytes(uint32_t data) { (void)data; } static ssize_t sector_to_offset(uint8_t sector) { - switch (sector) { - case 0: - return 0x0; - case 1: - return 0x4000; - case 2: - return 0x8000; - case 3: - return 0xC000; - case 4: - return 0x10000; - case 5: - return 0x20000; - case 6: - return 0x40000; - case 7: - return 0x60000; - case 8: - return 0x80000; - default: - return -1; - } + switch (sector) { + case 0: + return 0x0; + case 1: + return 0x4000; + case 2: + return 0x8000; + case 3: + return 0xC000; + case 4: + return 0x10000; + case 5: + return 0x20000; + case 6: + return 0x40000; + case 7: + return 0x60000; + case 8: + return 0x80000; + default: + return -1; + } } static void *sector_to_address(uint8_t sector) { - ssize_t offset = sector_to_offset(sector); - if (offset < 0) { - return NULL; - } + ssize_t offset = sector_to_offset(sector); + if (offset < 0) { + return NULL; + } - return (void *) FLASH_PTR(FLASH_ORIGIN + offset); + return (void *)FLASH_PTR(FLASH_ORIGIN + offset); } static ssize_t sector_to_size(uint8_t sector) { - ssize_t start = sector_to_offset(sector); - if (start < 0) { - return -1; - } + ssize_t start = sector_to_offset(sector); + if (start < 0) { + return -1; + } - ssize_t end = sector_to_offset(sector + 1); - if (end < 0) { - return -1; - } + ssize_t end = sector_to_offset(sector + 1); + if (end < 0) { + return -1; + } - return end - start; + return end - start; } void flash_erase_sector(uint8_t sector, uint32_t program_size) { - (void) program_size; + (void)program_size; - void *address = sector_to_address(sector); - if (address == NULL) { - return; - } + void *address = sector_to_address(sector); + if (address == NULL) { + return; + } - ssize_t size = sector_to_size(sector); - if (size < 0) { - return; - } + ssize_t size = sector_to_size(sector); + if (size < 0) { + return; + } - memset(address, 0xFF, size); + memset(address, 0xFF, size); } void flash_erase_all_sectors(uint32_t program_size) { - (void) program_size; + (void)program_size; - memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE); + memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE); } void flash_program_word(uint32_t address, uint32_t data) { - *(volatile uint32_t *)FLASH_PTR(address) = data; + *(volatile uint32_t *)FLASH_PTR(address) = data; } void flash_program_byte(uint32_t address, uint8_t data) { - *(volatile uint8_t *)FLASH_PTR(address) = data; + *(volatile uint8_t *)FLASH_PTR(address) = data; } static bool flash_locked = true; void svc_flash_unlock(void) { - assert (flash_locked); - flash_locked = false; + assert(flash_locked); + flash_locked = false; } void svc_flash_program(uint32_t size) { - (void) size; - assert (!flash_locked); + (void)size; + assert(!flash_locked); } void svc_flash_erase_sector(uint16_t sector) { - assert (!flash_locked); - assert (sector >= FLASH_STORAGE_SECTOR_FIRST && sector <= FLASH_STORAGE_SECTOR_LAST); - flash_erase_sector(sector, 3); + assert(!flash_locked); + assert(sector >= FLASH_STORAGE_SECTOR_FIRST && + sector <= FLASH_STORAGE_SECTOR_LAST); + flash_erase_sector(sector, 3); } uint32_t svc_flash_lock(void) { - assert (!flash_locked); - flash_locked = true; - sync(); - return 0; + assert(!flash_locked); + flash_locked = true; + sync(); + return 0; } diff --git a/emulator/oled.c b/emulator/oled.c index cbb853c85c..a4466e9932 100644 --- a/emulator/oled.c +++ b/emulator/oled.c @@ -37,114 +37,114 @@ static SDL_Rect dstrect; #define ENV_OLED_SCALE "TREZOR_OLED_SCALE" static int emulatorFullscreen(void) { - const char *variable = getenv(ENV_OLED_FULLSCREEN); - if (!variable) { - return 0; - } - return atoi(variable); + const char *variable = getenv(ENV_OLED_FULLSCREEN); + if (!variable) { + return 0; + } + return atoi(variable); } static int emulatorScale(void) { - const char *variable = getenv(ENV_OLED_SCALE); - if (!variable) { - return 1; - } - int scale = atoi(variable); - if (scale >= 1 && scale <= 16) { - return scale; - } - return 1; + const char *variable = getenv(ENV_OLED_SCALE); + if (!variable) { + return 1; + } + int scale = atoi(variable); + if (scale >= 1 && scale <= 16) { + return scale; + } + return 1; } void oledInit(void) { - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); - exit(1); - } - atexit(SDL_Quit); + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); - int scale = emulatorScale(); - int fullscreen = emulatorFullscreen(); + int scale = emulatorScale(); + int fullscreen = emulatorFullscreen(); - SDL_Window *window = SDL_CreateWindow("TREZOR", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - OLED_WIDTH * scale, - OLED_HEIGHT * scale, - fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_Window *window = SDL_CreateWindow( + "TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + OLED_WIDTH * scale, OLED_HEIGHT * scale, + fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); - if (window == NULL) { - fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); - exit(1); - } + if (window == NULL) { + fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); + exit(1); + } - renderer = SDL_CreateRenderer(window, -1, 0); - if (!renderer) { - fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); - exit(1); - } - if (fullscreen) { - SDL_DisplayMode current_mode; - if (SDL_GetCurrentDisplayMode(0, ¤t_mode) != 0) - { - fprintf(stderr, "Failed to get current display mode: %s\n", SDL_GetError()); - exit(1); - } + renderer = SDL_CreateRenderer(window, -1, 0); + if (!renderer) { + fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); + exit(1); + } + if (fullscreen) { + SDL_DisplayMode current_mode; + if (SDL_GetCurrentDisplayMode(0, ¤t_mode) != 0) { + fprintf(stderr, "Failed to get current display mode: %s\n", + SDL_GetError()); + exit(1); + } - dstrect.x = (current_mode.w - OLED_WIDTH * scale) / 2; - dstrect.y = (current_mode.h - OLED_HEIGHT * scale) / 2; + dstrect.x = (current_mode.w - OLED_WIDTH * scale) / 2; + dstrect.y = (current_mode.h - OLED_HEIGHT * scale) / 2; - SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); - SDL_RenderClear(renderer); - SDL_ShowCursor(SDL_DISABLE); - } else { - dstrect.x = 0; - dstrect.y = 0; - } + SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderClear(renderer); + SDL_ShowCursor(SDL_DISABLE); + } else { + dstrect.x = 0; + dstrect.y = 0; + } - dstrect.w = OLED_WIDTH * scale; - dstrect.h = OLED_HEIGHT * scale; + dstrect.w = OLED_WIDTH * scale; + dstrect.h = OLED_HEIGHT * scale; - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); + texture = + SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); - oledClear(); - oledRefresh(); + oledClear(); + oledRefresh(); } void oledRefresh(void) { - /* Draw triangle in upper right corner */ - oledInvertDebugLink(); + /* Draw triangle in upper right corner */ + oledInvertDebugLink(); - const uint8_t *buffer = oledGetBuffer(); + const uint8_t *buffer = oledGetBuffer(); - static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; + static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; - for (size_t i = 0; i < OLED_BUFSIZE; i++) { - int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH; - int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7; + for (size_t i = 0; i < OLED_BUFSIZE; i++) { + int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH; + int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7; - for (uint8_t shift = 0; shift < 8; shift++, y--) { - bool set = (buffer[i] >> shift) & 1; - data[y][x] = set ? 0xFFFFFFFF : 0xFF000000; - } - } + for (uint8_t shift = 0; shift < 8; shift++, y--) { + bool set = (buffer[i] >> shift) & 1; + data[y][x] = set ? 0xFFFFFFFF : 0xFF000000; + } + } - SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); - SDL_RenderCopy(renderer, texture, NULL, &dstrect); - SDL_RenderPresent(renderer); + SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); + SDL_RenderCopy(renderer, texture, NULL, &dstrect); + SDL_RenderPresent(renderer); - /* Return it back */ - oledInvertDebugLink(); + /* Return it back */ + oledInvertDebugLink(); } void emulatorPoll(void) { - SDL_Event event; + SDL_Event event; - if (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - exit(1); - } - } + if (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + exit(1); + } + } } #endif diff --git a/emulator/rng.c b/emulator/rng.c index 8d53de28d3..cd6eb616ee 100644 --- a/emulator/rng.c +++ b/emulator/rng.c @@ -20,13 +20,13 @@ #include "rng.h" uint32_t random32(void) { - static uint32_t last = 0; - uint32_t new; + static uint32_t last = 0; + uint32_t new; - do { - emulatorRandom(&new, sizeof(new)); - } while (last == new); + do { + emulatorRandom(&new, sizeof(new)); + } while (last == new); - last = new; - return new; + last = new; + return new; } diff --git a/emulator/setup.c b/emulator/setup.c index 61b4bad149..81b283ecc4 100644 --- a/emulator/setup.c +++ b/emulator/setup.c @@ -48,60 +48,61 @@ static void setup_urandom(void); static void setup_flash(void); void setup(void) { - setup_urandom(); - setup_flash(); + setup_urandom(); + setup_flash(); } void __attribute__((noreturn)) shutdown(void) { - for(;;) pause(); + for (;;) pause(); } void emulatorRandom(void *buffer, size_t size) { - ssize_t n, len = 0; - do { - n = read(random_fd, (char*)buffer + len, size - len); - if (n < 0) { - perror("Failed to read " RANDOM_DEV_FILE); - exit(1); - } - len += n; - } while (len != (ssize_t)size); + ssize_t n, len = 0; + do { + n = read(random_fd, (char *)buffer + len, size - len); + if (n < 0) { + perror("Failed to read " RANDOM_DEV_FILE); + exit(1); + } + len += n; + } while (len != (ssize_t)size); } static void setup_urandom(void) { - random_fd = open(RANDOM_DEV_FILE, O_RDONLY); - if (random_fd < 0) { - perror("Failed to open " RANDOM_DEV_FILE); - exit(1); - } + random_fd = open(RANDOM_DEV_FILE, O_RDONLY); + if (random_fd < 0) { + perror("Failed to open " RANDOM_DEV_FILE); + exit(1); + } } static void setup_flash(void) { - int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); - if (fd < 0) { - perror("Failed to open flash emulation file"); - exit(1); - } + int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); + if (fd < 0) { + perror("Failed to open flash emulation file"); + exit(1); + } - off_t length = lseek(fd, 0, SEEK_END); - if (length < 0) { - perror("Failed to read length of flash emulation file"); - exit(1); - } + off_t length = lseek(fd, 0, SEEK_END); + if (length < 0) { + perror("Failed to read length of flash emulation file"); + exit(1); + } - emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (emulator_flash_base == MAP_FAILED) { - perror("Failed to map flash emulation file"); - exit(1); - } + emulator_flash_base = + mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (emulator_flash_base == MAP_FAILED) { + perror("Failed to map flash emulation file"); + exit(1); + } - if (length < FLASH_TOTAL_SIZE) { - if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { - perror("Failed to initialize flash emulation file"); - exit(1); - } + if (length < FLASH_TOTAL_SIZE) { + if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { + perror("Failed to initialize flash emulation file"); + exit(1); + } - /* Initialize the flash */ - flash_erase_all_sectors(FLASH_CR_PROGRAM_X32); - } + /* Initialize the flash */ + flash_erase_all_sectors(FLASH_CR_PROGRAM_X32); + } } diff --git a/emulator/strl.c b/emulator/strl.c index 26668b80a3..da48ac86f5 100644 --- a/emulator/strl.c +++ b/emulator/strl.c @@ -24,21 +24,21 @@ #if (!defined __APPLE__) && (!defined HAVE_STRLCPY) size_t strlcpy(char *dst, const char *src, size_t size) { - size_t ret = strlen(src); + size_t ret = strlen(src); - if (size) { - size_t len = MIN(ret, size - 1); - memcpy(dst, src, len); - dst[len] = '\0'; - } + if (size) { + size_t len = MIN(ret, size - 1); + memcpy(dst, src, len); + dst[len] = '\0'; + } - return ret; + return ret; } size_t strlcat(char *dst, const char *src, size_t size) { - size_t n = strnlen(dst, size); + size_t n = strnlen(dst, size); - return n + strlcpy(&dst[n], src, size - n); + return n + strlcpy(&dst[n], src, size - n); } #endif diff --git a/emulator/timer.c b/emulator/timer.c index efb95564bd..e994d9613d 100644 --- a/emulator/timer.c +++ b/emulator/timer.c @@ -24,9 +24,9 @@ void timer_init(void) {} uint32_t timer_ms(void) { - struct timespec t; - clock_gettime(CLOCK_MONOTONIC, &t); + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); - uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); - return msec; + uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); + return msec; } diff --git a/emulator/udp.c b/emulator/udp.c index b7b18a914c..4a80059963 100644 --- a/emulator/udp.c +++ b/emulator/udp.c @@ -27,97 +27,101 @@ #define TREZOR_UDP_PORT 21324 struct usb_socket { - int fd; - struct sockaddr_in from; - socklen_t fromlen; + int fd; + struct sockaddr_in from; + socklen_t fromlen; }; static struct usb_socket usb_main; static struct usb_socket usb_debug; static int socket_setup(int port) { - int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) { - perror("Failed to create socket"); - exit(1); - } + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + perror("Failed to create socket"); + exit(1); + } - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { - perror("Failed to bind socket"); - exit(1); - } + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { + perror("Failed to bind socket"); + exit(1); + } - return fd; + return fd; } -static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t size) { - if (sock->fromlen > 0) { - ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &sock->from, sock->fromlen); - if (n < 0 || ((size_t) n) != size) { - perror("Failed to write socket"); - return 0; - } - } +static size_t socket_write(struct usb_socket *sock, const void *buffer, + size_t size) { + if (sock->fromlen > 0) { + ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, + (const struct sockaddr *)&sock->from, sock->fromlen); + if (n < 0 || ((size_t)n) != size) { + perror("Failed to write socket"); + return 0; + } + } - return size; + return size; } static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) { - sock->fromlen = sizeof(sock->from); - ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &sock->from, &sock->fromlen); + sock->fromlen = sizeof(sock->from); + ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, + (struct sockaddr *)&sock->from, &sock->fromlen); - if (n < 0) { - if (errno != EAGAIN && errno != EWOULDBLOCK) { - perror("Failed to read socket"); - } - return 0; - } + if (n < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("Failed to read socket"); + } + return 0; + } - static const char msg_ping[] = { 'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G' }; - static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; + static const char msg_ping[] = {'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G'}; + static const char msg_pong[] = {'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G'}; - if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { - socket_write(sock, msg_pong, sizeof(msg_pong)); - return 0; - } + if (n == sizeof(msg_ping) && + memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { + socket_write(sock, msg_pong, sizeof(msg_pong)); + return 0; + } - return n; + return n; } void emulatorSocketInit(void) { - usb_main.fd = socket_setup(TREZOR_UDP_PORT); - usb_main.fromlen = 0; - usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); - usb_debug.fromlen = 0; + usb_main.fd = socket_setup(TREZOR_UDP_PORT); + usb_main.fromlen = 0; + usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); + usb_debug.fromlen = 0; } size_t emulatorSocketRead(int *iface, void *buffer, size_t size) { - size_t n = socket_read(&usb_main, buffer, size); - if (n > 0) { - *iface = 0; - return n; - } + size_t n = socket_read(&usb_main, buffer, size); + if (n > 0) { + *iface = 0; + return n; + } - n = socket_read(&usb_debug, buffer, size); - if (n > 0) { - *iface = 1; - return n; - } + n = socket_read(&usb_debug, buffer, size); + if (n > 0) { + *iface = 1; + return n; + } - return 0; + return 0; } size_t emulatorSocketWrite(int iface, const void *buffer, size_t size) { - if (iface == 0) { - return socket_write(&usb_main, buffer, size); - } - if (iface == 1) { - return socket_write(&usb_debug, buffer, size); - } - return 0; + if (iface == 0) { + return socket_write(&usb_main, buffer, size); + } + if (iface == 1) { + return socket_write(&usb_debug, buffer, size); + } + return 0; } diff --git a/firmware/bl_check.c b/firmware/bl_check.c index 45238a5def..68728902f9 100644 --- a/firmware/bl_check.c +++ b/firmware/bl_check.c @@ -17,91 +17,176 @@ * along with this library. If not, see . */ +#include #include #include -#include #include "bl_data.h" -#include "memory.h" -#include "layout.h" #include "gettext.h" +#include "layout.h" +#include "memory.h" #include "util.h" static int known_bootloader(int r, const uint8_t *hash) { - if (r != 32) return 0; - if (0 == memcmp(hash, "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98", 32)) return 1; // 1.2.0a - if (0 == memcmp(hash, "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e", 32)) return 1; // 1.2.0b - if (0 == memcmp(hash, "\xc4\xc3\x25\x39\xb4\xa0\x25\xa8\xe7\x53\xa4\xc4\x62\x64\x28\x59\x11\xa4\x5f\xcb\x14\xf4\x71\x81\x79\xe7\x11\xb1\xce\x99\x05\x24", 32)) return 1; // 1.2.5 - if (0 == memcmp(hash, "\x42\x59\x66\x94\xa0\xf2\x9d\x1e\xc2\x35\x71\x29\x2d\x54\x39\xd8\x2f\xa1\x8c\x07\x37\xcb\x10\x7e\x98\xf6\x1e\xf5\x93\x4d\xe7\x16", 32)) return 1; // 1.3.0a - if (0 == memcmp(hash, "\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37", 32)) return 1; // 1.3.0b - if (0 == memcmp(hash, "\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15", 32)) return 1; // 1.3.1 - if (0 == memcmp(hash, "\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07", 32)) return 1; // 1.3.2 - // note to those verifying these values: bootloader versions above this comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions below are padded with 0x00. - // for more info, refer to "make -C bootloader align" and "firmware/bl_data.py". - if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 - if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 shipped with fw 1.6.1 - if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 shipped with fw 1.6.2 - if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 shipped with fw 1.6.3 - if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 - if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 - if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 - if (0 == memcmp(hash, "\xf7\xfa\x16\x5b\xe6\xd7\x80\xf3\xe1\xaf\x00\xab\xc0\x7d\xf8\xb3\x07\x6b\xcd\xad\x72\xd7\x0d\xa2\x2a\x63\xd8\x89\x6b\x63\x91\xd8", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 - return 0; + if (r != 32) return 0; + if (0 == + memcmp(hash, + "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa" + "\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98", + 32)) + return 1; // 1.2.0a + if (0 == + memcmp(hash, + "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05" + "\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e", + 32)) + return 1; // 1.2.0b + if (0 == + memcmp(hash, + "\xc4\xc3\x25\x39\xb4\xa0\x25\xa8\xe7\x53\xa4\xc4\x62\x64\x28\x59" + "\x11\xa4\x5f\xcb\x14\xf4\x71\x81\x79\xe7\x11\xb1\xce\x99\x05\x24", + 32)) + return 1; // 1.2.5 + if (0 == + memcmp(hash, + "\x42\x59\x66\x94\xa0\xf2\x9d\x1e\xc2\x35\x71\x29\x2d\x54\x39\xd8" + "\x2f\xa1\x8c\x07\x37\xcb\x10\x7e\x98\xf6\x1e\xf5\x93\x4d\xe7\x16", + 32)) + return 1; // 1.3.0a + if (0 == + memcmp(hash, + "\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e" + "\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37", + 32)) + return 1; // 1.3.0b + if (0 == + memcmp(hash, + "\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e" + "\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15", + 32)) + return 1; // 1.3.1 + if (0 == + memcmp(hash, + "\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39" + "\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07", + 32)) + return 1; // 1.3.2 + // note to those verifying these values: bootloader versions above this + // comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions + // below are padded with 0x00. + // for more info, refer to "make -C + // bootloader align" and + // "firmware/bl_data.py". + if (0 == + memcmp(hash, + "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d" + "\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", + 32)) + return 1; // 1.3.3 + if (0 == + memcmp(hash, + "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a" + "\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", + 32)) + return 1; // 1.4.0 shipped with fw 1.6.1 + if (0 == + memcmp(hash, + "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7" + "\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", + 32)) + return 1; // 1.5.0 shipped with fw 1.6.2 + if (0 == + memcmp(hash, + "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54" + "\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", + 32)) + return 1; // 1.5.1 shipped with fw 1.6.3 + if (0 == + memcmp(hash, + "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17" + "\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", + 32)) + return 1; // 1.6.0 shipped with fw 1.7.0 + if (0 == + memcmp(hash, + "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f" + "\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", + 32)) + return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 + if (0 == + memcmp(hash, + "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3" + "\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", + 32)) + return 1; // 1.6.1 shipped with fw 1.7.3 + if (0 == + memcmp(hash, + "\xf7\xfa\x16\x5b\xe6\xd7\x80\xf3\xe1\xaf\x00\xab\xc0\x7d\xf8\xb3" + "\x07\x6b\xcd\xad\x72\xd7\x0d\xa2\x2a\x63\xd8\x89\x6b\x63\x91\xd8", + 32)) + return 1; // 1.8.0 shipped with fw 1.8.0 + return 0; } -void check_bootloader(void) -{ +void check_bootloader(void) { #if MEMORY_PROTECT - uint8_t hash[32]; - int r = memory_bootloader_hash(hash); + uint8_t hash[32]; + int r = memory_bootloader_hash(hash); - if (!known_bootloader(r, hash)) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Unknown bootloader"), _("detected."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); - shutdown(); - } + if (!known_bootloader(r, hash)) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Unknown bootloader"), + _("detected."), NULL, _("Unplug your TREZOR"), + _("contact our support."), NULL); + shutdown(); + } - if (is_mode_unprivileged()) { - return; - } + if (is_mode_unprivileged()) { + return; + } - if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { - // all OK -> done - return; - } + if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { + // all OK -> done + return; + } - // ENABLE THIS AT YOUR OWN RISK - // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK - // YOUR DEVICE. + // ENABLE THIS AT YOUR OWN RISK + // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK + // YOUR DEVICE. - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, _("Updating bootloader"), NULL, NULL, _("DO NOT UNPLUG"), _("YOUR TREZOR!"), NULL); + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, _("Updating bootloader"), + NULL, NULL, _("DO NOT UNPLUG"), _("YOUR TREZOR!"), NULL); - // unlock sectors - memory_write_unlock(); + // unlock sectors + memory_write_unlock(); - for (int tries = 0; tries < 10; tries++) { - // replace bootloader - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - for (int i = 0; i < FLASH_BOOT_LEN / 4; i++) { - const uint32_t *w = (const uint32_t *)(bl_data + i * 4); - flash_program_word(FLASH_BOOT_START + i * 4, *w); - } - flash_wait_for_last_operation(); - flash_lock(); - // check whether the write was OK - r = memory_bootloader_hash(hash); - if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { - // OK -> show info and halt - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); - shutdown(); - return; - } - } - // show info and halt - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Bootloader update"), _("broken."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); - shutdown(); + for (int tries = 0; tries < 10; tries++) { + // replace bootloader + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_BOOT_SECTOR_FIRST; i <= FLASH_BOOT_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + for (int i = 0; i < FLASH_BOOT_LEN / 4; i++) { + const uint32_t *w = (const uint32_t *)(bl_data + i * 4); + flash_program_word(FLASH_BOOT_START + i * 4, *w); + } + flash_wait_for_last_operation(); + flash_lock(); + // check whether the write was OK + r = memory_bootloader_hash(hash); + if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { + // OK -> show info and halt + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), + _("successfully."), NULL, _("Please reconnect"), + _("the device."), NULL); + shutdown(); + return; + } + } + // show info and halt + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Bootloader update"), + _("broken."), NULL, _("Unplug your TREZOR"), + _("contact our support."), NULL); + shutdown(); #endif } diff --git a/firmware/coins.c b/firmware/coins.c index a53155fbdc..55ae243884 100644 --- a/firmware/coins.c +++ b/firmware/coins.c @@ -17,64 +17,64 @@ * along with this library. If not, see . */ -#include #include "coins.h" +#include #include "address.h" -#include "ecdsa.h" #include "base58.h" +#include "ecdsa.h" -const CoinInfo *coinByName(const char *name) -{ - if (!name) return 0; - for (int i = 0; i < COINS_COUNT; i++) { - if (strcmp(name, coins[i].coin_name) == 0) { - return &(coins[i]); - } - } - return 0; +const CoinInfo *coinByName(const char *name) { + if (!name) return 0; + for (int i = 0; i < COINS_COUNT; i++) { + if (strcmp(name, coins[i].coin_name) == 0) { + return &(coins[i]); + } + } + return 0; } -const CoinInfo *coinByAddressType(uint32_t address_type) -{ - for (int i = 0; i < COINS_COUNT; i++) { - if (address_type == coins[i].address_type) { - return &(coins[i]); - } - } - return 0; +const CoinInfo *coinByAddressType(uint32_t address_type) { + for (int i = 0; i < COINS_COUNT; i++) { + if (address_type == coins[i].address_type) { + return &(coins[i]); + } + } + return 0; } -const CoinInfo *coinBySlip44(uint32_t coin_type) -{ - for (int i = 0; i < COINS_COUNT; i++) { - if (coin_type == coins[i].coin_type) { - return &(coins[i]); - } - } - return 0; +const CoinInfo *coinBySlip44(uint32_t coin_type) { + for (int i = 0; i < COINS_COUNT; i++) { + if (coin_type == coins[i].coin_type) { + return &(coins[i]); + } + } + return 0; } -bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type) -{ - if (!addr) return false; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - if (len >= 21) { - return coinExtractAddressTypeRaw(coin, addr_raw, address_type); - } - return false; +bool coinExtractAddressType(const CoinInfo *coin, const char *addr, + uint32_t *address_type) { + if (!addr) return false; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw, + MAX_ADDR_RAW_SIZE); + if (len >= 21) { + return coinExtractAddressTypeRaw(coin, addr_raw, address_type); + } + return false; } -bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type) -{ - if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { - *address_type = coin->address_type; - return true; - } - if (coin->has_address_type_p2sh && address_check_prefix(addr_raw, coin->address_type_p2sh)) { - *address_type = coin->address_type_p2sh; - return true; - } - *address_type = 0; - return false; +bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, + uint32_t *address_type) { + if (coin->has_address_type && + address_check_prefix(addr_raw, coin->address_type)) { + *address_type = coin->address_type; + return true; + } + if (coin->has_address_type_p2sh && + address_check_prefix(addr_raw, coin->address_type_p2sh)) { + *address_type = coin->address_type_p2sh; + return true; + } + *address_type = 0; + return false; } diff --git a/firmware/coins.h b/firmware/coins.h index 96ed77a05c..166cc47fc7 100644 --- a/firmware/coins.h +++ b/firmware/coins.h @@ -20,35 +20,35 @@ #ifndef __COINS_H__ #define __COINS_H__ -#include #include +#include #include "bip32.h" #include "hasher.h" typedef struct _CoinInfo { - const char *coin_name; - const char *coin_shortcut; - uint64_t maxfee_kb; - const char *signed_message_header; - bool has_address_type; - bool has_address_type_p2sh; - bool has_segwit; - bool has_fork_id; - bool force_bip143; - bool decred; - // address types > 0xFF represent a two-byte prefix in big-endian order - uint32_t address_type; - uint32_t address_type_p2sh; - uint32_t xpub_magic; - uint32_t xpub_magic_segwit_p2sh; - uint32_t xpub_magic_segwit_native; - uint32_t fork_id; - const char *bech32_prefix; - const char *cashaddr_prefix; - uint32_t coin_type; - const char *curve_name; - const curve_info *curve; + const char *coin_name; + const char *coin_shortcut; + uint64_t maxfee_kb; + const char *signed_message_header; + bool has_address_type; + bool has_address_type_p2sh; + bool has_segwit; + bool has_fork_id; + bool force_bip143; + bool decred; + // address types > 0xFF represent a two-byte prefix in big-endian order + uint32_t address_type; + uint32_t address_type_p2sh; + uint32_t xpub_magic; + uint32_t xpub_magic_segwit_p2sh; + uint32_t xpub_magic_segwit_native; + uint32_t fork_id; + const char *bech32_prefix; + const char *cashaddr_prefix; + uint32_t coin_type; + const char *curve_name; + const curve_info *curve; } CoinInfo; #include "coin_info.h" @@ -56,7 +56,9 @@ typedef struct _CoinInfo { const CoinInfo *coinByName(const char *name); const CoinInfo *coinByAddressType(uint32_t address_type); const CoinInfo *coinBySlip44(uint32_t coin_type); -bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); -bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); +bool coinExtractAddressType(const CoinInfo *coin, const char *addr, + uint32_t *address_type); +bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, + uint32_t *address_type); #endif diff --git a/firmware/config.c b/firmware/config.c index 22293cdb98..16cac6e3c0 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -17,66 +17,67 @@ * along with this library. If not, see . */ -#include -#include #include +#include +#include #include "messages.pb.h" -#include "common.h" -#include "trezor.h" -#include "sha2.h" #include "aes/aes.h" -#include "pbkdf2.h" -#include "hmac.h" #include "bip32.h" #include "bip39.h" -#include "curves.h" -#include "util.h" -#include "memory.h" -#include "rng.h" +#include "common.h" #include "config.h" +#include "curves.h" #include "debug.h" -#include "protect.h" -#include "layout2.h" -#include "usb.h" #include "gettext.h" -#include "u2f.h" +#include "hmac.h" +#include "layout2.h" +#include "memory.h" #include "memzero.h" -#include "supervise.h" +#include "pbkdf2.h" +#include "protect.h" +#include "rng.h" +#include "sha2.h" #include "storage.h" +#include "supervise.h" +#include "trezor.h" +#include "u2f.h" +#include "usb.h" +#include "util.h" -/* Magic constants to check validity of storage block for storage versions 1 to 10. */ -static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t +/* Magic constants to check validity of storage block for storage versions 1 + * to 10. */ +static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t #if !EMULATOR -static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' as uint32_t +static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' as uint32_t #else -static const uint32_t META_MAGIC_V10 = 0xFFFFFFFF; +static const uint32_t META_MAGIC_V10 = 0xFFFFFFFF; #endif -#define APP 0x0100 +#define APP 0x0100 #define FLAG_PUBLIC 0x8000 #define FLAGS_WRITE 0xC000 -#define KEY_UUID ( 0 | APP | FLAG_PUBLIC) // bytes(12) -#define KEY_VERSION ( 1 | APP) // uint32 -#define KEY_MNEMONIC ( 2 | APP) // string(241) -#define KEY_LANGUAGE ( 3 | APP | FLAG_PUBLIC) // string(17) -#define KEY_LABEL ( 4 | APP | FLAG_PUBLIC) // string(33) -#define KEY_PASSPHRASE_PROTECTION ( 5 | APP | FLAG_PUBLIC) // bool -#define KEY_HOMESCREEN ( 6 | APP | FLAG_PUBLIC) // bytes(1024) -#define KEY_NEEDS_BACKUP ( 7 | APP) // bool -#define KEY_FLAGS ( 8 | APP) // uint32 -#define KEY_U2F_COUNTER ( 9 | APP | FLAGS_WRITE) // uint32 -#define KEY_UNFINISHED_BACKUP ( 11 | APP) // bool -#define KEY_AUTO_LOCK_DELAY_MS ( 12 | APP) // uint32 -#define KEY_NO_BACKUP ( 13 | APP) // bool -#define KEY_INITIALIZED ( 14 | APP | FLAG_PUBLIC) // uint32 -#define KEY_NODE ( 15 | APP) // node -#define KEY_IMPORTED ( 16 | APP) // bool -#define KEY_U2F_ROOT ( 17 | APP | FLAG_PUBLIC) // node -#define KEY_DEBUG_LINK_PIN (255 | APP | FLAG_PUBLIC) // string(10) +#define KEY_UUID (0 | APP | FLAG_PUBLIC) // bytes(12) +#define KEY_VERSION (1 | APP) // uint32 +#define KEY_MNEMONIC (2 | APP) // string(241) +#define KEY_LANGUAGE (3 | APP | FLAG_PUBLIC) // string(17) +#define KEY_LABEL (4 | APP | FLAG_PUBLIC) // string(33) +#define KEY_PASSPHRASE_PROTECTION (5 | APP | FLAG_PUBLIC) // bool +#define KEY_HOMESCREEN (6 | APP | FLAG_PUBLIC) // bytes(1024) +#define KEY_NEEDS_BACKUP (7 | APP) // bool +#define KEY_FLAGS (8 | APP) // uint32 +#define KEY_U2F_COUNTER (9 | APP | FLAGS_WRITE) // uint32 +#define KEY_UNFINISHED_BACKUP (11 | APP) // bool +#define KEY_AUTO_LOCK_DELAY_MS (12 | APP) // uint32 +#define KEY_NO_BACKUP (13 | APP) // bool +#define KEY_INITIALIZED (14 | APP | FLAG_PUBLIC) // uint32 +#define KEY_NODE (15 | APP) // node +#define KEY_IMPORTED (16 | APP) // bool +#define KEY_U2F_ROOT (17 | APP | FLAG_PUBLIC) // node +#define KEY_DEBUG_LINK_PIN (255 | APP | FLAG_PUBLIC) // string(10) // The PIN value corresponding to an empty PIN. static const uint32_t PIN_EMPTY = 1; @@ -84,7 +85,7 @@ static const uint32_t PIN_EMPTY = 1; static uint32_t config_uuid[UUID_SIZE / sizeof(uint32_t)]; _Static_assert(sizeof(config_uuid) == UUID_SIZE, "config_uuid has wrong size"); -char config_uuid_str[2*UUID_SIZE + 1]; +char config_uuid_str[2 * UUID_SIZE + 1]; /* Old storage layout: @@ -103,7 +104,7 @@ The area for pin failures looks like this: 0 ... 0 pinfail 0xffffffff .. 0xffffffff The pinfail is a binary number of the form 1...10...0, the number of zeros is the number of pin failures. -This layout is used because we can only clear bits without +This layout is used because we can only clear bits without erasing the flash. The area for u2f counter updates is just a sequence of zero-bits @@ -123,7 +124,7 @@ static uint8_t CONFIDENTIAL sessionSeed[64]; static secbool sessionPassphraseCached = secfalse; static char CONFIDENTIAL sessionPassphrase[51]; -#define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes +#define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes static secbool autoLockDelayMsCached = secfalse; static uint32_t autoLockDelayMs = autoLockDelayMsDefault; @@ -132,818 +133,805 @@ static const uint32_t CONFIG_VERSION = 11; static const uint8_t FALSE_BYTE = '\x00'; static const uint8_t TRUE_BYTE = '\x01'; -static uint32_t pin_to_int(const char *pin) -{ - uint32_t val = 1; - size_t i = 0; - for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) { - if (pin[i] < '0' || pin[i] > '9') { - return 0; - } - val = 10*val + pin[i] - '0'; +static uint32_t pin_to_int(const char *pin) { + uint32_t val = 1; + size_t i = 0; + for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) { + if (pin[i] < '0' || pin[i] > '9') { + return 0; } + val = 10 * val + pin[i] - '0'; + } - if (pin[i] != '\0') { - return 0; - } + if (pin[i] != '\0') { + return 0; + } - return val; + return val; } -static secbool config_set_bool(uint16_t key, bool value) -{ - if (value) { - return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE)); - } else { - return storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE)); - } +static secbool config_set_bool(uint16_t key, bool value) { + if (value) { + return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE)); + } else { + return storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE)); + } } -static secbool config_get_bool(uint16_t key, bool *value) -{ - uint8_t val = 0; - uint16_t len = 0; - if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { - *value = (val == TRUE_BYTE); - return sectrue; - } else { - *value = false; - return secfalse; - } -} - -static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size, uint16_t *real_size) -{ - if (dest_size == 0) { - return secfalse; - } - - if (sectrue != storage_get(key, dest, dest_size, real_size)) { - return secfalse; - } +static secbool config_get_bool(uint16_t key, bool *value) { + uint8_t val = 0; + uint16_t len = 0; + if (sectrue == storage_get(key, &val, sizeof(val), &len) && + len == sizeof(TRUE_BYTE)) { + *value = (val == TRUE_BYTE); return sectrue; + } else { + *value = false; + return secfalse; + } } -static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) -{ - if (dest_size == 0) { - return secfalse; - } +static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size, + uint16_t *real_size) { + if (dest_size == 0) { + return secfalse; + } - uint16_t len = 0; - if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { - dest[0] = '\0'; - return secfalse; - } - dest[len] = '\0'; - return sectrue; + if (sectrue != storage_get(key, dest, dest_size, real_size)) { + return secfalse; + } + return sectrue; } -static secbool config_get_uint32(uint16_t key, uint32_t *value) -{ - uint16_t len = 0; - if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { - *value = 0; - return secfalse; - } - return sectrue; +static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { + if (dest_size == 0) { + return secfalse; + } + + uint16_t len = 0; + if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { + dest[0] = '\0'; + return secfalse; + } + dest[len] = '\0'; + return sectrue; } -#define FLASH_META_START 0x08008000 -#define FLASH_META_LEN 0x100 +static secbool config_get_uint32(uint16_t key, uint32_t *value) { + uint16_t len = 0; + if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || + len != sizeof(uint32_t)) { + *value = 0; + return secfalse; + } + return sectrue; +} -static secbool config_upgrade_v10(void) -{ -#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) +#define FLASH_META_START 0x08008000 +#define FLASH_META_LEN 0x100 - if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || - memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { - // wrong magic - return secfalse; +static secbool config_upgrade_v10(void) { +#define OLD_STORAGE_SIZE(last_member) \ + (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + \ + 3) & \ + ~3) + + if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10, + sizeof(META_MAGIC_V10)) != 0 || + memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, + sizeof(CONFIG_MAGIC_V10)) != 0) { + // wrong magic + return secfalse; + } + + Storage config __attribute__((aligned(4))); + _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); + + memcpy( + config_uuid, + FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)), + sizeof(config_uuid)); + memcpy(&config, + FLASH_PTR(FLASH_META_START + FLASH_META_LEN + + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), + sizeof(config)); + + // version 1: since 1.0.0 + // version 2: since 1.2.1 + // version 3: since 1.3.1 + // version 4: since 1.3.2 + // version 5: since 1.3.3 + // version 6: since 1.3.6 + // version 7: since 1.5.1 + // version 8: since 1.5.2 + // version 9: since 1.6.1 + // version 10: since 1.7.2 + if (config.version > CONFIG_VERSION) { + // downgrade -> clear storage + config_wipe(); + return secfalse; + } + + size_t old_config_size = 0; + if (config.version == 0) { + } else if (config.version <= 2) { + old_config_size = OLD_STORAGE_SIZE(imported); + } else if (config.version <= 5) { + // added homescreen + old_config_size = OLD_STORAGE_SIZE(homescreen); + } else if (config.version <= 7) { + // added u2fcounter + old_config_size = OLD_STORAGE_SIZE(u2f_counter); + } else if (config.version <= 8) { + // added flags and needsBackup + old_config_size = OLD_STORAGE_SIZE(flags); + } else if (config.version <= 9) { + // added u2froot, unfinished_backup and auto_lock_delay_ms + old_config_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); + } else if (config.version <= 10) { + // added no_backup + old_config_size = OLD_STORAGE_SIZE(no_backup); + } + + // Erase newly added fields. + if (old_config_size != sizeof(Storage)) { + memzero((char *)&config + old_config_size, + sizeof(Storage) - old_config_size); + } + + const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; + uint32_t pin_wait = 0; + if (config.version <= 5) { + // Get PIN failure counter from version 5 format. + uint32_t pinctr = + config.has_pin_failed_attempts ? config.pin_failed_attempts : 0; + if (pinctr > 31) { + pinctr = 31; } - Storage config __attribute__((aligned(4))); - _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); - - memcpy(config_uuid, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); - memcpy(&config, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); - - // version 1: since 1.0.0 - // version 2: since 1.2.1 - // version 3: since 1.3.1 - // version 4: since 1.3.2 - // version 5: since 1.3.3 - // version 6: since 1.3.6 - // version 7: since 1.5.1 - // version 8: since 1.5.2 - // version 9: since 1.6.1 - // version 10: since 1.7.2 - if (config.version > CONFIG_VERSION) { - // downgrade -> clear storage - config_wipe(); - return secfalse; + pin_wait = (1 << pinctr) - 1; + } else { + // Get PIN failure counter from version 10 format. + uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; + while (*(const uint32_t *)FLASH_PTR(flash_pinfails) == 0) { + flash_pinfails += sizeof(uint32_t); } + pin_wait = ~*(const uint32_t *)FLASH_PTR(flash_pinfails); + } - size_t old_config_size = 0; - if (config.version == 0) { - } else if (config.version <= 2) { - old_config_size = OLD_STORAGE_SIZE(imported); - } else if (config.version <= 5) { - // added homescreen - old_config_size = OLD_STORAGE_SIZE(homescreen); - } else if (config.version <= 7) { - // added u2fcounter - old_config_size = OLD_STORAGE_SIZE(u2f_counter); - } else if (config.version <= 8) { - // added flags and needsBackup - old_config_size = OLD_STORAGE_SIZE(flags); - } else if (config.version <= 9) { - // added u2froot, unfinished_backup and auto_lock_delay_ms - old_config_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); - } else if (config.version <= 10) { - // added no_backup - old_config_size = OLD_STORAGE_SIZE(no_backup); + uint32_t u2f_offset = 0; + if (config.has_u2f_counter) { + const uint32_t FLASH_STORAGE_U2FAREA = FLASH_STORAGE_PINAREA + 0x1000; + const uint32_t *u2fptr = (const uint32_t *)FLASH_PTR(FLASH_STORAGE_U2FAREA); + while (*u2fptr == 0) { + u2fptr++; } - - // Erase newly added fields. - if (old_config_size != sizeof(Storage)) { - memzero((char*)&config + old_config_size, sizeof(Storage) - old_config_size); + u2f_offset = + 32 * (u2fptr - (const uint32_t *)FLASH_PTR(FLASH_STORAGE_U2FAREA)); + uint32_t u2fword = *u2fptr; + while ((u2fword & 1) == 0) { + u2f_offset++; + u2fword >>= 1; } + } - const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; - uint32_t pin_wait = 0; - if (config.version <= 5) { - // Get PIN failure counter from version 5 format. - uint32_t pinctr = config.has_pin_failed_attempts ? config.pin_failed_attempts : 0; - if (pinctr > 31) { - pinctr = 31; - } + storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + storage_unlock(PIN_EMPTY); + if (config.has_pin) { + storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); + } - pin_wait = (1 << pinctr) - 1; - } else { - // Get PIN failure counter from version 10 format. - uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; - while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) { - flash_pinfails += sizeof(uint32_t); - } - pin_wait = ~*(const uint32_t*)FLASH_PTR(flash_pinfails); + while (pin_wait != 0) { + storage_pin_fails_increase(); + pin_wait >>= 1; + } + + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + if (config.has_node) { + if (sectrue == storage_set(KEY_NODE, &config.node, sizeof(config.node))) { + config_set_bool(KEY_INITIALIZED, true); } + } + if (config.has_mnemonic) { + config_setMnemonic(config.mnemonic); + } + if (config.has_passphrase_protection) { + config_setPassphraseProtection(config.passphrase_protection); + } + if (config.has_language) { + config_setLanguage(config.language); + } + if (config.has_label) { + config_setLabel(config.label); + } + if (config.has_imported) { + config_setImported(config.imported); + } + if (config.has_homescreen) { + config_setHomescreen(config.homescreen.bytes, config.homescreen.size); + } + if (config.has_u2f_counter) { + config_setU2FCounter(config.u2f_counter + u2f_offset); + } + if (config.has_needs_backup) { + config_setNeedsBackup(config.needs_backup); + } + if (config.has_flags) { + config_applyFlags(config.flags); + } + if (config.has_unfinished_backup) { + config_setUnfinishedBackup(config.unfinished_backup); + } + if (config.has_auto_lock_delay_ms) { + config_setAutoLockDelayMs(config.auto_lock_delay_ms); + } + if (config.has_no_backup && config.no_backup) { + config_setNoBackup(); + } + memzero(&config, sizeof(config)); - uint32_t u2f_offset = 0; - if (config.has_u2f_counter) { - const uint32_t FLASH_STORAGE_U2FAREA = FLASH_STORAGE_PINAREA + 0x1000; - const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); - while (*u2fptr == 0) { - u2fptr++; - } - u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); - uint32_t u2fword = *u2fptr; - while ((u2fword & 1) == 0) { - u2f_offset++; - u2fword >>= 1; - } - } + session_clear(true); - storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + return sectrue; +} + +void config_init(void) { + char oldTiny = usbTiny(1); + + config_upgrade_v10(); + + storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); + + // Auto-unlock storage if no PIN is set. + if (storage_is_unlocked() == secfalse && storage_has_pin() == secfalse) { storage_unlock(PIN_EMPTY); - if (config.has_pin) { - storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); - } - - while (pin_wait != 0) { - storage_pin_fails_increase(); - pin_wait >>= 1; - } + } + uint16_t len = 0; + // If UUID is not set, then the config is uninitialized. + if (sectrue != + storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) || + len != sizeof(config_uuid)) { + random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); - if (config.has_node) { - if (sectrue == storage_set(KEY_NODE, &config.node, sizeof(config.node))) { - config_set_bool(KEY_INITIALIZED, true); - } - } - if (config.has_mnemonic) { - config_setMnemonic(config.mnemonic); - } - if (config.has_passphrase_protection) { - config_setPassphraseProtection(config.passphrase_protection); - } - if (config.has_language) { - config_setLanguage(config.language); - } - if (config.has_label) { - config_setLabel(config.label); - } - if (config.has_imported) { - config_setImported(config.imported); - } - if (config.has_homescreen) { - config_setHomescreen(config.homescreen.bytes, config.homescreen.size); - } - if (config.has_u2f_counter) { - config_setU2FCounter(config.u2f_counter + u2f_offset); - } - if (config.has_needs_backup) { - config_setNeedsBackup(config.needs_backup); - } - if (config.has_flags) { - config_applyFlags(config.flags); - } - if (config.has_unfinished_backup) { - config_setUnfinishedBackup(config.unfinished_backup); - } - if (config.has_auto_lock_delay_ms) { - config_setAutoLockDelayMs(config.auto_lock_delay_ms); - } - if (config.has_no_backup && config.no_backup) { - config_setNoBackup(); - } - memzero(&config, sizeof(config)); + } + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); - session_clear(true); - - return sectrue; + usbTiny(oldTiny); } -void config_init(void) -{ - char oldTiny = usbTiny(1); - - config_upgrade_v10(); - - storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); - memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); - - // Auto-unlock storage if no PIN is set. - if (storage_is_unlocked() == secfalse && storage_has_pin() == secfalse) { - storage_unlock(PIN_EMPTY); - } - - uint16_t len = 0; - // If UUID is not set, then the config is uninitialized. - if (sectrue != storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) || len != sizeof(config_uuid)) { - random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); - storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); - storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); - } - data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); - - usbTiny(oldTiny); +void session_clear(bool lock) { + sessionSeedCached = secfalse; + memzero(&sessionSeed, sizeof(sessionSeed)); + sessionPassphraseCached = secfalse; + memzero(&sessionPassphrase, sizeof(sessionPassphrase)); + if (lock) { + storage_lock(); + } } -void session_clear(bool lock) -{ - sessionSeedCached = secfalse; - memzero(&sessionSeed, sizeof(sessionSeed)); - sessionPassphraseCached = secfalse; - memzero(&sessionPassphrase, sizeof(sessionPassphrase)); - if (lock) { - storage_lock(); - } +static void get_u2froot_callback(uint32_t iter, uint32_t total) { + layoutProgress(_("Updating"), 1000 * iter / total); } -static void get_u2froot_callback(uint32_t iter, uint32_t total) -{ - layoutProgress(_("Updating"), 1000 * iter / total); -} - -static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { - static CONFIDENTIAL HDNode node; - char oldTiny = usbTiny(1); - mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 - usbTiny(oldTiny); - hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); - hdnode_private_ckd(&node, U2F_KEY_PATH); - u2froot->depth = node.depth; - u2froot->child_num = U2F_KEY_PATH; - u2froot->chain_code.size = sizeof(node.chain_code); - memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); - u2froot->has_private_key = true; - u2froot->private_key.size = sizeof(node.private_key); - memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - memzero(&node, sizeof(node)); - session_clear(false); // invalidate seed cache +static void config_compute_u2froot(const char *mnemonic, + StorageHDNode *u2froot) { + static CONFIDENTIAL HDNode node; + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, "", sessionSeed, + get_u2froot_callback); // BIP-0039 + usbTiny(oldTiny); + hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); + hdnode_private_ckd(&node, U2F_KEY_PATH); + u2froot->depth = node.depth; + u2froot->child_num = U2F_KEY_PATH; + u2froot->chain_code.size = sizeof(node.chain_code); + memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); + u2froot->has_private_key = true; + u2froot->private_key.size = sizeof(node.private_key); + memcpy(u2froot->private_key.bytes, node.private_key, + sizeof(node.private_key)); + memzero(&node, sizeof(node)); + session_clear(false); // invalidate seed cache } static void config_setNode(const HDNodeType *node) { - StorageHDNode storageHDNode; - memzero(&storageHDNode, sizeof(storageHDNode)); + StorageHDNode storageHDNode; + memzero(&storageHDNode, sizeof(storageHDNode)); - storageHDNode.depth = node->depth; - storageHDNode.fingerprint = node->fingerprint; - storageHDNode.child_num = node->child_num; - storageHDNode.chain_code.size = 32; - memcpy(storageHDNode.chain_code.bytes, node->chain_code.bytes, 32); + storageHDNode.depth = node->depth; + storageHDNode.fingerprint = node->fingerprint; + storageHDNode.child_num = node->child_num; + storageHDNode.chain_code.size = 32; + memcpy(storageHDNode.chain_code.bytes, node->chain_code.bytes, 32); - if (node->has_private_key) { - storageHDNode.has_private_key = true; - storageHDNode.private_key.size = 32; - memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); - } - if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { - config_set_bool(KEY_INITIALIZED, true); - } - memzero(&storageHDNode, sizeof(storageHDNode)); + if (node->has_private_key) { + storageHDNode.has_private_key = true; + storageHDNode.private_key.size = 32; + memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); + } + if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { + config_set_bool(KEY_INITIALIZED, true); + } + memzero(&storageHDNode, sizeof(storageHDNode)); } #if DEBUG_LINK -bool config_dumpNode(HDNodeType *node) -{ - memzero(node, sizeof(HDNodeType)); - - StorageHDNode storageNode; - uint16_t len = 0; - if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { - memzero(&storageNode, sizeof(storageNode)); - return false; - } - - node->depth = storageNode.depth; - node->fingerprint = storageNode.fingerprint; - node->child_num = storageNode.child_num; - - node->chain_code.size = 32; - memcpy(node->chain_code.bytes, storageNode.chain_code.bytes, 32); - - if (storageNode.has_private_key) { - node->has_private_key = true; - node->private_key.size = 32; - memcpy(node->private_key.bytes, storageNode.private_key.bytes, 32); - } +bool config_dumpNode(HDNodeType *node) { + memzero(node, sizeof(HDNodeType)); + StorageHDNode storageNode; + uint16_t len = 0; + if (sectrue != + storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || + len != sizeof(StorageHDNode)) { memzero(&storageNode, sizeof(storageNode)); - return true; + return false; + } + + node->depth = storageNode.depth; + node->fingerprint = storageNode.fingerprint; + node->child_num = storageNode.child_num; + + node->chain_code.size = 32; + memcpy(node->chain_code.bytes, storageNode.chain_code.bytes, 32); + + if (storageNode.has_private_key) { + node->has_private_key = true; + node->private_key.size = 32; + memcpy(node->private_key.bytes, storageNode.private_key.bytes, 32); + } + + memzero(&storageNode, sizeof(storageNode)); + return true; } #endif -void config_loadDevice(const LoadDevice *msg) -{ - session_clear(false); - config_set_bool(KEY_IMPORTED, true); - config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); +void config_loadDevice(const LoadDevice *msg) { + session_clear(false); + config_set_bool(KEY_IMPORTED, true); + config_setPassphraseProtection(msg->has_passphrase_protection && + msg->passphrase_protection); - if (msg->has_pin) { - config_changePin("", msg->pin); - } + if (msg->has_pin) { + config_changePin("", msg->pin); + } - if (msg->has_node) { - storage_delete(KEY_MNEMONIC); - config_setNode(&(msg->node)); - } else if (msg->has_mnemonic) { - storage_delete(KEY_NODE); - config_setMnemonic(msg->mnemonic); - } + if (msg->has_node) { + storage_delete(KEY_MNEMONIC); + config_setNode(&(msg->node)); + } else if (msg->has_mnemonic) { + storage_delete(KEY_NODE); + config_setMnemonic(msg->mnemonic); + } - if (msg->has_language) { - config_setLanguage(msg->language); - } + if (msg->has_language) { + config_setLanguage(msg->language); + } - config_setLabel(msg->has_label ? msg->label : ""); + config_setLabel(msg->has_label ? msg->label : ""); - if (msg->has_u2f_counter) { - config_setU2FCounter(msg->u2f_counter); - } + if (msg->has_u2f_counter) { + config_setU2FCounter(msg->u2f_counter); + } } -void config_setLabel(const char *label) -{ - if (label == NULL || label[0] == '\0') { - storage_delete(KEY_LABEL); - } else { - storage_set(KEY_LABEL, label, strnlen(label, MAX_LABEL_LEN)); +void config_setLabel(const char *label) { + if (label == NULL || label[0] == '\0') { + storage_delete(KEY_LABEL); + } else { + storage_set(KEY_LABEL, label, strnlen(label, MAX_LABEL_LEN)); + } +} + +void config_setLanguage(const char *lang) { + if (lang == NULL) { + return; + } + + // Sanity check. + if (strcmp(lang, "english") != 0) { + return; + } + storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN)); +} + +void config_setPassphraseProtection(bool passphrase_protection) { + sessionSeedCached = secfalse; + sessionPassphraseCached = secfalse; + config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); +} + +bool config_getPassphraseProtection(bool *passphrase_protection) { + return sectrue == + config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); +} + +void config_setHomescreen(const uint8_t *data, uint32_t size) { + if (data != NULL && size == HOMESCREEN_SIZE) { + storage_set(KEY_HOMESCREEN, data, size); + } else { + storage_delete(KEY_HOMESCREEN); + } +} + +static void get_root_node_callback(uint32_t iter, uint32_t total) { + usbSleep(1); + layoutProgress(_("Waking up"), 1000 * iter / total); +} + +const uint8_t *config_getSeed(bool usePassphrase) { + // root node is properly cached + if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) && + sectrue == sessionSeedCached) { + return sessionSeed; + } + + // if storage has mnemonic, convert it to node and use it + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + if (usePassphrase && !protectPassphrase()) { + memzero(mnemonic, sizeof(mnemonic)); + return NULL; } -} - -void config_setLanguage(const char *lang) -{ - if (lang == NULL) { - return; + // if storage was not imported (i.e. it was properly generated or recovered) + bool imported = false; + config_get_bool(KEY_IMPORTED, &imported); + if (!imported) { + // test whether mnemonic is a valid BIP-0039 mnemonic + if (!mnemonic_check(mnemonic)) { + // and if not then halt the device + error_shutdown(_("Storage failure"), _("detected."), NULL, NULL); + } } + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", + sessionSeed, get_root_node_callback); // BIP-0039 + memzero(mnemonic, sizeof(mnemonic)); + usbTiny(oldTiny); + sessionSeedCached = sectrue; + sessionSeedUsesPassphrase = usePassphrase ? sectrue : secfalse; + return sessionSeed; + } - // Sanity check. - if (strcmp(lang, "english") != 0) { - return; - } - storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN)); + return NULL; } -void config_setPassphraseProtection(bool passphrase_protection) -{ - sessionSeedCached = secfalse; - sessionPassphraseCached = secfalse; - config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); +static bool config_loadNode(const StorageHDNode *node, const char *curve, + HDNode *out) { + return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, + node->private_key.bytes, curve, out); } -bool config_getPassphraseProtection(bool *passphrase_protection) -{ - return sectrue == config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); -} - -void config_setHomescreen(const uint8_t *data, uint32_t size) -{ - if (data != NULL && size == HOMESCREEN_SIZE) { - storage_set(KEY_HOMESCREEN, data, size); - } else { - storage_delete(KEY_HOMESCREEN); - } -} - -static void get_root_node_callback(uint32_t iter, uint32_t total) -{ - usbSleep(1); - layoutProgress(_("Waking up"), 1000 * iter / total); -} - -const uint8_t *config_getSeed(bool usePassphrase) -{ - // root node is properly cached - if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) - && sectrue == sessionSeedCached) { - return sessionSeed; - } - - // if storage has mnemonic, convert it to node and use it - char mnemonic[MAX_MNEMONIC_LEN + 1]; - if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { - if (usePassphrase && !protectPassphrase()) { - memzero(mnemonic, sizeof(mnemonic)); - return NULL; - } - // if storage was not imported (i.e. it was properly generated or recovered) - bool imported = false; - config_get_bool(KEY_IMPORTED, &imported); - if (!imported) { - // test whether mnemonic is a valid BIP-0039 mnemonic - if (!mnemonic_check(mnemonic)) { - // and if not then halt the device - error_shutdown(_("Storage failure"), _("detected."), NULL, NULL); - } - } - char oldTiny = usbTiny(1); - mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 - memzero(mnemonic, sizeof(mnemonic)); - usbTiny(oldTiny); - sessionSeedCached = sectrue; - sessionSeedUsesPassphrase = usePassphrase ? sectrue : secfalse; - return sessionSeed; - } - - return NULL; -} - -static bool config_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { - return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); -} - -bool config_getU2FRoot(HDNode *node) -{ - StorageHDNode u2fNode; - uint16_t len = 0; - if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) || len != sizeof(StorageHDNode)) { - memzero(&u2fNode, sizeof(u2fNode)); - return false; - } - bool ret = config_loadNode(&u2fNode, NIST256P1_NAME, node); +bool config_getU2FRoot(HDNode *node) { + StorageHDNode u2fNode; + uint16_t len = 0; + if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) || + len != sizeof(StorageHDNode)) { memzero(&u2fNode, sizeof(u2fNode)); - return ret; + return false; + } + bool ret = config_loadNode(&u2fNode, NIST256P1_NAME, node); + memzero(&u2fNode, sizeof(u2fNode)); + return ret; } -bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) -{ - // if storage has node, decrypt and use it - StorageHDNode storageHDNode; - uint16_t len = 0; - if (strcmp(curve, SECP256K1_NAME) == 0 && sectrue == storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) && len == sizeof(StorageHDNode)) { - if (!protectPassphrase()) { - memzero(&storageHDNode, sizeof(storageHDNode)); - return false; - } - if (!config_loadNode(&storageHDNode, curve, node)) { - memzero(&storageHDNode, sizeof(storageHDNode)); - return false; - } - bool passphrase_protection = false; - config_getPassphraseProtection(&passphrase_protection); - if (passphrase_protection && sectrue == sessionPassphraseCached && sessionPassphrase[0] != '\0') { - // decrypt hd node - uint8_t secret[64]; - PBKDF2_HMAC_SHA512_CTX pctx; - char oldTiny = usbTiny(1); - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); - get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); - for (int i = 0; i < 8; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); - get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); - } - pbkdf2_hmac_sha512_Final(&pctx, secret); - usbTiny(oldTiny); - aes_decrypt_ctx ctx; - aes_decrypt_key256(secret, &ctx); - aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); - aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); - } - return true; +bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) { + // if storage has node, decrypt and use it + StorageHDNode storageHDNode; + uint16_t len = 0; + if (strcmp(curve, SECP256K1_NAME) == 0 && + sectrue == + storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) && + len == sizeof(StorageHDNode)) { + if (!protectPassphrase()) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; } - memzero(&storageHDNode, sizeof(storageHDNode)); - - const uint8_t *seed = config_getSeed(usePassphrase); - if (seed == NULL) { - return false; + if (!config_loadNode(&storageHDNode, curve, node)) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; } - - return hdnode_from_seed(seed, 64, curve, node); -} - -bool config_getLabel(char *dest, uint16_t dest_size) -{ - return sectrue == config_get_string(KEY_LABEL, dest, dest_size); -} - -bool config_getLanguage(char *dest, uint16_t dest_size) -{ - return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size); -} - -bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) -{ - uint16_t len = 0; - secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len); - if (sectrue != ret || len != HOMESCREEN_SIZE) { - return false; + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (passphrase_protection && sectrue == sessionPassphraseCached && + sessionPassphrase[0] != '\0') { + // decrypt hd node + uint8_t secret[64]; + PBKDF2_HMAC_SHA512_CTX pctx; + char oldTiny = usbTiny(1); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, + strlen(sessionPassphrase), + (const uint8_t *)"TREZORHD", 8, 1); + get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, + BIP39_PBKDF2_ROUNDS); + } + pbkdf2_hmac_sha512_Final(&pctx, secret); + usbTiny(oldTiny); + aes_decrypt_ctx ctx; + aes_decrypt_key256(secret, &ctx); + aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, + &ctx); + aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, + &ctx); } return true; + } + memzero(&storageHDNode, sizeof(storageHDNode)); + + const uint8_t *seed = config_getSeed(usePassphrase); + if (seed == NULL) { + return false; + } + + return hdnode_from_seed(seed, 64, curve, node); } -bool config_setMnemonic(const char *mnemonic) -{ - if (mnemonic == NULL) { - return false; - } - - if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { - return false; - } - - StorageHDNode u2fNode; - memzero(&u2fNode, sizeof(u2fNode)); - config_compute_u2froot(mnemonic, &u2fNode); - secbool ret = storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); - memzero(&u2fNode, sizeof(u2fNode)); - - if (sectrue != ret) { - storage_delete(KEY_MNEMONIC); - return false; - } - - config_set_bool(KEY_INITIALIZED, true); - - return true; +bool config_getLabel(char *dest, uint16_t dest_size) { + return sectrue == config_get_string(KEY_LABEL, dest, dest_size); } -bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size) -{ - return sectrue == config_get_bytes(KEY_MNEMONIC, dest, dest_size, real_size); +bool config_getLanguage(char *dest, uint16_t dest_size) { + return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size); } -bool config_getMnemonic(char *dest, uint16_t dest_size) -{ - return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); +bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) { + uint16_t len = 0; + secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len); + if (sectrue != ret || len != HOMESCREEN_SIZE) { + return false; + } + return true; +} + +bool config_setMnemonic(const char *mnemonic) { + if (mnemonic == NULL) { + return false; + } + + if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, + strnlen(mnemonic, MAX_MNEMONIC_LEN))) { + return false; + } + + StorageHDNode u2fNode; + memzero(&u2fNode, sizeof(u2fNode)); + config_compute_u2froot(mnemonic, &u2fNode); + secbool ret = storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); + memzero(&u2fNode, sizeof(u2fNode)); + + if (sectrue != ret) { + storage_delete(KEY_MNEMONIC); + return false; + } + + config_set_bool(KEY_INITIALIZED, true); + + return true; +} + +bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, + uint16_t *real_size) { + return sectrue == config_get_bytes(KEY_MNEMONIC, dest, dest_size, real_size); +} + +bool config_getMnemonic(char *dest, uint16_t dest_size) { + return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); } /* Check whether mnemonic matches storage. The mnemonic must be * a null-terminated string. */ -bool config_containsMnemonic(const char *mnemonic) -{ - uint16_t len = 0; - uint8_t stored_mnemonic[MAX_MNEMONIC_LEN]; - if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, sizeof(stored_mnemonic), &len)) { - return false; - } +bool config_containsMnemonic(const char *mnemonic) { + uint16_t len = 0; + uint8_t stored_mnemonic[MAX_MNEMONIC_LEN]; + if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, + sizeof(stored_mnemonic), &len)) { + return false; + } - // Compare the digests to mitigate side-channel attacks. - uint8_t digest_stored[SHA256_DIGEST_LENGTH]; - sha256_Raw(stored_mnemonic, len, digest_stored); - memzero(stored_mnemonic, sizeof(stored_mnemonic)); + // Compare the digests to mitigate side-channel attacks. + uint8_t digest_stored[SHA256_DIGEST_LENGTH]; + sha256_Raw(stored_mnemonic, len, digest_stored); + memzero(stored_mnemonic, sizeof(stored_mnemonic)); - uint8_t digest_input[SHA256_DIGEST_LENGTH]; - sha256_Raw((const uint8_t*)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), digest_input); + uint8_t digest_input[SHA256_DIGEST_LENGTH]; + sha256_Raw((const uint8_t *)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), + digest_input); - uint8_t diff = 0; - for (size_t i = 0; i < sizeof(digest_input); i++) { - diff |= (digest_stored[i] - digest_input[i]); - } - memzero(digest_stored, sizeof(digest_stored)); - memzero(digest_input, sizeof(digest_input)); - return diff == 0; + uint8_t diff = 0; + for (size_t i = 0; i < sizeof(digest_input); i++) { + diff |= (digest_stored[i] - digest_input[i]); + } + memzero(digest_stored, sizeof(digest_stored)); + memzero(digest_input, sizeof(digest_input)); + return diff == 0; } /* Check whether pin matches storage. The pin must be * a null-terminated string with at most 9 characters. */ -bool config_unlock(const char *pin) -{ - char oldTiny = usbTiny(1); - secbool ret = storage_unlock(pin_to_int(pin)); - usbTiny(oldTiny); - return sectrue == ret; +bool config_unlock(const char *pin) { + char oldTiny = usbTiny(1); + secbool ret = storage_unlock(pin_to_int(pin)); + usbTiny(oldTiny); + return sectrue == ret; } -bool config_hasPin(void) -{ - return sectrue == storage_has_pin(); -} +bool config_hasPin(void) { return sectrue == storage_has_pin(); } -bool config_changePin(const char *old_pin, const char *new_pin) -{ - uint32_t new_pin_int = pin_to_int(new_pin); - if (new_pin_int == 0) { - return false; - } +bool config_changePin(const char *old_pin, const char *new_pin) { + uint32_t new_pin_int = pin_to_int(new_pin); + if (new_pin_int == 0) { + return false; + } - char oldTiny = usbTiny(1); - secbool ret = storage_change_pin(pin_to_int(old_pin), new_pin_int); - usbTiny(oldTiny); + char oldTiny = usbTiny(1); + secbool ret = storage_change_pin(pin_to_int(old_pin), new_pin_int); + usbTiny(oldTiny); #if DEBUG_LINK - if (sectrue == ret) { - if (new_pin_int != PIN_EMPTY) { - storage_set(KEY_DEBUG_LINK_PIN, new_pin, strnlen(new_pin, MAX_PIN_LEN)); - } else { - storage_delete(KEY_DEBUG_LINK_PIN); - } + if (sectrue == ret) { + if (new_pin_int != PIN_EMPTY) { + storage_set(KEY_DEBUG_LINK_PIN, new_pin, strnlen(new_pin, MAX_PIN_LEN)); + } else { + storage_delete(KEY_DEBUG_LINK_PIN); } + } #endif - memzero(&new_pin_int, sizeof(new_pin_int)); + memzero(&new_pin_int, sizeof(new_pin_int)); - return sectrue == ret; + return sectrue == ret; } #if DEBUG_LINK -bool config_getPin(char *dest, uint16_t dest_size) -{ - return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size); +bool config_getPin(char *dest, uint16_t dest_size) { + return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size); } #endif -void session_cachePassphrase(const char *passphrase) -{ - strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); - sessionPassphraseCached = sectrue; +void session_cachePassphrase(const char *passphrase) { + strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); + sessionPassphraseCached = sectrue; } -bool session_isPassphraseCached(void) -{ - return sectrue == sessionPassphraseCached; +bool session_isPassphraseCached(void) { + return sectrue == sessionPassphraseCached; } -bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) -{ - if (!passphrase && sectrue != sessionPassphraseCached) { - return false; - } else { - passphrase = sessionPassphrase; - } - if (!salt) { - // if salt is not provided fill the first half of the state with random data - random_buffer(state, 32); - } else { - // if salt is provided fill the first half of the state with salt - memcpy(state, salt, 32); - } - // state[0:32] = salt - // state[32:64] = HMAC(passphrase, salt || device_id) - HMAC_SHA256_CTX ctx; - hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); - hmac_sha256_Update(&ctx, state, 32); - hmac_sha256_Update(&ctx, (const uint8_t *)config_uuid, sizeof(config_uuid)); - hmac_sha256_Final(&ctx, state + 32); +bool session_getState(const uint8_t *salt, uint8_t *state, + const char *passphrase) { + if (!passphrase && sectrue != sessionPassphraseCached) { + return false; + } else { + passphrase = sessionPassphrase; + } + if (!salt) { + // if salt is not provided fill the first half of the state with random data + random_buffer(state, 32); + } else { + // if salt is provided fill the first half of the state with salt + memcpy(state, salt, 32); + } + // state[0:32] = salt + // state[32:64] = HMAC(passphrase, salt || device_id) + HMAC_SHA256_CTX ctx; + hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); + hmac_sha256_Update(&ctx, state, 32); + hmac_sha256_Update(&ctx, (const uint8_t *)config_uuid, sizeof(config_uuid)); + hmac_sha256_Final(&ctx, state + 32); - memzero(&ctx, sizeof(ctx)); + memzero(&ctx, sizeof(ctx)); - return true; + return true; } -bool session_isUnlocked(void) -{ - return sectrue == storage_is_unlocked(); +bool session_isUnlocked(void) { return sectrue == storage_is_unlocked(); } + +bool config_isInitialized(void) { + bool initialized = false; + config_get_bool(KEY_INITIALIZED, &initialized); + return initialized; } -bool config_isInitialized(void) -{ - bool initialized = false; - config_get_bool(KEY_INITIALIZED, &initialized); - return initialized; +bool config_getImported(bool *imported) { + return sectrue == config_get_bool(KEY_IMPORTED, imported); } -bool config_getImported(bool* imported) -{ - return sectrue == config_get_bool(KEY_IMPORTED, imported); +void config_setImported(bool imported) { + config_set_bool(KEY_IMPORTED, imported); } -void config_setImported(bool imported) -{ - config_set_bool(KEY_IMPORTED, imported); +bool config_getNeedsBackup(bool *needs_backup) { + return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup); } -bool config_getNeedsBackup(bool *needs_backup) -{ - return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup); +void config_setNeedsBackup(bool needs_backup) { + config_set_bool(KEY_NEEDS_BACKUP, needs_backup); } -void config_setNeedsBackup(bool needs_backup) -{ - config_set_bool(KEY_NEEDS_BACKUP, needs_backup); +bool config_getUnfinishedBackup(bool *unfinished_backup) { + return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } -bool config_getUnfinishedBackup(bool *unfinished_backup) -{ - return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); +void config_setUnfinishedBackup(bool unfinished_backup) { + config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } -void config_setUnfinishedBackup(bool unfinished_backup) -{ - config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); +bool config_getNoBackup(bool *no_backup) { + return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup); } -bool config_getNoBackup(bool *no_backup) -{ - return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup); +void config_setNoBackup(void) { config_set_bool(KEY_NO_BACKUP, true); } + +void config_applyFlags(uint32_t flags) { + uint32_t old_flags = 0; + config_get_uint32(KEY_FLAGS, &old_flags); + flags |= old_flags; + if (flags == old_flags) { + return; // no new flags + } + storage_set(KEY_FLAGS, &flags, sizeof(flags)); } -void config_setNoBackup(void) -{ - config_set_bool(KEY_NO_BACKUP, true); +bool config_getFlags(uint32_t *flags) { + return sectrue == config_get_uint32(KEY_FLAGS, flags); } -void config_applyFlags(uint32_t flags) -{ - uint32_t old_flags = 0; - config_get_uint32(KEY_FLAGS, &old_flags); - flags |= old_flags; - if (flags == old_flags) { - return; // no new flags - } - storage_set(KEY_FLAGS, &flags, sizeof(flags)); +uint32_t config_nextU2FCounter(void) { + uint32_t u2fcounter = 0; + storage_next_counter(KEY_U2F_COUNTER, &u2fcounter); + return u2fcounter; } -bool config_getFlags(uint32_t *flags) -{ - return sectrue == config_get_uint32(KEY_FLAGS, flags); +void config_setU2FCounter(uint32_t u2fcounter) { + storage_set_counter(KEY_U2F_COUNTER, u2fcounter); } -uint32_t config_nextU2FCounter(void) -{ - uint32_t u2fcounter = 0; - storage_next_counter(KEY_U2F_COUNTER, &u2fcounter); - return u2fcounter; -} - -void config_setU2FCounter(uint32_t u2fcounter) -{ - storage_set_counter(KEY_U2F_COUNTER, u2fcounter); -} - -uint32_t config_getAutoLockDelayMs() -{ - if (sectrue == autoLockDelayMsCached) { - return autoLockDelayMs; - } - - if (sectrue != storage_is_unlocked()) { - return autoLockDelayMsDefault; - } - - if (sectrue != config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { - autoLockDelayMs = autoLockDelayMsDefault; - } - autoLockDelayMsCached = sectrue; +uint32_t config_getAutoLockDelayMs() { + if (sectrue == autoLockDelayMsCached) { return autoLockDelayMs; + } + + if (sectrue != storage_is_unlocked()) { + return autoLockDelayMsDefault; + } + + if (sectrue != config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { + autoLockDelayMs = autoLockDelayMsDefault; + } + autoLockDelayMsCached = sectrue; + return autoLockDelayMs; } -void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) -{ - const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds - auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); - if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms))) { - autoLockDelayMs = auto_lock_delay_ms; - autoLockDelayMsCached = sectrue; - } +void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { + const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds + auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); + if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, + sizeof(auto_lock_delay_ms))) { + autoLockDelayMs = auto_lock_delay_ms; + autoLockDelayMsCached = sectrue; + } } -void config_wipe(void) -{ - char oldTiny = usbTiny(1); - storage_wipe(); - if (storage_is_unlocked() != sectrue) { - storage_unlock(PIN_EMPTY); - } - usbTiny(oldTiny); - random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); - data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); - autoLockDelayMsCached = secfalse; - storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); - storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); - session_clear(false); +void config_wipe(void) { + char oldTiny = usbTiny(1); + storage_wipe(); + if (storage_is_unlocked() != sectrue) { + storage_unlock(PIN_EMPTY); + } + usbTiny(oldTiny); + random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + autoLockDelayMsCached = secfalse; + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + session_clear(false); } diff --git a/firmware/config.h b/firmware/config.h index 2f2c26da24..593cb90fe5 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -24,66 +24,66 @@ #include "messages-management.pb.h" #define STORAGE_FIELD(TYPE, NAME) \ - bool has_##NAME; \ - TYPE NAME; + bool has_##NAME; \ + TYPE NAME; #define STORAGE_STRING(NAME, SIZE) \ - bool has_##NAME; \ - char NAME[SIZE]; + bool has_##NAME; \ + char NAME[SIZE]; #define STORAGE_BYTES(NAME, SIZE) \ - bool has_##NAME; \ - struct { \ - uint32_t size; \ - uint8_t bytes[SIZE]; \ - } NAME; + bool has_##NAME; \ + struct { \ + uint32_t size; \ + uint8_t bytes[SIZE]; \ + } NAME; -#define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME) -#define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME) -#define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME) +#define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME) +#define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME) +#define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME) typedef struct { - uint32_t depth; - uint32_t fingerprint; - uint32_t child_num; - struct { - uint32_t size; - uint8_t bytes[32]; - } chain_code; + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + struct { + uint32_t size; + uint8_t bytes[32]; + } chain_code; - STORAGE_BYTES(private_key, 32); - STORAGE_BYTES(public_key, 33); + STORAGE_BYTES(private_key, 32); + STORAGE_BYTES(public_key, 33); } StorageHDNode; typedef struct _Storage { - uint32_t version; + uint32_t version; - STORAGE_NODE (node) - STORAGE_STRING (mnemonic, 241) - STORAGE_BOOL (passphrase_protection) - STORAGE_UINT32 (pin_failed_attempts) - STORAGE_STRING (pin, 10) - STORAGE_STRING (language, 17) - STORAGE_STRING (label, 33) - STORAGE_BOOL (imported) - STORAGE_BYTES (homescreen, 1024) - STORAGE_UINT32 (u2f_counter) - STORAGE_BOOL (needs_backup) - STORAGE_UINT32 (flags) - STORAGE_NODE (u2froot) - STORAGE_BOOL (unfinished_backup) - STORAGE_UINT32 (auto_lock_delay_ms) - STORAGE_BOOL (no_backup) + STORAGE_NODE(node) + STORAGE_STRING(mnemonic, 241) + STORAGE_BOOL(passphrase_protection) + STORAGE_UINT32(pin_failed_attempts) + STORAGE_STRING(pin, 10) + STORAGE_STRING(language, 17) + STORAGE_STRING(label, 33) + STORAGE_BOOL(imported) + STORAGE_BYTES(homescreen, 1024) + STORAGE_UINT32(u2f_counter) + STORAGE_BOOL(needs_backup) + STORAGE_UINT32(flags) + STORAGE_NODE(u2froot) + STORAGE_BOOL(unfinished_backup) + STORAGE_UINT32(auto_lock_delay_ms) + STORAGE_BOOL(no_backup) } Storage; extern Storage configUpdate; -#define MAX_PIN_LEN 9 -#define MAX_LABEL_LEN 32 -#define MAX_LANGUAGE_LEN 16 -#define MAX_MNEMONIC_LEN 240 -#define HOMESCREEN_SIZE 1024 -#define UUID_SIZE 12 +#define MAX_PIN_LEN 9 +#define MAX_LABEL_LEN 32 +#define MAX_LANGUAGE_LEN 16 +#define MAX_MNEMONIC_LEN 240 +#define HOMESCREEN_SIZE 1024 +#define UUID_SIZE 12 void config_init(void); void session_clear(bool lock); @@ -109,12 +109,14 @@ void config_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); -bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); +bool session_getState(const uint8_t *salt, uint8_t *state, + const char *passphrase); bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); bool config_getMnemonic(char *dest, uint16_t dest_size); -bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size); +bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, + uint16_t *real_size); #if DEBUG_LINK bool config_dumpNode(HDNodeType *node); @@ -151,6 +153,6 @@ void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); void config_wipe(void); -extern char config_uuid_str[2*UUID_SIZE + 1]; +extern char config_uuid_str[2 * UUID_SIZE + 1]; #endif diff --git a/firmware/crypto.c b/firmware/crypto.c index f71b093321..3b7aac7d68 100644 --- a/firmware/crypto.c +++ b/firmware/crypto.c @@ -17,452 +17,482 @@ * along with this library. If not, see . */ -#include #include "crypto.h" -#include "sha2.h" -#include "pbkdf2.h" -#include "aes/aes.h" -#include "hmac.h" -#include "bip32.h" -#include "layout.h" -#include "curves.h" -#include "secp256k1.h" +#include #include "address.h" -#include "coins.h" +#include "aes/aes.h" #include "base58.h" -#include "segwit_addr.h" +#include "bip32.h" #include "cash_addr.h" +#include "coins.h" +#include "curves.h" +#include "hmac.h" +#include "layout.h" +#include "pbkdf2.h" +#include "secp256k1.h" +#include "segwit_addr.h" +#include "sha2.h" -uint32_t ser_length(uint32_t len, uint8_t *out) -{ - if (len < 253) { - out[0] = len & 0xFF; - return 1; - } - if (len < 0x10000) { - out[0] = 253; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - return 3; - } - out[0] = 254; - out[1] = len & 0xFF; - out[2] = (len >> 8) & 0xFF; - out[3] = (len >> 16) & 0xFF; - out[4] = (len >> 24) & 0xFF; - return 5; +uint32_t ser_length(uint32_t len, uint8_t *out) { + if (len < 253) { + out[0] = len & 0xFF; + return 1; + } + if (len < 0x10000) { + out[0] = 253; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + return 3; + } + out[0] = 254; + out[1] = len & 0xFF; + out[2] = (len >> 8) & 0xFF; + out[3] = (len >> 16) & 0xFF; + out[4] = (len >> 24) & 0xFF; + return 5; } -uint32_t ser_length_hash(Hasher *hasher, uint32_t len) -{ - if (len < 253) { - hasher_Update(hasher, (const uint8_t *)&len, 1); - return 1; - } - if (len < 0x10000) { - uint8_t d = 253; - hasher_Update(hasher, &d, 1); - hasher_Update(hasher, (const uint8_t *)&len, 2); - return 3; - } - uint8_t d = 254; - hasher_Update(hasher, &d, 1); - hasher_Update(hasher, (const uint8_t *)&len, 4); - return 5; +uint32_t ser_length_hash(Hasher *hasher, uint32_t len) { + if (len < 253) { + hasher_Update(hasher, (const uint8_t *)&len, 1); + return 1; + } + if (len < 0x10000) { + uint8_t d = 253; + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 2); + return 3; + } + uint8_t d = 254; + hasher_Update(hasher, &d, 1); + hasher_Update(hasher, (const uint8_t *)&len, 4); + return 5; } -uint32_t deser_length(const uint8_t *in, uint32_t *out) -{ - if (in[0] < 253) { - *out = in[0]; - return 1; - } - if (in[0] == 253) { - *out = in[1] + (in[2] << 8); - return 1 + 2; - } - if (in[0] == 254) { - *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t) in[4] << 24); - return 1 + 4; - } - *out = 0; // ignore 64 bit - return 1 + 8; +uint32_t deser_length(const uint8_t *in, uint32_t *out) { + if (in[0] < 253) { + *out = in[0]; + return 1; + } + if (in[0] == 253) { + *out = in[1] + (in[2] << 8); + return 1 + 2; + } + if (in[0] == 254) { + *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t)in[4] << 24); + return 1 + 4; + } + *out = 0; // ignore 64 bit + return 1 + 8; } -int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, NULL, NULL); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature) { + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, + NULL, NULL); } -int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes - const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); - if (ed25519_curve_info && node->curve == ed25519_curve_info) { - // GPG supports variable size digest for Ed25519 signatures - return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL); - } else { - // Ensure 256-bit digest before proceeding - if (message_len != 32) { - return 1; - } - return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); - } +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature) { + signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes + const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); + if (ed25519_curve_info && node->curve == ed25519_curve_info) { + // GPG supports variable size digest for Ed25519 signatures + return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, + NULL); + } else { + // Ensure 256-bit digest before proceeding + if (message_len != 32) { + return 1; + } + return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); + } } -static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { - Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_sign); - hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); - uint8_t varint[5]; - uint32_t l = ser_length(message_len, varint); - hasher_Update(&hasher, varint, l); - hasher_Update(&hasher, message, message_len); - hasher_Final(&hasher, hash); +static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, + size_t message_len, + uint8_t hash[HASHER_DIGEST_LENGTH]) { + Hasher hasher; + hasher_Init(&hasher, coin->curve->hasher_sign); + hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, + strlen(coin->signed_message_header)); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + hasher_Update(&hasher, varint, l); + hasher_Update(&hasher, message, message_len); + hasher_Final(&hasher, hash); } -int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) -{ - uint8_t hash[HASHER_DIGEST_LENGTH]; - cryptoMessageHash(coin, message, message_len, hash); +int cryptoMessageSign(const CoinInfo *coin, HDNode *node, + InputScriptType script_type, const uint8_t *message, + size_t message_len, uint8_t *signature) { + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, message, message_len, hash); - uint8_t pby; - int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); - if (result == 0) { - switch (script_type) { - case InputScriptType_SPENDP2SHWITNESS: - // segwit-in-p2sh - signature[0] = 35 + pby; - break; - case InputScriptType_SPENDWITNESS: - // segwit - signature[0] = 39 + pby; - break; - default: - // p2pkh - signature[0] = 31 + pby; - break; - } - } - return result; + uint8_t pby; + int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); + if (result == 0) { + switch (script_type) { + case InputScriptType_SPENDP2SHWITNESS: + // segwit-in-p2sh + signature[0] = 35 + pby; + break; + case InputScriptType_SPENDWITNESS: + // segwit + signature[0] = 39 + pby; + break; + default: + // p2pkh + signature[0] = 31 + pby; + break; + } + } + return result; } -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) -{ - // check for invalid signature prefix - if (signature[0] < 27 || signature[0] > 43) { - return 1; - } +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, + size_t message_len, const char *address, + const uint8_t *signature) { + // check for invalid signature prefix + if (signature[0] < 27 || signature[0] > 43) { + return 1; + } - uint8_t hash[HASHER_DIGEST_LENGTH]; - cryptoMessageHash(coin, message, message_len, hash); + uint8_t hash[HASHER_DIGEST_LENGTH]; + cryptoMessageHash(coin, message, message_len, hash); - uint8_t recid = (signature[0] - 27) % 4; - bool compressed = signature[0] >= 31; + uint8_t recid = (signature[0] - 27) % 4; + bool compressed = signature[0] >= 31; - // check if signature verifies the digest and recover the public key - uint8_t pubkey[65]; - if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { - return 3; - } - // convert public key to compressed pubkey if necessary - if (compressed) { - pubkey[0] = 0x02 | (pubkey[64] & 1); - } + // check if signature verifies the digest and recover the public key + uint8_t pubkey[65]; + if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1, + hash, recid) != 0) { + return 3; + } + // convert public key to compressed pubkey if necessary + if (compressed) { + pubkey[0] = 0x02 | (pubkey[64] & 1); + } - // check if the address is correct - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; + // check if the address is correct + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; - // p2pkh - if (signature[0] >= 27 && signature[0] <= 34) { - size_t len; - if (coin->cashaddr_prefix) { - if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { - return 2; - } - } else { - len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - } - ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_pubkey, recovered_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || len != address_prefix_bytes_len(coin->address_type) + 20) { - return 2; - } - } else - // segwit-in-p2sh - if (signature[0] >= 35 && signature[0] <= 38) { - size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_pubkey, recovered_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { - return 2; - } - } else - // segwit - if (signature[0] >= 39 && signature[0] <= 42) { - int witver; - size_t len; - if (!coin->bech32_prefix - || !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { - return 4; - } - ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw); - if (memcmp(recovered_raw, addr_raw, len) != 0 - || witver != 0 || len != 20) { - return 2; - } - } else { - return 4; - } + // p2pkh + if (signature[0] >= 27 && signature[0] <= 34) { + size_t len; + if (coin->cashaddr_prefix) { + if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { + return 2; + } + } else { + len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, + MAX_ADDR_RAW_SIZE); + } + ecdsa_get_address_raw(pubkey, coin->address_type, + coin->curve->hasher_pubkey, recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || + len != address_prefix_bytes_len(coin->address_type) + 20) { + return 2; + } + } else + // segwit-in-p2sh + if (signature[0] >= 35 && signature[0] <= 38) { + size_t len = base58_decode_check(address, coin->curve->hasher_base58, + addr_raw, MAX_ADDR_RAW_SIZE); + ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, + coin->curve->hasher_pubkey, + recovered_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || + len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { + return 2; + } + } else + // segwit + if (signature[0] >= 39 && signature[0] <= 42) { + int witver; + size_t len; + if (!coin->bech32_prefix || + !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, + address)) { + return 4; + } + ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw); + if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) { + return 2; + } + } else { + return 4; + } - return 0; + return 0; } /* ECIES disabled -int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t +msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t +*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t +*privkey, const uint8_t *address_raw) { - if (privkey && address_raw) { // signing == true - HDNode node; - payload[0] = display_only ? 0x81 : 0x01; - uint32_t l = ser_length(msg_size, payload + 1); - memcpy(payload + 1 + l, msg, msg_size); - memcpy(payload + 1 + l + msg_size, address_raw, 21); - hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node); - if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) { - return 1; - } - *payload_len = 1 + l + msg_size + 21 + 65; - } else { - payload[0] = display_only ? 0x80 : 0x00; - uint32_t l = ser_length(msg_size, payload + 1); - memcpy(payload + 1 + l, msg, msg_size); - *payload_len = 1 + l + msg_size; - } - // generate random nonce - curve_point R; - bignum256 k; - if (generate_k_random(&secp256k1, &k) != 0) { - return 2; - } - // compute k*G - scalar_multiply(&secp256k1, &k, &R); - nonce[0] = 0x02 | (R.y.val[0] & 0x01); - bn_write_be(&R.x, nonce + 1); - *nonce_len = 33; - // compute shared secret - point_multiply(&secp256k1, &k, pubkey, &R); - uint8_t shared_secret[33]; - shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); - bn_write_be(&R.x, shared_secret + 1); - // generate keying bytes - uint8_t keying_bytes[80]; - uint8_t salt[22 + 33]; - memcpy(salt, "Bitcoin Secure Message", 22); - memcpy(salt + 22, nonce, 33); - pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); - // encrypt payload - aes_encrypt_ctx ctx; - aes_encrypt_key256(keying_bytes, &ctx); - aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64, &ctx); - // compute hmac - uint8_t out[32]; - hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out); - memcpy(hmac, out, 8); - *hmac_len = 8; + if (privkey && address_raw) { // signing == true + HDNode node; + payload[0] = display_only ? 0x81 : 0x01; + uint32_t l = ser_length(msg_size, payload + 1); + memcpy(payload + 1 + l, msg, msg_size); + memcpy(payload + 1 + l + msg_size, address_raw, 21); + hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, +&node); if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + +21) != 0) { return 1; + } + *payload_len = 1 + l + msg_size + 21 + 65; + } else { + payload[0] = display_only ? 0x80 : 0x00; + uint32_t l = ser_length(msg_size, payload + 1); + memcpy(payload + 1 + l, msg, msg_size); + *payload_len = 1 + l + msg_size; + } + // generate random nonce + curve_point R; + bignum256 k; + if (generate_k_random(&secp256k1, &k) != 0) { + return 2; + } + // compute k*G + scalar_multiply(&secp256k1, &k, &R); + nonce[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, nonce + 1); + *nonce_len = 33; + // compute shared secret + point_multiply(&secp256k1, &k, pubkey, &R); + uint8_t shared_secret[33]; + shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, shared_secret + 1); + // generate keying bytes + uint8_t keying_bytes[80]; + uint8_t salt[22 + 33]; + memcpy(salt, "Bitcoin Secure Message", 22); + memcpy(salt + 22, nonce, 33); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, +80); + // encrypt payload + aes_encrypt_ctx ctx; + aes_encrypt_key256(keying_bytes, &ctx); + aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64, +&ctx); + // compute hmac + uint8_t out[32]; + hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out); + memcpy(hmac, out, 8); + *hmac_len = 8; - return 0; + return 0; } -int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t +payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, +uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t +*address_raw) { - if (hmac_len != 8) { - return 1; - } - // compute shared secret - curve_point R; - bignum256 k; - bn_read_be(privkey, &k); - point_multiply(&secp256k1, &k, nonce, &R); - uint8_t shared_secret[33]; - shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); - bn_write_be(&R.x, shared_secret + 1); - // generate keying bytes - uint8_t keying_bytes[80]; - uint8_t salt[22 + 33]; - memcpy(salt, "Bitcoin Secure Message", 22); - salt[22] = 0x02 | (nonce->y.val[0] & 0x01); - bn_write_be(&(nonce->x), salt + 23); - pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); - // compute hmac - uint8_t out[32]; - hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); - if (memcmp(hmac, out, 8) != 0) { - return 2; - } - // decrypt payload - aes_encrypt_ctx ctx; - aes_encrypt_key256(keying_bytes, &ctx); - aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx); - // check first byte - if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && payload[0] != 0x81) { - return 3; - } - *signing = payload[0] & 0x01; - *display_only = payload[0] & 0x80; - uint32_t l, o; - l = deser_length(payload + 1, &o); - if (*signing) { - // FIXME: assumes a raw address is 21 bytes (also below). - if (1 + l + o + 21 + 65 != payload_len) { - return 4; - } - // FIXME: cryptoMessageVerify changed to take the address_type as a parameter. - if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) { - return 5; - } - memcpy(address_raw, payload + 1 + l + o, 21); - } else { - if (1 + l + o != payload_len) { - return 4; - } - } - memcpy(msg, payload + 1 + l, o); - *msg_len = o; - return 0; + if (hmac_len != 8) { + return 1; + } + // compute shared secret + curve_point R; + bignum256 k; + bn_read_be(privkey, &k); + point_multiply(&secp256k1, &k, nonce, &R); + uint8_t shared_secret[33]; + shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); + bn_write_be(&R.x, shared_secret + 1); + // generate keying bytes + uint8_t keying_bytes[80]; + uint8_t salt[22 + 33]; + memcpy(salt, "Bitcoin Secure Message", 22); + salt[22] = 0x02 | (nonce->y.val[0] & 0x01); + bn_write_be(&(nonce->x), salt + 23); + pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, +80); + // compute hmac + uint8_t out[32]; + hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); + if (memcmp(hmac, out, 8) != 0) { + return 2; + } + // decrypt payload + aes_encrypt_ctx ctx; + aes_encrypt_key256(keying_bytes, &ctx); + aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx); + // check first byte + if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && +payload[0] != 0x81) { return 3; + } + *signing = payload[0] & 0x01; + *display_only = payload[0] & 0x80; + uint32_t l, o; + l = deser_length(payload + 1, &o); + if (*signing) { + // FIXME: assumes a raw address is 21 bytes (also below). + if (1 + l + o + 21 + 65 != payload_len) { + return 4; + } + // FIXME: cryptoMessageVerify changed to take the address_type +as a parameter. if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, +payload + 1 + l + o + 21) != 0) { return 5; + } + memcpy(address_raw, payload + 1 + l + o, 21); + } else { + if (1 + l + o != payload_len) { + return 4; + } + } + memcpy(msg, payload + 1 + l, o); + *msg_len = o; + return 0; } */ -const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index) -{ - const HDNodeType *node_ptr; - const uint32_t *address_n; - uint32_t address_n_count; - if (multisig->nodes_count) { // use multisig->nodes - if (index >= multisig->nodes_count) { - return 0; - } - node_ptr = &(multisig->nodes[index]); - address_n = multisig->address_n; - address_n_count = multisig->address_n_count; - } else - if (multisig->pubkeys_count) { // use multisig->pubkeys - if (index >= multisig->pubkeys_count) { - return 0; - } - node_ptr = &(multisig->pubkeys[index].node); - address_n = multisig->pubkeys[index].address_n; - address_n_count = multisig->pubkeys[index].address_n_count; - } else { - return 0; - } - if (node_ptr->chain_code.size != 32) return 0; - if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; - static HDNode node; - if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, node_ptr->chain_code.bytes, node_ptr->public_key.bytes, coin->curve_name, &node)) { - return 0; - } - layoutProgressUpdate(true); - for (uint32_t i = 0; i < address_n_count; i++) { - if (!hdnode_public_ckd(&node, address_n[i])) { - return 0; - } - layoutProgressUpdate(true); - } - return &node; +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint32_t index) { + const HDNodeType *node_ptr; + const uint32_t *address_n; + uint32_t address_n_count; + if (multisig->nodes_count) { // use multisig->nodes + if (index >= multisig->nodes_count) { + return 0; + } + node_ptr = &(multisig->nodes[index]); + address_n = multisig->address_n; + address_n_count = multisig->address_n_count; + } else if (multisig->pubkeys_count) { // use multisig->pubkeys + if (index >= multisig->pubkeys_count) { + return 0; + } + node_ptr = &(multisig->pubkeys[index].node); + address_n = multisig->pubkeys[index].address_n; + address_n_count = multisig->pubkeys[index].address_n_count; + } else { + return 0; + } + if (node_ptr->chain_code.size != 32) return 0; + if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; + static HDNode node; + if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, + node_ptr->chain_code.bytes, node_ptr->public_key.bytes, + coin->curve_name, &node)) { + return 0; + } + layoutProgressUpdate(true); + for (uint32_t i = 0; i < address_n_count; i++) { + if (!hdnode_public_ckd(&node, address_n[i])) { + return 0; + } + layoutProgressUpdate(true); + } + return &node; } -uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) -{ - return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count; +uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) { + return multisig->nodes_count ? multisig->nodes_count + : multisig->pubkeys_count; } -int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) -{ - for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { - const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); - if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { - return i; - } - } - return -1; +int cryptoMultisigPubkeyIndex(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + const uint8_t *pubkey) { + for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { + return i; + } + } + return -1; } -int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) -{ - static const HDNodeType *pubnodes[15], *swap; - const uint32_t n = cryptoMultisigPubkeyCount(multisig); - if (n < 1 || n > 15) { - return 0; - } - if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) { - return 0; - } - for (uint32_t i = 0; i < n; i++) { - if (multisig->nodes_count) { // use multisig->nodes - pubnodes[i] = &(multisig->nodes[i]); - } else - if (multisig->pubkeys_count) { // use multisig->pubkeys - pubnodes[i] = &(multisig->pubkeys[i].node); - } else { - return 0; - } - } - for (uint32_t i = 0; i < n; i++) { - if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) return 0; - if (pubnodes[i]->chain_code.size != 32) return 0; - } - // minsort according to pubkey - for (uint32_t i = 0; i < n - 1; i++) { - for (uint32_t j = n - 1; j > i; j--) { - if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, 33) > 0) { - swap = pubnodes[i]; - pubnodes[i] = pubnodes[j]; - pubnodes[j] = swap; - } - } - } - // hash sorted nodes - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); - for (uint32_t i = 0; i < n; i++) { - sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), sizeof(uint32_t)); - sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t)); - sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); - sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); - } - sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); - sha256_Final(&ctx, hash); - layoutProgressUpdate(true); - return 1; +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, + uint8_t *hash) { + static const HDNodeType *pubnodes[15], *swap; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); + if (n < 1 || n > 15) { + return 0; + } + if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) { + return 0; + } + for (uint32_t i = 0; i < n; i++) { + if (multisig->nodes_count) { // use multisig->nodes + pubnodes[i] = &(multisig->nodes[i]); + } else if (multisig->pubkeys_count) { // use multisig->pubkeys + pubnodes[i] = &(multisig->pubkeys[i].node); + } else { + return 0; + } + } + for (uint32_t i = 0; i < n; i++) { + if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) + return 0; + if (pubnodes[i]->chain_code.size != 32) return 0; + } + // minsort according to pubkey + for (uint32_t i = 0; i < n - 1; i++) { + for (uint32_t j = n - 1; j > i; j--) { + if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, + 33) > 0) { + swap = pubnodes[i]; + pubnodes[i] = pubnodes[j]; + pubnodes[j] = swap; + } + } + } + // hash sorted nodes + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); + for (uint32_t i = 0; i < n; i++) { + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), + sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), + sizeof(uint32_t)); + sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), + sizeof(uint32_t)); + sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); + sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); + } + sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); + sha256_Final(&ctx, hash); + layoutProgressUpdate(true); + return 1; } -int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) -{ - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); - if (identity->has_proto && identity->proto[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->proto), strlen(identity->proto)); - sha256_Update(&ctx, (const uint8_t *)"://", 3); - } - if (identity->has_user && identity->user[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->user), strlen(identity->user)); - sha256_Update(&ctx, (const uint8_t *)"@", 1); - } - if (identity->has_host && identity->host[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->host), strlen(identity->host)); - } - if (identity->has_port && identity->port[0]) { - sha256_Update(&ctx, (const uint8_t *)":", 1); - sha256_Update(&ctx, (const uint8_t *)(identity->port), strlen(identity->port)); - } - if (identity->has_path && identity->path[0]) { - sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); - } - sha256_Final(&ctx, hash); - return 1; +int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) { + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); + if (identity->has_proto && identity->proto[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->proto), + strlen(identity->proto)); + sha256_Update(&ctx, (const uint8_t *)"://", 3); + } + if (identity->has_user && identity->user[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->user), + strlen(identity->user)); + sha256_Update(&ctx, (const uint8_t *)"@", 1); + } + if (identity->has_host && identity->host[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->host), + strlen(identity->host)); + } + if (identity->has_port && identity->port[0]) { + sha256_Update(&ctx, (const uint8_t *)":", 1); + sha256_Update(&ctx, (const uint8_t *)(identity->port), + strlen(identity->port)); + } + if (identity->has_path && identity->path[0]) { + sha256_Update(&ctx, (const uint8_t *)(identity->path), + strlen(identity->path)); + } + sha256_Final(&ctx, hash); + return 1; } diff --git a/firmware/crypto.h b/firmware/crypto.h index f8d77c9205..ab550864ed 100644 --- a/firmware/crypto.h +++ b/firmware/crypto.h @@ -20,13 +20,13 @@ #ifndef __CRYPTO_H__ #define __CRYPTO_H__ +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include #include "coins.h" #include "hasher.h" #include "messages-bitcoin.pb.h" @@ -38,27 +38,44 @@ uint32_t ser_length(uint32_t len, uint8_t *out); uint32_t ser_length_hash(Hasher *hasher, uint32_t len); -int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature); -int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); +int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, + uint8_t *signature); -int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); +int cryptoMessageSign(const CoinInfo *coin, HDNode *node, + InputScriptType script_type, const uint8_t *message, + size_t message_len, uint8_t *signature); -int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature); +int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, + size_t message_len, const char *address, + const uint8_t *signature); /* ECIES disabled -int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); +int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t +msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t +*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t +*privkey, const uint8_t *address_raw); -int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); +int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t +payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, +uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t +*address_raw); */ -const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index); +const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint32_t index); uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig); -int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); +int cryptoMultisigPubkeyIndex(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + const uint8_t *pubkey); -int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); +int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, + uint8_t *hash); int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash); diff --git a/firmware/debug.c b/firmware/debug.c index eb27314921..288041a4c0 100644 --- a/firmware/debug.c +++ b/firmware/debug.c @@ -17,52 +17,49 @@ * along with this library. If not, see . */ -#include "trezor.h" #include "debug.h" #include "oled.h" +#include "trezor.h" #include "util.h" #if DEBUG_LOG -void oledDebug(const char *line) -{ - static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - static char id = 3; - for (int i = 0; i < 7; i++) { - lines[i] = lines[i + 1]; - } - lines[7] = line; - oledClear(); - for (int i = 0; i < 8; i++) { - if (lines[i]) { - oledDrawChar(0, i * 8, '0' + (id + i) % 10, FONT_STANDARD); - oledDrawString(8, i * 8, lines[i], FONT_STANDARD); - } - } - oledRefresh(); - id = (id + 1) % 10; +void oledDebug(const char *line) { + static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + static char id = 3; + for (int i = 0; i < 7; i++) { + lines[i] = lines[i + 1]; + } + lines[7] = line; + oledClear(); + for (int i = 0; i < 8; i++) { + if (lines[i]) { + oledDrawChar(0, i * 8, '0' + (id + i) % 10, FONT_STANDARD); + oledDrawString(8, i * 8, lines[i], FONT_STANDARD); + } + } + oledRefresh(); + id = (id + 1) % 10; } -void debugLog(int level, const char *bucket, const char *text) -{ - (void)level; - (void)bucket; +void debugLog(int level, const char *bucket, const char *text) { + (void)level; + (void)bucket; #if EMULATOR - puts(text); + puts(text); #else - oledDebug(text); + oledDebug(text); #endif } -char *debugInt(const uint32_t i) -{ - static uint8_t n = 0; - static char id[8][9]; - uint32hex(i, id[n]); - debugLog(0, "", id[n]); - char *ret = (char *)id[n]; - n = (n + 1) % 8; - return ret; +char *debugInt(const uint32_t i) { + static uint8_t n = 0; + static char id[8][9]; + uint32hex(i, id[n]); + debugLog(0, "", id[n]); + char *ret = (char *)id[n]; + n = (n + 1) % 8; + return ret; } #endif diff --git a/firmware/debug.h b/firmware/debug.h index 94f9a0642a..0a20807cdb 100644 --- a/firmware/debug.h +++ b/firmware/debug.h @@ -20,8 +20,8 @@ #ifndef __DEBUG_H__ #define __DEBUG_H__ -#include "trezor.h" #include +#include "trezor.h" #if DEBUG_LOG @@ -30,8 +30,12 @@ char *debugInt(const uint32_t i); #else -#define debugLog(L, B, T) do{}while(0) -#define debugInt(I) do{}while(0) +#define debugLog(L, B, T) \ + do { \ + } while (0) +#define debugInt(I) \ + do { \ + } while (0) #endif diff --git a/firmware/ethereum.c b/firmware/ethereum.c index c9de7c9cca..51011cd6ac 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -20,22 +20,22 @@ */ #include "ethereum.h" -#include "fsm.h" -#include "layout2.h" -#include "messages.h" -#include "transaction.h" -#include "ecdsa.h" -#include "protect.h" +#include "address.h" #include "crypto.h" +#include "ecdsa.h" +#include "ethereum_networks.h" +#include "ethereum_tokens.h" +#include "fsm.h" +#include "gettext.h" +#include "layout2.h" +#include "memzero.h" +#include "messages.h" +#include "messages.pb.h" +#include "protect.h" #include "secp256k1.h" #include "sha3.h" -#include "address.h" +#include "transaction.h" #include "util.h" -#include "gettext.h" -#include "ethereum_tokens.h" -#include "ethereum_networks.h" -#include "memzero.h" -#include "messages.pb.h" /* maximum supported chain id. v must fit in an uint32_t. */ #define MAX_CHAIN_ID 2147483629 @@ -48,95 +48,90 @@ static uint32_t chain_id; static uint32_t tx_type; struct SHA3_CTX keccak_ctx; -static inline void hash_data(const uint8_t *buf, size_t size) -{ - sha3_Update(&keccak_ctx, buf, size); +static inline void hash_data(const uint8_t *buf, size_t size) { + sha3_Update(&keccak_ctx, buf, size); } /* * Push an RLP encoded length to the hash buffer. */ -static void hash_rlp_length(uint32_t length, uint8_t firstbyte) -{ - uint8_t buf[4]; - if (length == 1 && firstbyte <= 0x7f) { - /* empty length header */ - } else if (length <= 55) { - buf[0] = 0x80 + length; - hash_data(buf, 1); - } else if (length <= 0xff) { - buf[0] = 0xb7 + 1; - buf[1] = length; - hash_data(buf, 2); - } else if (length <= 0xffff) { - buf[0] = 0xb7 + 2; - buf[1] = length >> 8; - buf[2] = length & 0xff; - hash_data(buf, 3); - } else { - buf[0] = 0xb7 + 3; - buf[1] = length >> 16; - buf[2] = length >> 8; - buf[3] = length & 0xff; - hash_data(buf, 4); - } +static void hash_rlp_length(uint32_t length, uint8_t firstbyte) { + uint8_t buf[4]; + if (length == 1 && firstbyte <= 0x7f) { + /* empty length header */ + } else if (length <= 55) { + buf[0] = 0x80 + length; + hash_data(buf, 1); + } else if (length <= 0xff) { + buf[0] = 0xb7 + 1; + buf[1] = length; + hash_data(buf, 2); + } else if (length <= 0xffff) { + buf[0] = 0xb7 + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + hash_data(buf, 3); + } else { + buf[0] = 0xb7 + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + hash_data(buf, 4); + } } /* * Push an RLP encoded list length to the hash buffer. */ -static void hash_rlp_list_length(uint32_t length) -{ - uint8_t buf[4]; - if (length <= 55) { - buf[0] = 0xc0 + length; - hash_data(buf, 1); - } else if (length <= 0xff) { - buf[0] = 0xf7 + 1; - buf[1] = length; - hash_data(buf, 2); - } else if (length <= 0xffff) { - buf[0] = 0xf7 + 2; - buf[1] = length >> 8; - buf[2] = length & 0xff; - hash_data(buf, 3); - } else { - buf[0] = 0xf7 + 3; - buf[1] = length >> 16; - buf[2] = length >> 8; - buf[3] = length & 0xff; - hash_data(buf, 4); - } +static void hash_rlp_list_length(uint32_t length) { + uint8_t buf[4]; + if (length <= 55) { + buf[0] = 0xc0 + length; + hash_data(buf, 1); + } else if (length <= 0xff) { + buf[0] = 0xf7 + 1; + buf[1] = length; + hash_data(buf, 2); + } else if (length <= 0xffff) { + buf[0] = 0xf7 + 2; + buf[1] = length >> 8; + buf[2] = length & 0xff; + hash_data(buf, 3); + } else { + buf[0] = 0xf7 + 3; + buf[1] = length >> 16; + buf[2] = length >> 8; + buf[3] = length & 0xff; + hash_data(buf, 4); + } } /* * Push an RLP encoded length field and data to the hash buffer. */ -static void hash_rlp_field(const uint8_t *buf, size_t size) -{ - hash_rlp_length(size, buf[0]); - hash_data(buf, size); +static void hash_rlp_field(const uint8_t *buf, size_t size) { + hash_rlp_length(size, buf[0]); + hash_data(buf, size); } /* * Push an RLP encoded number to the hash buffer. * Ethereum yellow paper says to convert to big endian and strip leading zeros. */ -static void hash_rlp_number(uint32_t number) -{ - if (!number) { - return; - } - uint8_t data[4]; - data[0] = (number >> 24) & 0xff; - data[1] = (number >> 16) & 0xff; - data[2] = (number >> 8) & 0xff; - data[3] = (number) & 0xff; - int offset = 0; - while (!data[offset]) { - offset++; - } - hash_rlp_field(data + offset, 4 - offset); +static void hash_rlp_number(uint32_t number) { + if (!number) { + return; + } + uint8_t data[4]; + data[0] = (number >> 24) & 0xff; + data[1] = (number >> 16) & 0xff; + data[2] = (number >> 8) & 0xff; + data[3] = (number)&0xff; + int offset = 0; + while (!data[offset]) { + offset++; + } + hash_rlp_field(data + offset, 4 - offset); } /* @@ -144,274 +139,242 @@ static void hash_rlp_number(uint32_t number) * NOTE: supports up to 16MB of data (how unlikely...) * FIXME: improve */ -static int rlp_calculate_length(int length, uint8_t firstbyte) -{ - if (length == 1 && firstbyte <= 0x7f) { - return 1; - } else if (length <= 55) { - return 1 + length; - } else if (length <= 0xff) { - return 2 + length; - } else if (length <= 0xffff) { - return 3 + length; - } else { - return 4 + length; - } +static int rlp_calculate_length(int length, uint8_t firstbyte) { + if (length == 1 && firstbyte <= 0x7f) { + return 1; + } else if (length <= 55) { + return 1 + length; + } else if (length <= 0xff) { + return 2 + length; + } else if (length <= 0xffff) { + return 3 + length; + } else { + return 4 + length; + } } -static int rlp_calculate_number_length(uint32_t number) -{ - if (number <= 0x7f) { - return 1; - } - else if (number <= 0xff) { - return 2; - } - else if (number <= 0xffff) { - return 3; - } - else if (number <= 0xffffff) { - return 4; - } else { - return 5; - } +static int rlp_calculate_number_length(uint32_t number) { + if (number <= 0x7f) { + return 1; + } else if (number <= 0xff) { + return 2; + } else if (number <= 0xffff) { + return 3; + } else if (number <= 0xffffff) { + return 4; + } else { + return 5; + } } -static void send_request_chunk(void) -{ - int progress = 1000 - (data_total > 1000000 - ? data_left / (data_total/800) - : data_left * 800 / data_total); - layoutProgress(_("Signing"), progress); - msg_tx_request.has_data_length = true; - msg_tx_request.data_length = data_left <= 1024 ? data_left : 1024; - msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); +static void send_request_chunk(void) { + int progress = 1000 - (data_total > 1000000 ? data_left / (data_total / 800) + : data_left * 800 / data_total); + layoutProgress(_("Signing"), progress); + msg_tx_request.has_data_length = true; + msg_tx_request.data_length = data_left <= 1024 ? data_left : 1024; + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); } -static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) -{ - (void) signature; - return (v & 2) == 0; +static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) { + (void)signature; + return (v & 2) == 0; } -static void send_signature(void) -{ - uint8_t hash[32], sig[64]; - uint8_t v; - layoutProgress(_("Signing"), 1000); +static void send_signature(void) { + uint8_t hash[32], sig[64]; + uint8_t v; + layoutProgress(_("Signing"), 1000); - /* eip-155 replay protection */ - if (chain_id) { - /* hash v=chain_id, r=0, s=0 */ - hash_rlp_number(chain_id); - hash_rlp_length(0, 0); - hash_rlp_length(0, 0); - } + /* eip-155 replay protection */ + if (chain_id) { + /* hash v=chain_id, r=0, s=0 */ + hash_rlp_number(chain_id); + hash_rlp_length(0, 0); + hash_rlp_length(0, 0); + } - keccak_Final(&keccak_ctx, hash); - if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); - ethereum_signing_abort(); - return; - } + keccak_Final(&keccak_ctx, hash); + if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, + ethereum_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + ethereum_signing_abort(); + return; + } - memzero(privkey, sizeof(privkey)); + memzero(privkey, sizeof(privkey)); - /* Send back the result */ - msg_tx_request.has_data_length = false; + /* Send back the result */ + msg_tx_request.has_data_length = false; - msg_tx_request.has_signature_v = true; - if (chain_id > MAX_CHAIN_ID) { - msg_tx_request.signature_v = v; - } else if (chain_id) { - msg_tx_request.signature_v = v + 2 * chain_id + 35; - } else { - msg_tx_request.signature_v = v + 27; - } + msg_tx_request.has_signature_v = true; + if (chain_id > MAX_CHAIN_ID) { + msg_tx_request.signature_v = v; + } else if (chain_id) { + msg_tx_request.signature_v = v + 2 * chain_id + 35; + } else { + msg_tx_request.signature_v = v + 27; + } - msg_tx_request.has_signature_r = true; - msg_tx_request.signature_r.size = 32; - memcpy(msg_tx_request.signature_r.bytes, sig, 32); + msg_tx_request.has_signature_r = true; + msg_tx_request.signature_r.size = 32; + memcpy(msg_tx_request.signature_r.bytes, sig, 32); - msg_tx_request.has_signature_s = true; - msg_tx_request.signature_s.size = 32; - memcpy(msg_tx_request.signature_s.bytes, sig + 32, 32); + msg_tx_request.has_signature_s = true; + msg_tx_request.signature_s.size = 32; + memcpy(msg_tx_request.signature_s.bytes, sig + 32, 32); - msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); + msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); - ethereum_signing_abort(); + ethereum_signing_abort(); } /* Format a 256 bit number (amount in wei) into a human readable format * using standard ethereum units. * The buffer must be at least 25 bytes. */ -static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, char *buf, int buflen) -{ - bignum256 bn1e9; - bn_read_uint32(1000000000, &bn1e9); - const char *suffix = NULL; - int decimals = 18; - if (token == UnknownToken) { - strlcpy(buf, "Unknown token value", buflen); - return; - } else - if (token != NULL) { - suffix = token->ticker; - decimals = token->decimals; - } else - if (bn_is_less(amnt, &bn1e9)) { - suffix = " Wei"; - decimals = 0; - } else { - if (tx_type == 1 || tx_type == 6) { - suffix = " WAN"; - } else { - ASSIGN_ETHEREUM_SUFFIX(suffix, chain_id); - } - } - bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); +static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, + char *buf, int buflen) { + bignum256 bn1e9; + bn_read_uint32(1000000000, &bn1e9); + const char *suffix = NULL; + int decimals = 18; + if (token == UnknownToken) { + strlcpy(buf, "Unknown token value", buflen); + return; + } else if (token != NULL) { + suffix = token->ticker; + decimals = token->decimals; + } else if (bn_is_less(amnt, &bn1e9)) { + suffix = " Wei"; + decimals = 0; + } else { + if (tx_type == 1 || tx_type == 6) { + suffix = " WAN"; + } else { + ASSIGN_ETHEREUM_SUFFIX(suffix, chain_id); + } + } + bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); } -static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token) -{ - bignum256 val; - uint8_t pad_val[32]; - memzero(pad_val, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, &val); +static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, + const uint8_t *value, uint32_t value_len, + const TokenType *token) { + bignum256 val; + uint8_t pad_val[32]; + memzero(pad_val, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); - char amount[32]; - if (token == NULL) { - if (bn_is_zero(&val)) { - strcpy(amount, _("message")); - } else { - ethereumFormatAmount(&val, NULL, amount, sizeof(amount)); - } - } else { - ethereumFormatAmount(&val, token, amount, sizeof(amount)); - } + char amount[32]; + if (token == NULL) { + if (bn_is_zero(&val)) { + strcpy(amount, _("message")); + } else { + ethereumFormatAmount(&val, NULL, amount, sizeof(amount)); + } + } else { + ethereumFormatAmount(&val, token, amount, sizeof(amount)); + } - char _to1[] = "to 0x__________"; - char _to2[] = "_______________"; - char _to3[] = "_______________?"; + char _to1[] = "to 0x__________"; + char _to2[] = "_______________"; + char _to3[] = "_______________?"; - if (to_len) { - char to_str[41]; + if (to_len) { + char to_str[41]; - bool rskip60 = false; - // constants from trezor-common/defs/ethereum/networks.json - switch (chain_id) { - case 30: rskip60 = true; break; - case 31: rskip60 = true; break; - } + bool rskip60 = false; + // constants from trezor-common/defs/ethereum/networks.json + switch (chain_id) { + case 30: + rskip60 = true; + break; + case 31: + rskip60 = true; + break; + } - ethereum_address_checksum(to, to_str, rskip60, chain_id); - memcpy(_to1 + 5, to_str, 10); - memcpy(_to2, to_str + 10, 15); - memcpy(_to3, to_str + 25, 15); - } else { - strlcpy(_to1, _("to new contract?"), sizeof(_to1)); - strlcpy(_to2, "", sizeof(_to2)); - strlcpy(_to3, "", sizeof(_to3)); - } + ethereum_address_checksum(to, to_str, rskip60, chain_id); + memcpy(_to1 + 5, to_str, 10); + memcpy(_to2, to_str + 10, 15); + memcpy(_to3, to_str + 25, 15); + } else { + strlcpy(_to1, _("to new contract?"), sizeof(_to1)); + strlcpy(_to2, "", sizeof(_to2)); + strlcpy(_to3, "", sizeof(_to3)); + } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Send"), - amount, - _to1, - _to2, - _to3, - NULL - ); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Send"), amount, _to1, _to2, _to3, NULL); } -static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total_len) -{ - char hexdata[3][17]; - char summary[20]; - uint32_t printed = 0; - for (int i = 0; i < 3; i++) { - uint32_t linelen = len - printed; - if (linelen > 8) { - linelen = 8; - } - data2hex(data, linelen, hexdata[i]); - data += linelen; - printed += linelen; - } +static void layoutEthereumData(const uint8_t *data, uint32_t len, + uint32_t total_len) { + char hexdata[3][17]; + char summary[20]; + uint32_t printed = 0; + for (int i = 0; i < 3; i++) { + uint32_t linelen = len - printed; + if (linelen > 8) { + linelen = 8; + } + data2hex(data, linelen, hexdata[i]); + data += linelen; + printed += linelen; + } - strcpy(summary, "... bytes"); - char *p = summary + 11; - uint32_t number = total_len; - while (number > 0) { - *p-- = '0' + number % 10; - number = number / 10; - } - char *summarystart = summary; - if (total_len == printed) - summarystart = summary + 4; + strcpy(summary, "... bytes"); + char *p = summary + 11; + uint32_t number = total_len; + while (number > 0) { + *p-- = '0' + number % 10; + number = number / 10; + } + char *summarystart = summary; + if (total_len == printed) summarystart = summary + 4; - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Transaction data:"), - hexdata[0], - hexdata[1], - hexdata[2], - summarystart, - NULL - ); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Transaction data:"), hexdata[0], hexdata[1], hexdata[2], + summarystart, NULL); } static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, - const uint8_t *gas_price, uint32_t gas_price_len, - const uint8_t *gas_limit, uint32_t gas_limit_len, - bool is_token) -{ - bignum256 val, gas; - uint8_t pad_val[32]; - char tx_value[32]; - char gas_value[32]; + const uint8_t *gas_price, uint32_t gas_price_len, + const uint8_t *gas_limit, uint32_t gas_limit_len, + bool is_token) { + bignum256 val, gas; + uint8_t pad_val[32]; + char tx_value[32]; + char gas_value[32]; - memzero(tx_value, sizeof(tx_value)); - memzero(gas_value, sizeof(gas_value)); + memzero(tx_value, sizeof(tx_value)); + memzero(gas_value, sizeof(gas_value)); - memzero(pad_val, sizeof(pad_val)); - memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); - bn_read_be(pad_val, &val); + memzero(pad_val, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_price_len), gas_price, gas_price_len); + bn_read_be(pad_val, &val); - memzero(pad_val, sizeof(pad_val)); - memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); - bn_read_be(pad_val, &gas); - bn_multiply(&val, &gas, &secp256k1.prime); + memzero(pad_val, sizeof(pad_val)); + memcpy(pad_val + (32 - gas_limit_len), gas_limit, gas_limit_len); + bn_read_be(pad_val, &gas); + bn_multiply(&val, &gas, &secp256k1.prime); - ethereumFormatAmount(&gas, NULL, gas_value, sizeof(gas_value)); + ethereumFormatAmount(&gas, NULL, gas_value, sizeof(gas_value)); - memzero(pad_val, sizeof(pad_val)); - memcpy(pad_val + (32 - value_len), value, value_len); - bn_read_be(pad_val, &val); + memzero(pad_val, sizeof(pad_val)); + memcpy(pad_val + (32 - value_len), value, value_len); + bn_read_be(pad_val, &val); - if (bn_is_zero(&val)) { - strcpy(tx_value, is_token ? _("token") : _("message")); - } else { - ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value)); - } + if (bn_is_zero(&val)) { + strcpy(tx_value, is_token ? _("token") : _("message")); + } else { + ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value)); + } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Really send"), - tx_value, - _("paying up to"), - gas_value, - _("for gas?"), - NULL - ); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Really send"), tx_value, _("paying up to"), gas_value, + _("for gas?"), NULL); } /* @@ -424,353 +387,385 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, * - data (0 ..) */ -static bool ethereum_signing_check(const EthereumSignTx *msg) -{ - if (!msg->has_gas_price || !msg->has_gas_limit) { - return false; - } - - size_t tolen = msg->has_to ? strlen(msg->to) : 0; +static bool ethereum_signing_check(const EthereumSignTx *msg) { + if (!msg->has_gas_price || !msg->has_gas_limit) { + return false; + } - if (tolen != 42 && tolen != 40 && tolen != 0) { - /* Address has wrong length */ - return false; - } + size_t tolen = msg->has_to ? strlen(msg->to) : 0; - // sending transaction to address 0 (contract creation) without a data field - if (tolen == 0 && (!msg->has_data_length || msg->data_length == 0)) { - return false; - } + if (tolen != 42 && tolen != 40 && tolen != 0) { + /* Address has wrong length */ + return false; + } - if (msg->gas_price.size + msg->gas_limit.size > 30) { - // sanity check that fee doesn't overflow - return false; - } + // sending transaction to address 0 (contract creation) without a data field + if (tolen == 0 && (!msg->has_data_length || msg->data_length == 0)) { + return false; + } - return true; + if (msg->gas_price.size + msg->gas_limit.size > 30) { + // sanity check that fee doesn't overflow + return false; + } + + return true; } -void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) -{ - ethereum_signing = true; - sha3_256_Init(&keccak_ctx); +void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) { + ethereum_signing = true; + sha3_256_Init(&keccak_ctx); - memzero(&msg_tx_request, sizeof(EthereumTxRequest)); - /* set fields to 0, to avoid conditions later */ - if (!msg->has_value) - msg->value.size = 0; - if (!msg->has_data_initial_chunk) - msg->data_initial_chunk.size = 0; - bool toset; - uint8_t pubkeyhash[20]; - if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) { - toset = true; - } else { - msg->to[0] = 0; - toset = false; - memzero(pubkeyhash, sizeof(pubkeyhash)); - } - if (!msg->has_nonce) - msg->nonce.size = 0; + memzero(&msg_tx_request, sizeof(EthereumTxRequest)); + /* set fields to 0, to avoid conditions later */ + if (!msg->has_value) msg->value.size = 0; + if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0; + bool toset; + uint8_t pubkeyhash[20]; + if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) { + toset = true; + } else { + msg->to[0] = 0; + toset = false; + memzero(pubkeyhash, sizeof(pubkeyhash)); + } + if (!msg->has_nonce) msg->nonce.size = 0; - /* eip-155 chain id */ - if (msg->has_chain_id) { - if (msg->chain_id < 1) { - fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); - ethereum_signing_abort(); - return; - } - chain_id = msg->chain_id; - } else { - chain_id = 0; - } + /* eip-155 chain id */ + if (msg->has_chain_id) { + if (msg->chain_id < 1) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Chain Id out of bounds")); + ethereum_signing_abort(); + return; + } + chain_id = msg->chain_id; + } else { + chain_id = 0; + } - /* Wanchain txtype */ - if (msg->has_tx_type) { - if (msg->tx_type == 1 || msg->tx_type == 6) { - tx_type = msg->tx_type; - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); - ethereum_signing_abort(); - return; - } - } else { - tx_type = 0; - } + /* Wanchain txtype */ + if (msg->has_tx_type) { + if (msg->tx_type == 1 || msg->tx_type == 6) { + tx_type = msg->tx_type; + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Txtype out of bounds")); + ethereum_signing_abort(); + return; + } + } else { + tx_type = 0; + } - if (msg->has_data_length && msg->data_length > 0) { - if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); - ethereum_signing_abort(); - return; - } - /* Our encoding only supports transactions up to 2^24 bytes. To - * prevent exceeding the limit we use a stricter limit on data length. - */ - if (msg->data_length > 16000000) { - fsm_sendFailure(FailureType_Failure_DataError, _("Data length exceeds limit")); - ethereum_signing_abort(); - return; - } - data_total = msg->data_length; - } else { - data_total = 0; - } - if (msg->data_initial_chunk.size > data_total) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid size of initial chunk")); - ethereum_signing_abort(); - return; - } + if (msg->has_data_length && msg->data_length > 0) { + if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Data length provided, but no initial chunk")); + ethereum_signing_abort(); + return; + } + /* Our encoding only supports transactions up to 2^24 bytes. To + * prevent exceeding the limit we use a stricter limit on data length. + */ + if (msg->data_length > 16000000) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Data length exceeds limit")); + ethereum_signing_abort(); + return; + } + data_total = msg->data_length; + } else { + data_total = 0; + } + if (msg->data_initial_chunk.size > data_total) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid size of initial chunk")); + ethereum_signing_abort(); + return; + } - // safety checks - if (!ethereum_signing_check(msg)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed")); - ethereum_signing_abort(); - return; - } + // safety checks + if (!ethereum_signing_check(msg)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Safety check failed")); + ethereum_signing_abort(); + return; + } - const TokenType *token = NULL; + const TokenType *token = NULL; - // detect ERC-20 token - if (toset && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 - && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - token = tokenByChainAddress(chain_id, pubkeyhash); - } + // detect ERC-20 token + if (toset && msg->value.size == 0 && data_total == 68 && + msg->data_initial_chunk.size == 68 && + memcmp(msg->data_initial_chunk.bytes, + "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + 16) == 0) { + token = tokenByChainAddress(chain_id, pubkeyhash); + } - if (token != NULL) { - layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); - } else { - layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size, NULL); - } + if (token != NULL) { + layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, + msg->data_initial_chunk.bytes + 36, 32, token); + } else { + layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size, + NULL); + } - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - ethereum_signing_abort(); - return; - } + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + ethereum_signing_abort(); + return; + } - if (token == NULL && data_total > 0) { - layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - ethereum_signing_abort(); - return; - } - } + if (token == NULL && data_total > 0) { + layoutEthereumData(msg->data_initial_chunk.bytes, + msg->data_initial_chunk.size, data_total); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + ethereum_signing_abort(); + return; + } + } - layoutEthereumFee(msg->value.bytes, msg->value.size, - msg->gas_price.bytes, msg->gas_price.size, - msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - ethereum_signing_abort(); - return; - } - - /* Stage 1: Calculate total RLP length */ - uint32_t rlp_length = 0; + layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes, + msg->gas_price.size, msg->gas_limit.bytes, + msg->gas_limit.size, token != NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + ethereum_signing_abort(); + return; + } - layoutProgress(_("Signing"), 0); + /* Stage 1: Calculate total RLP length */ + uint32_t rlp_length = 0; - rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); - rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); - rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]); - rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); - rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); - if (tx_type) { - rlp_length += rlp_calculate_number_length(tx_type); - } - if (chain_id) { - rlp_length += rlp_calculate_number_length(chain_id); - rlp_length += rlp_calculate_length(0, 0); - rlp_length += rlp_calculate_length(0, 0); - } + layoutProgress(_("Signing"), 0); - /* Stage 2: Store header fields */ - hash_rlp_list_length(rlp_length); + rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); + rlp_length += + rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); + rlp_length += + rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); + rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]); + rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); + rlp_length += + rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); + if (tx_type) { + rlp_length += rlp_calculate_number_length(tx_type); + } + if (chain_id) { + rlp_length += rlp_calculate_number_length(chain_id); + rlp_length += rlp_calculate_length(0, 0); + rlp_length += rlp_calculate_length(0, 0); + } - layoutProgress(_("Signing"), 100); + /* Stage 2: Store header fields */ + hash_rlp_list_length(rlp_length); - if (tx_type) { - hash_rlp_number(tx_type); - } - hash_rlp_field(msg->nonce.bytes, msg->nonce.size); - hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); - hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - hash_rlp_field(pubkeyhash, toset ? 20 : 0); - hash_rlp_field(msg->value.bytes, msg->value.size); - hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); - hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - data_left = data_total - msg->data_initial_chunk.size; + layoutProgress(_("Signing"), 100); - memcpy(privkey, node->private_key, 32); + if (tx_type) { + hash_rlp_number(tx_type); + } + hash_rlp_field(msg->nonce.bytes, msg->nonce.size); + hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); + hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); + hash_rlp_field(pubkeyhash, toset ? 20 : 0); + hash_rlp_field(msg->value.bytes, msg->value.size); + hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); + hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); + data_left = data_total - msg->data_initial_chunk.size; - if (data_left > 0) { - send_request_chunk(); - } else { - send_signature(); - } + memcpy(privkey, node->private_key, 32); + + if (data_left > 0) { + send_request_chunk(); + } else { + send_signature(); + } } -void ethereum_signing_txack(const EthereumTxAck *tx) -{ - if (!ethereum_signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); - layoutHome(); - return; - } +void ethereum_signing_txack(const EthereumTxAck *tx) { + if (!ethereum_signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Ethereum signing mode")); + layoutHome(); + return; + } - if (tx->data_chunk.size > data_left) { - fsm_sendFailure(FailureType_Failure_DataError, _("Too much data")); - ethereum_signing_abort(); - return; - } + if (tx->data_chunk.size > data_left) { + fsm_sendFailure(FailureType_Failure_DataError, _("Too much data")); + ethereum_signing_abort(); + return; + } - if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received")); - ethereum_signing_abort(); - return; - } + if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Empty data chunk received")); + ethereum_signing_abort(); + return; + } - hash_data(tx->data_chunk.bytes, tx->data_chunk.size); + hash_data(tx->data_chunk.bytes, tx->data_chunk.size); - data_left -= tx->data_chunk.size; + data_left -= tx->data_chunk.size; - if (data_left > 0) { - send_request_chunk(); - } else { - send_signature(); - } + if (data_left > 0) { + send_request_chunk(); + } else { + send_signature(); + } } -void ethereum_signing_abort(void) -{ - if (ethereum_signing) { - memzero(privkey, sizeof(privkey)); - layoutHome(); - ethereum_signing = false; - } +void ethereum_signing_abort(void) { + if (ethereum_signing) { + memzero(privkey, sizeof(privkey)); + layoutHome(); + ethereum_signing = false; + } } -static void ethereum_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) -{ - struct SHA3_CTX ctx; - sha3_256_Init(&ctx); - sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); - uint8_t c; - if (message_len > 1000000000) { c = '0' + message_len / 1000000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 100000000) { c = '0' + message_len / 100000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 10000000) { c = '0' + message_len / 10000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 1000000) { c = '0' + message_len / 1000000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 100000) { c = '0' + message_len / 100000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 10000) { c = '0' + message_len / 10000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 1000) { c = '0' + message_len / 1000 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 100) { c = '0' + message_len / 100 % 10; sha3_Update(&ctx, &c, 1); } - if (message_len > 10) { c = '0' + message_len / 10 % 10; sha3_Update(&ctx, &c, 1); } - c = '0' + message_len % 10; sha3_Update(&ctx, &c, 1); - sha3_Update(&ctx, message, message_len); - keccak_Final(&ctx, hash); +static void ethereum_message_hash(const uint8_t *message, size_t message_len, + uint8_t hash[32]) { + struct SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); + uint8_t c; + if (message_len > 1000000000) { + c = '0' + message_len / 1000000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 100000000) { + c = '0' + message_len / 100000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 10000000) { + c = '0' + message_len / 10000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 1000000) { + c = '0' + message_len / 1000000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 100000) { + c = '0' + message_len / 100000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 10000) { + c = '0' + message_len / 10000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 1000) { + c = '0' + message_len / 1000 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 100) { + c = '0' + message_len / 100 % 10; + sha3_Update(&ctx, &c, 1); + } + if (message_len > 10) { + c = '0' + message_len / 10 % 10; + sha3_Update(&ctx, &c, 1); + } + c = '0' + message_len % 10; + sha3_Update(&ctx, &c, 1); + sha3_Update(&ctx, message, message_len); + keccak_Final(&ctx, hash); } -void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) -{ - uint8_t pubkeyhash[20]; - if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) { - return; - } +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, + EthereumMessageSignature *resp) { + uint8_t pubkeyhash[20]; + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) { + return; + } - resp->has_address = true; - resp->address[0] = '0'; - resp->address[1] = 'x'; - ethereum_address_checksum(pubkeyhash, resp->address + 2, false, 0); - // ethereum_address_checksum adds trailing zero + resp->has_address = true; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, false, 0); + // ethereum_address_checksum adds trailing zero - uint8_t hash[32]; - ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + uint8_t hash[32]; + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); - uint8_t v; - if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); - return; - } + uint8_t v; + if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, + resp->signature.bytes, &v, ethereum_is_canonic) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + return; + } - resp->has_signature = true; - resp->signature.bytes[64] = 27 + v; - resp->signature.size = 65; - msg_write(MessageType_MessageType_EthereumMessageSignature, resp); + resp->has_signature = true; + resp->signature.bytes[64] = 27 + v; + resp->signature.size = 65; + msg_write(MessageType_MessageType_EthereumMessageSignature, resp); } -int ethereum_message_verify(const EthereumVerifyMessage *msg) -{ - if (msg->signature.size != 65) { - fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature")); - return 1; - } +int ethereum_message_verify(const EthereumVerifyMessage *msg) { + if (msg->signature.size != 65) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature")); + return 1; + } - uint8_t pubkeyhash[20]; - if (!ethereum_parse(msg->address, pubkeyhash)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Malformed address")); - return 1; - } + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed address")); + return 1; + } - uint8_t pubkey[65]; - uint8_t hash[32]; + uint8_t pubkey[65]; + uint8_t hash[32]; - ethereum_message_hash(msg->message.bytes, msg->message.size, hash); + ethereum_message_hash(msg->message.bytes, msg->message.size, hash); - /* v should be 27, 28 but some implementations use 0,1. We are - * compatible with both. - */ - uint8_t v = msg->signature.bytes[64]; - if (v >= 27) { - v -= 27; - } - if (v >= 2 || - ecdsa_recover_pub_from_sig(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { - return 2; - } + /* v should be 27, 28 but some implementations use 0,1. We are + * compatible with both. + */ + uint8_t v = msg->signature.bytes[64]; + if (v >= 27) { + v -= 27; + } + if (v >= 2 || ecdsa_recover_pub_from_sig( + &secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { + return 2; + } - struct SHA3_CTX ctx; - sha3_256_Init(&ctx); - sha3_Update(&ctx, pubkey + 1, 64); - keccak_Final(&ctx, hash); + struct SHA3_CTX ctx; + sha3_256_Init(&ctx); + sha3_Update(&ctx, pubkey + 1, 64); + keccak_Final(&ctx, hash); - /* result are the least significant 160 bits */ - if (memcmp(pubkeyhash, hash + 12, 20) != 0) { - return 2; - } - return 0; + /* result are the least significant 160 bits */ + if (memcmp(pubkeyhash, hash + 12, 20) != 0) { + return 2; + } + return 0; } -bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) -{ - memzero(pubkeyhash, 20); - size_t len = strlen(address); - if (len == 40) { - // do nothing - } else - if (len == 42) { - // check for "0x" prefix and strip it when required - if (address[0] != '0') return false; - if (address[1] != 'x' && address[1] != 'X') return false; - address += 2; - len -= 2; - } else { - return false; - } - for (size_t i = 0; i < len; i++) { - if (address[i] >= '0' && address[i] <= '9') { - pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4); - } else - if (address[i] >= 'a' && address[i] <= 'f') { - pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4); - } else - if (address[i] >= 'A' && address[i] <= 'F') { - pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4); - } else { - return false; - } - } - return true; +bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) { + memzero(pubkeyhash, 20); + size_t len = strlen(address); + if (len == 40) { + // do nothing + } else if (len == 42) { + // check for "0x" prefix and strip it when required + if (address[0] != '0') return false; + if (address[1] != 'x' && address[1] != 'X') return false; + address += 2; + len -= 2; + } else { + return false; + } + for (size_t i = 0; i < len; i++) { + if (address[i] >= '0' && address[i] <= '9') { + pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4); + } else if (address[i] >= 'a' && address[i] <= 'f') { + pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4); + } else if (address[i] >= 'A' && address[i] <= 'F') { + pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4); + } else { + return false; + } + } + return true; } diff --git a/firmware/ethereum.h b/firmware/ethereum.h index 0bcc006273..3e8ad02f68 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -20,8 +20,8 @@ #ifndef __ETHEREUM_H__ #define __ETHEREUM_H__ -#include #include +#include #include "bip32.h" #include "messages-ethereum.pb.h" @@ -29,7 +29,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node); void ethereum_signing_abort(void); void ethereum_signing_txack(const EthereumTxAck *msg); -void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); +void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, + EthereumMessageSignature *resp); int ethereum_message_verify(const EthereumVerifyMessage *msg); bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]); diff --git a/firmware/fsm.c b/firmware/fsm.c index ce0732fa15..59f93774f3 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -19,235 +19,242 @@ #include -#include "trezor.h" -#include "fsm.h" -#include "messages.h" -#include "bip32.h" -#include "config.h" -#include "coins.h" -#include "debug.h" -#include "transaction.h" -#include "rng.h" -#include "oled.h" -#include "protect.h" -#include "pinmatrix.h" -#include "layout2.h" #include "address.h" -#include "base58.h" -#include "ecdsa.h" -#include "reset.h" -#include "recovery.h" -#include "memory.h" -#include "usb.h" -#include "util.h" -#include "signing.h" #include "aes/aes.h" -#include "hmac.h" -#include "crypto.h" #include "base58.h" +#include "bip32.h" #include "bip39.h" +#include "coins.h" +#include "config.h" +#include "crypto.h" #include "curves.h" -#include "secp256k1.h" +#include "debug.h" +#include "ecdsa.h" #include "ethereum.h" +#include "fsm.h" +#include "gettext.h" +#include "hmac.h" +#include "layout2.h" +#include "lisk.h" +#include "memory.h" +#include "memzero.h" +#include "messages.h" +#include "messages.pb.h" #include "nem.h" #include "nem2.h" +#include "oled.h" +#include "pinmatrix.h" +#include "protect.h" +#include "recovery.h" +#include "reset.h" #include "rfc6979.h" -#include "gettext.h" -#include "supervise.h" -#include "messages.pb.h" +#include "rng.h" +#include "secp256k1.h" +#include "signing.h" #include "stellar.h" -#include "lisk.h" -#include "memzero.h" +#include "supervise.h" +#include "transaction.h" +#include "trezor.h" +#include "usb.h" +#include "util.h" // message methods -static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); +static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__((aligned)); -#define RESP_INIT(TYPE) \ - TYPE *resp = (TYPE *) (void *) msg_resp; \ - _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ - memzero(resp, sizeof(TYPE)); +#define RESP_INIT(TYPE) \ + TYPE *resp = (TYPE *)(void *)msg_resp; \ + _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ + memzero(resp, sizeof(TYPE)); -#define CHECK_INITIALIZED \ - if (!config_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ - return; \ - } +#define CHECK_INITIALIZED \ + if (!config_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ + return; \ + } -#define CHECK_NOT_INITIALIZED \ - if (config_isInitialized()) { \ - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ - return; \ - } +#define CHECK_NOT_INITIALIZED \ + if (config_isInitialized()) { \ + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, \ + _("Device is already initialized. Use Wipe first.")); \ + return; \ + } -#define CHECK_PIN \ - if (!protectPin(true)) { \ - layoutHome(); \ - return; \ - } +#define CHECK_PIN \ + if (!protectPin(true)) { \ + layoutHome(); \ + return; \ + } -#define CHECK_PIN_UNCACHED \ - if (!protectPin(false)) { \ - layoutHome(); \ - return; \ - } +#define CHECK_PIN_UNCACHED \ + if (!protectPin(false)) { \ + layoutHome(); \ + return; \ + } -#define CHECK_PARAM(cond, errormsg) \ - if (!(cond)) { \ - fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ - layoutHome(); \ - return; \ - } +#define CHECK_PARAM(cond, errormsg) \ + if (!(cond)) { \ + fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ + layoutHome(); \ + return; \ + } -void fsm_sendSuccess(const char *text) -{ - RESP_INIT(Success); - if (text) { - resp->has_message = true; - strlcpy(resp->message, text, sizeof(resp->message)); - } - msg_write(MessageType_MessageType_Success, resp); +void fsm_sendSuccess(const char *text) { + RESP_INIT(Success); + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Success, resp); } #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) +void fsm_sendFailureDebug(FailureType code, const char *text, + const char *source) #else void fsm_sendFailure(FailureType code, const char *text) #endif { - if (protectAbortedByCancel) { - protectAbortedByCancel = false; - } - if (protectAbortedByInitialize) { - fsm_msgInitialize((Initialize *)0); - protectAbortedByInitialize = false; - return; - } - RESP_INIT(Failure); - resp->has_code = true; - resp->code = code; - if (!text) { - switch (code) { - case FailureType_Failure_UnexpectedMessage: - text = _("Unexpected message"); - break; - case FailureType_Failure_ButtonExpected: - text = _("Button expected"); - break; - case FailureType_Failure_DataError: - text = _("Data error"); - break; - case FailureType_Failure_ActionCancelled: - text = _("Action cancelled by user"); - break; - case FailureType_Failure_PinExpected: - text = _("PIN expected"); - break; - case FailureType_Failure_PinCancelled: - text = _("PIN cancelled"); - break; - case FailureType_Failure_PinInvalid: - text = _("PIN invalid"); - break; - case FailureType_Failure_InvalidSignature: - text = _("Invalid signature"); - break; - case FailureType_Failure_ProcessError: - text = _("Process error"); - break; - case FailureType_Failure_NotEnoughFunds: - text = _("Not enough funds"); - break; - case FailureType_Failure_NotInitialized: - text = _("Device not initialized"); - break; - case FailureType_Failure_PinMismatch: - text = _("PIN mismatch"); - break; - case FailureType_Failure_FirmwareError: - text = _("Firmware error"); - break; - } - } + if (protectAbortedByCancel) { + protectAbortedByCancel = false; + } + if (protectAbortedByInitialize) { + fsm_msgInitialize((Initialize *)0); + protectAbortedByInitialize = false; + return; + } + RESP_INIT(Failure); + resp->has_code = true; + resp->code = code; + if (!text) { + switch (code) { + case FailureType_Failure_UnexpectedMessage: + text = _("Unexpected message"); + break; + case FailureType_Failure_ButtonExpected: + text = _("Button expected"); + break; + case FailureType_Failure_DataError: + text = _("Data error"); + break; + case FailureType_Failure_ActionCancelled: + text = _("Action cancelled by user"); + break; + case FailureType_Failure_PinExpected: + text = _("PIN expected"); + break; + case FailureType_Failure_PinCancelled: + text = _("PIN cancelled"); + break; + case FailureType_Failure_PinInvalid: + text = _("PIN invalid"); + break; + case FailureType_Failure_InvalidSignature: + text = _("Invalid signature"); + break; + case FailureType_Failure_ProcessError: + text = _("Process error"); + break; + case FailureType_Failure_NotEnoughFunds: + text = _("Not enough funds"); + break; + case FailureType_Failure_NotInitialized: + text = _("Device not initialized"); + break; + case FailureType_Failure_PinMismatch: + text = _("PIN mismatch"); + break; + case FailureType_Failure_FirmwareError: + text = _("Firmware error"); + break; + } + } #if DEBUG_LINK - resp->has_message = true; - strlcpy(resp->message, source, sizeof(resp->message)); - if (text) { - strlcat(resp->message, text, sizeof(resp->message)); - } + resp->has_message = true; + strlcpy(resp->message, source, sizeof(resp->message)); + if (text) { + strlcat(resp->message, text, sizeof(resp->message)); + } #else - if (text) { - resp->has_message = true; - strlcpy(resp->message, text, sizeof(resp->message)); - } + if (text) { + resp->has_message = true; + strlcpy(resp->message, text, sizeof(resp->message)); + } #endif - msg_write(MessageType_MessageType_Failure, resp); + msg_write(MessageType_MessageType_Failure, resp); } -static const CoinInfo *fsm_getCoin(bool has_name, const char *name) -{ - const CoinInfo *coin; - if (has_name) { - coin = coinByName(name); - } else { - coin = coinByName("Bitcoin"); - } - if (!coin) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); - layoutHome(); - return 0; - } - return coin; +static const CoinInfo *fsm_getCoin(bool has_name, const char *name) { + const CoinInfo *coin; + if (has_name) { + coin = coinByName(name); + } else { + coin = coinByName("Bitcoin"); + } + if (!coin) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); + layoutHome(); + return 0; + } + return coin; } -static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) -{ - static CONFIDENTIAL HDNode node; - if (fingerprint) { - *fingerprint = 0; - } - if (!config_getRootNode(&node, curve, true)) { - fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); - layoutHome(); - return 0; - } - if (!address_n || address_n_count == 0) { - return &node; - } - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); - layoutHome(); - return 0; - } - return &node; +static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, + size_t address_n_count, + uint32_t *fingerprint) { + static CONFIDENTIAL HDNode node; + if (fingerprint) { + *fingerprint = 0; + } + if (!config_getRootNode(&node, curve, true)) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + _("Device not initialized or passphrase request cancelled " + "or unsupported curve")); + layoutHome(); + return 0; + } + if (!address_n || address_n_count == 0) { + return &node; + } + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, + fingerprint) == 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to derive private key")); + layoutHome(); + return 0; + } + return &node; } -static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, size_t prefixlen, const uint32_t *address_n, size_t address_n_count, bool address_is_account) -{ - bool qrcode = false; - for (;;) { - const char* display_addr = address; - if (prefixlen && !qrcode) { - display_addr += prefixlen; - } - layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count, address_is_account); - if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { - return true; - } - if (protectAbortedByCancel || protectAbortedByInitialize) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return false; - } - qrcode = !qrcode; - } +static bool fsm_layoutAddress(const char *address, const char *desc, + bool ignorecase, size_t prefixlen, + const uint32_t *address_n, size_t address_n_count, + bool address_is_account) { + bool qrcode = false; + for (;;) { + const char *display_addr = address; + if (prefixlen && !qrcode) { + display_addr += prefixlen; + } + layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, + address_n_count, address_is_account); + if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { + return true; + } + if (protectAbortedByCancel || protectAbortedByInitialize) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return false; + } + qrcode = !qrcode; + } } -#include "fsm_msg_common.h" #include "fsm_msg_coin.h" -#include "fsm_msg_ethereum.h" +#include "fsm_msg_common.h" #include "fsm_msg_crypto.h" +#include "fsm_msg_debug.h" +#include "fsm_msg_ethereum.h" +#include "fsm_msg_lisk.h" #include "fsm_msg_nem.h" #include "fsm_msg_stellar.h" -#include "fsm_msg_lisk.h" -#include "fsm_msg_debug.h" diff --git a/firmware/fsm.h b/firmware/fsm.h index 4a8e53b38f..d4cde689b7 100644 --- a/firmware/fsm.h +++ b/firmware/fsm.h @@ -24,19 +24,21 @@ #include "messages-crypto.pb.h" #include "messages-debug.pb.h" #include "messages-ethereum.pb.h" +#include "messages-lisk.pb.h" #include "messages-management.pb.h" #include "messages-nem.pb.h" #include "messages-stellar.pb.h" -#include "messages-lisk.pb.h" // message functions void fsm_sendSuccess(const char *text); #if DEBUG_LINK -void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); +void fsm_sendFailureDebug(FailureType code, const char *text, + const char *source); -#define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") +#define fsm_sendFailure(code, text) \ + fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") #else void fsm_sendFailure(FailureType code, const char *text); #endif @@ -67,7 +69,8 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg); // coin void fsm_msgGetPublicKey(const GetPublicKey *msg); void fsm_msgSignTx(const SignTx *msg); -void fsm_msgTxAck(TxAck *msg); // not const because we mutate input/output scripts +void fsm_msgTxAck( + TxAck *msg); // not const because we mutate input/output scripts void fsm_msgGetAddress(const GetAddress *msg); void fsm_msgSignMessage(const SignMessage *msg); void fsm_msgVerifyMessage(const VerifyMessage *msg); @@ -92,7 +95,9 @@ void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg); // ethereum void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg); void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg); -void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction during validation +void fsm_msgEthereumSignTx( + EthereumSignTx + *msg); // not const because we mutate transaction during validation void fsm_msgEthereumTxAck(const EthereumTxAck *msg); void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg); void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg); @@ -102,12 +107,16 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg); void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg); void fsm_msgLiskSignMessage(const LiskSignMessage *msg); void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg); -void fsm_msgLiskSignTx(LiskSignTx *msg); // not const because we mutate transaction during validation +void fsm_msgLiskSignTx(LiskSignTx *msg); // not const because we mutate + // transaction during validation // nem -void fsm_msgNEMGetAddress(NEMGetAddress *msg); // not const because we mutate msg->network -void fsm_msgNEMSignTx(NEMSignTx *msg); // not const because we mutate msg->network -void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); // not const because we mutate msg->payload +void fsm_msgNEMGetAddress( + NEMGetAddress *msg); // not const because we mutate msg->network +void fsm_msgNEMSignTx( + NEMSignTx *msg); // not const because we mutate msg->network +void fsm_msgNEMDecryptMessage( + NEMDecryptMessage *msg); // not const because we mutate msg->payload // stellar void fsm_msgStellarGetAddress(const StellarGetAddress *msg); diff --git a/firmware/fsm_msg_coin.h b/firmware/fsm_msg_coin.h index 7e07cadcce..30b5e1747e 100644 --- a/firmware/fsm_msg_coin.h +++ b/firmware/fsm_msg_coin.h @@ -17,296 +17,313 @@ * along with this library. If not, see . */ -void fsm_msgGetPublicKey(const GetPublicKey *msg) -{ - RESP_INIT(PublicKey); +void fsm_msgGetPublicKey(const GetPublicKey *msg) { + RESP_INIT(PublicKey); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; + InputScriptType script_type = + msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; - const char *curve = coin->curve_name; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - uint32_t fingerprint; - HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); - if (!node) return; - hdnode_fill_public_key(node); + const char *curve = coin->curve_name; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + uint32_t fingerprint; + HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, + msg->address_n_count, &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); - if (msg->has_show_display && msg->show_display) { - layoutPublicKey(node->public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_show_display && msg->show_display) { + layoutPublicKey(node->public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - resp->has_node = true; - resp->node.depth = node->depth; - resp->node.fingerprint = fingerprint; - resp->node.child_num = node->child_num; - resp->node.chain_code.size = 32; - memcpy(resp->node.chain_code.bytes, node->chain_code, 32); - resp->node.has_private_key = false; - resp->node.has_public_key = true; - resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->node.public_key.bytes[0] = 0; - } + resp->has_node = true; + resp->node.depth = node->depth; + resp->node.fingerprint = fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->node.public_key.bytes[0] = 0; + } - resp->has_xpub = true; - if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); - } else - if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, resp->xpub, sizeof(resp->xpub)); - } else - if (coin->has_segwit && coin->xpub_magic_segwit_native && script_type == InputScriptType_SPENDWITNESS) { - hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, resp->xpub, sizeof(resp->xpub)); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid combination of coin and script_type")); - layoutHome(); - return; - } + resp->has_xpub = true; + if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || + script_type == InputScriptType_SPENDMULTISIG)) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, + sizeof(resp->xpub)); + } else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && + script_type == InputScriptType_SPENDP2SHWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, + resp->xpub, sizeof(resp->xpub)); + } else if (coin->has_segwit && coin->xpub_magic_segwit_native && + script_type == InputScriptType_SPENDWITNESS) { + hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, + resp->xpub, sizeof(resp->xpub)); + } else { + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid combination of coin and script_type")); + layoutHome(); + return; + } - msg_write(MessageType_MessageType_PublicKey, resp); - layoutHome(); + msg_write(MessageType_MessageType_PublicKey, resp); + layoutHome(); } -void fsm_msgSignTx(const SignTx *msg) -{ - CHECK_INITIALIZED +void fsm_msgSignTx(const SignTx *msg) { + CHECK_INITIALIZED - CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); - CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); - CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); + CHECK_PARAM(msg->inputs_count > 0, + _("Transaction must have at least one input")); + CHECK_PARAM(msg->outputs_count > 0, + _("Transaction must have at least one output")); + CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, + _("Value overflow")); - CHECK_PIN + CHECK_PIN - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); - if (!node) return; + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); + if (!node) return; - signing_init(msg, coin, node); + signing_init(msg, coin, node); } -void fsm_msgTxAck(TxAck *msg) -{ - CHECK_PARAM(msg->has_tx, _("No transaction provided")); +void fsm_msgTxAck(TxAck *msg) { + CHECK_PARAM(msg->has_tx, _("No transaction provided")); - signing_txack(&(msg->tx)); + signing_txack(&(msg->tx)); } -static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) -{ - bool mismatch = false; +static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) { + bool mismatch = false; - // m : no path - if (msg->address_n_count == 0) { - return false; - } + // m : no path + if (msg->address_n_count == 0) { + return false; + } - // m/44' : BIP44 Legacy - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 44)) { - mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } + // m/44' : BIP44 Legacy + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 44)) { + mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } - // m/45' - BIP45 Copay Abandoned Multisig P2SH - // m / purpose' / cosigner_index / change / address_index - if (msg->address_n[0] == (0x80000000 + 45)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count != 4); - mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - return mismatch; - } + // m/45' - BIP45 Copay Abandoned Multisig P2SH + // m / purpose' / cosigner_index / change / address_index + if (msg->address_n[0] == (0x80000000 + 45)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count != 4); + mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + return mismatch; + } - // m/48' - BIP48 Copay Multisig P2SH - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 48)) { - mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } + // m/48' - BIP48 Copay Multisig P2SH + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 48)) { + mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } - // m/49' : BIP49 SegWit - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 49)) { - mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); - mismatch |= !coin->has_segwit; - mismatch |= !coin->has_address_type_p2sh; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } + // m/49' : BIP49 SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 49)) { + mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->has_address_type_p2sh; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } - // m/84' : BIP84 Native SegWit - // m / purpose' / coin_type' / account' / change / address_index - if (msg->address_n[0] == (0x80000000 + 84)) { - mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); - mismatch |= !coin->has_segwit; - mismatch |= !coin->bech32_prefix; - mismatch |= (msg->address_n_count != 5); - mismatch |= (msg->address_n[1] != coin->coin_type); - mismatch |= (msg->address_n[2] & 0x80000000) == 0; - mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; - mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; - return mismatch; - } + // m/84' : BIP84 Native SegWit + // m / purpose' / coin_type' / account' / change / address_index + if (msg->address_n[0] == (0x80000000 + 84)) { + mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); + mismatch |= !coin->has_segwit; + mismatch |= !coin->bech32_prefix; + mismatch |= (msg->address_n_count != 5); + mismatch |= (msg->address_n[1] != coin->coin_type); + mismatch |= (msg->address_n[2] & 0x80000000) == 0; + mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; + mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; + return mismatch; + } - return false; + return false; } -void fsm_msgGetAddress(const GetAddress *msg) -{ - RESP_INIT(Address); +void fsm_msgGetAddress(const GetAddress *msg) { + RESP_INIT(Address); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; - hdnode_fill_public_key(node); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; + hdnode_fill_public_key(node); - char address[MAX_ADDR_SIZE]; - if (msg->has_multisig) { // use progress bar only for multisig - layoutProgress(_("Computing address"), 0); - } - if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); - layoutHome(); - return; - } + char address[MAX_ADDR_SIZE]; + if (msg->has_multisig) { // use progress bar only for multisig + layoutProgress(_("Computing address"), 0); + } + if (!compute_address(coin, msg->script_type, node, msg->has_multisig, + &msg->multisig, address)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); + layoutHome(); + return; + } - if (msg->has_show_display && msg->show_display) { - char desc[20]; - if (msg->has_multisig) { - strlcpy(desc, "Multisig __ of __:", sizeof(desc)); - const uint32_t m = msg->multisig.m; - const uint32_t n = msg->multisig.pubkeys_count; - desc[9] = (m < 10) ? ' ': ('0' + (m / 10)); - desc[10] = '0' + (m % 10); - desc[15] = (n < 10) ? ' ': ('0' + (n / 10)); - desc[16] = '0' + (n % 10); - } else { - strlcpy(desc, _("Address:"), sizeof(desc)); - } + if (msg->has_show_display && msg->show_display) { + char desc[20]; + if (msg->has_multisig) { + strlcpy(desc, "Multisig __ of __:", sizeof(desc)); + const uint32_t m = msg->multisig.m; + const uint32_t n = msg->multisig.pubkeys_count; + desc[9] = (m < 10) ? ' ' : ('0' + (m / 10)); + desc[10] = '0' + (m % 10); + desc[15] = (n < 10) ? ' ' : ('0' + (n / 10)); + desc[16] = '0' + (n % 10); + } else { + strlcpy(desc, _("Address:"), sizeof(desc)); + } - bool mismatch = path_mismatched(coin, msg); + bool mismatch = path_mismatched(coin, msg); - if (mismatch) { - layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (mismatch) { + layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, + _("Wrong address path"), _("for selected coin."), NULL, + _("Continue at your"), _("own risk!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - bool is_cashaddr = coin->cashaddr_prefix != NULL; - bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; - if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count, false)) { - return; - } - } + bool is_cashaddr = coin->cashaddr_prefix != NULL; + bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; + if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, + is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, + msg->address_n, msg->address_n_count, false)) { + return; + } + } - strlcpy(resp->address, address, sizeof(resp->address)); - msg_write(MessageType_MessageType_Address, resp); - layoutHome(); + strlcpy(resp->address, address, sizeof(resp->address)); + msg_write(MessageType_MessageType_Address, resp); + layoutHome(); } -void fsm_msgSignMessage(const SignMessage *msg) -{ - // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings")); +void fsm_msgSignMessage(const SignMessage *msg) { + // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot + // sign non-ASCII strings")); - RESP_INIT(MessageSignature); + RESP_INIT(MessageSignature); - CHECK_INITIALIZED + CHECK_INITIALIZED - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - layoutProgressSwipe(_("Signing"), 0); - if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { - resp->has_address = true; - hdnode_fill_public_key(node); - if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); - layoutHome(); - return; - } - resp->has_signature = true; - resp->signature.size = 65; - msg_write(MessageType_MessageType_MessageSignature, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); - } - layoutHome(); + layoutProgressSwipe(_("Signing"), 0); + if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, + msg->message.size, resp->signature.bytes) == 0) { + resp->has_address = true; + hdnode_fill_public_key(node); + if (!compute_address(coin, msg->script_type, node, false, NULL, + resp->address)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Error computing address")); + layoutHome(); + return; + } + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_MessageSignature, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Error signing message")); + } + layoutHome(); } -void fsm_msgVerifyMessage(const VerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); +void fsm_msgVerifyMessage(const VerifyMessage *msg) { + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); - const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); - if (!coin) return; - layoutProgressSwipe(_("Verifying"), 0); - if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { - layoutVerifyAddress(coin, msg->address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - } - layoutHome(); + const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); + if (!coin) return; + layoutProgressSwipe(_("Verifying"), 0); + if (msg->signature.size == 65 && + cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, + msg->address, msg->signature.bytes) == 0) { + layoutVerifyAddress(coin, msg->address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + } + layoutHome(); } diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 96da11d830..265b629d40 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -17,364 +17,396 @@ * along with this library. If not, see . */ -void fsm_msgInitialize(const Initialize *msg) -{ - recovery_abort(); - signing_abort(); - if (msg && msg->has_state && msg->state.size == 64) { - uint8_t i_state[64]; - if (!session_getState(msg->state.bytes, i_state, NULL)) { - session_clear(false); // do not clear PIN - } else { - if (0 != memcmp(msg->state.bytes, i_state, 64)) { - session_clear(false); // do not clear PIN - } - } - } else { - session_clear(false); // do not clear PIN - } - layoutHome(); - fsm_msgGetFeatures(0); +void fsm_msgInitialize(const Initialize *msg) { + recovery_abort(); + signing_abort(); + if (msg && msg->has_state && msg->state.size == 64) { + uint8_t i_state[64]; + if (!session_getState(msg->state.bytes, i_state, NULL)) { + session_clear(false); // do not clear PIN + } else { + if (0 != memcmp(msg->state.bytes, i_state, 64)) { + session_clear(false); // do not clear PIN + } + } + } else { + session_clear(false); // do not clear PIN + } + layoutHome(); + fsm_msgGetFeatures(0); } -void fsm_msgGetFeatures(const GetFeatures *msg) -{ - (void)msg; - RESP_INIT(Features); - resp->has_vendor = true; strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor)); - resp->has_major_version = true; resp->major_version = VERSION_MAJOR; - resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; - resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; - resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); - resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); - resp->has_passphrase_protection = true; config_getPassphraseProtection(&(resp->passphrase_protection)); +void fsm_msgGetFeatures(const GetFeatures *msg) { + (void)msg; + RESP_INIT(Features); + resp->has_vendor = true; + strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor)); + resp->has_major_version = true; + resp->major_version = VERSION_MAJOR; + resp->has_minor_version = true; + resp->minor_version = VERSION_MINOR; + resp->has_patch_version = true; + resp->patch_version = VERSION_PATCH; + resp->has_device_id = true; + strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); + resp->has_pin_protection = true; + resp->pin_protection = config_hasPin(); + resp->has_passphrase_protection = true; + config_getPassphraseProtection(&(resp->passphrase_protection)); #ifdef SCM_REVISION - int len = sizeof(SCM_REVISION) - 1; - resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; + int len = sizeof(SCM_REVISION) - 1; + resp->has_revision = true; + memcpy(resp->revision.bytes, SCM_REVISION, len); + resp->revision.size = len; #endif - resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); + resp->has_bootloader_hash = true; + resp->bootloader_hash.size = + memory_bootloader_hash(resp->bootloader_hash.bytes); - resp->has_language = config_getLanguage(resp->language, sizeof(resp->language)); - resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); - resp->has_initialized = true; resp->initialized = config_isInitialized(); - resp->has_imported = config_getImported(&(resp->imported)); - resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); - resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; config_getNeedsBackup(&(resp->needs_backup)); - resp->has_unfinished_backup = true; config_getUnfinishedBackup(&(resp->unfinished_backup)); - resp->has_no_backup = true; config_getNoBackup(&(resp->no_backup)); - resp->has_flags = config_getFlags(&(resp->flags)); - resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); + resp->has_language = + config_getLanguage(resp->language, sizeof(resp->language)); + resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); + resp->has_initialized = true; + resp->initialized = config_isInitialized(); + resp->has_imported = config_getImported(&(resp->imported)); + resp->has_pin_cached = true; + resp->pin_cached = session_isUnlocked() && config_hasPin(); + resp->has_passphrase_cached = true; + resp->passphrase_cached = session_isPassphraseCached(); + resp->has_needs_backup = true; + config_getNeedsBackup(&(resp->needs_backup)); + resp->has_unfinished_backup = true; + config_getUnfinishedBackup(&(resp->unfinished_backup)); + resp->has_no_backup = true; + config_getNoBackup(&(resp->no_backup)); + resp->has_flags = config_getFlags(&(resp->flags)); + resp->has_model = true; + strlcpy(resp->model, "1", sizeof(resp->model)); - msg_write(MessageType_MessageType_Features, resp); + msg_write(MessageType_MessageType_Features, resp); } -void fsm_msgPing(const Ping *msg) -{ - RESP_INIT(Success); +void fsm_msgPing(const Ping *msg) { + RESP_INIT(Success); - if (msg->has_button_protection && msg->button_protection) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_button_protection && msg->button_protection) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("answer to ping?"), NULL, + NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (msg->has_pin_protection && msg->pin_protection) { - CHECK_PIN - } + if (msg->has_pin_protection && msg->pin_protection) { + CHECK_PIN + } - if (msg->has_passphrase_protection && msg->passphrase_protection) { - if (!protectPassphrase()) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - return; - } - } + if (msg->has_passphrase_protection && msg->passphrase_protection) { + if (!protectPassphrase()) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return; + } + } - if (msg->has_message) { - resp->has_message = true; - memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); - } - msg_write(MessageType_MessageType_Success, resp); - layoutHome(); + if (msg->has_message) { + resp->has_message = true; + memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); + } + msg_write(MessageType_MessageType_Success, resp); + layoutHome(); } -void fsm_msgChangePin(const ChangePin *msg) -{ - bool removal = msg->has_remove && msg->remove; - if (removal) { - if (config_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); - } else { - fsm_sendSuccess(_("PIN removed")); - return; - } - } else { - if (config_hasPin()) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); - } else { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); - } - } - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } +void fsm_msgChangePin(const ChangePin *msg) { + bool removal = msg->has_remove && msg->remove; + if (removal) { + if (config_hasPin()) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("remove current PIN?"), + NULL, NULL, NULL, NULL); + } else { + fsm_sendSuccess(_("PIN removed")); + return; + } + } else { + if (config_hasPin()) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change current PIN?"), + NULL, NULL, NULL, NULL); + } else { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("set new PIN?"), NULL, + NULL, NULL, NULL); + } + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - if (protectChangePin(removal)) { - if (removal) { - fsm_sendSuccess(_("PIN removed")); - } else { - fsm_sendSuccess(_("PIN changed")); - } - } + if (protectChangePin(removal)) { + if (removal) { + fsm_sendSuccess(_("PIN removed")); + } else { + fsm_sendSuccess(_("PIN changed")); + } + } - layoutHome(); + layoutHome(); } -void fsm_msgWipeDevice(const WipeDevice *msg) -{ - (void)msg; - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - config_wipe(); - // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed - // usbReconnect(); // force re-enumeration because of the serial number change - fsm_sendSuccess(_("Device wiped")); - layoutHome(); +void fsm_msgWipeDevice(const WipeDevice *msg) { + (void)msg; + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("wipe the device?"), NULL, + _("All data will be lost."), NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + config_wipe(); + // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it + // is not needed usbReconnect(); // force re-enumeration because of the serial + // number change + fsm_sendSuccess(_("Device wiped")); + layoutHome(); } -void fsm_msgGetEntropy(const GetEntropy *msg) -{ +void fsm_msgGetEntropy(const GetEntropy *msg) { #if !DEBUG_RNG - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("send entropy?"), NULL, NULL, + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } #endif - RESP_INIT(Entropy); - uint32_t len = msg->size; - if (len > 1024) { - len = 1024; - } - resp->entropy.size = len; - random_buffer(resp->entropy.bytes, len); - msg_write(MessageType_MessageType_Entropy, resp); - layoutHome(); + RESP_INIT(Entropy); + uint32_t len = msg->size; + if (len > 1024) { + len = 1024; + } + resp->entropy.size = len; + random_buffer(resp->entropy.bytes, len); + msg_write(MessageType_MessageType_Entropy, resp); + layoutHome(); } -void fsm_msgLoadDevice(const LoadDevice *msg) -{ - CHECK_PIN +void fsm_msgLoadDevice(const LoadDevice *msg) { + CHECK_PIN - CHECK_NOT_INITIALIZED + CHECK_NOT_INITIALIZED - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, + _("Loading private seed"), _("is not recommended."), + _("Continue only if you"), _("know what you are"), + _("doing!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { - if (!mnemonic_check(msg->mnemonic)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); - layoutHome(); - return; - } - } + if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) { + if (!mnemonic_check(msg->mnemonic)) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Mnemonic with wrong checksum provided")); + layoutHome(); + return; + } + } - config_loadDevice(msg); - fsm_sendSuccess(_("Device loaded")); - layoutHome(); + config_loadDevice(msg); + fsm_sendSuccess(_("Device loaded")); + layoutHome(); } -void fsm_msgResetDevice(const ResetDevice *msg) -{ - CHECK_PIN +void fsm_msgResetDevice(const ResetDevice *msg) { + CHECK_PIN - CHECK_NOT_INITIALIZED + CHECK_NOT_INITIALIZED - CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); + CHECK_PARAM(!msg->has_strength || msg->strength == 128 || + msg->strength == 192 || msg->strength == 256, + _("Invalid seed strength")); - reset_init( - msg->has_display_random && msg->display_random, - msg->has_strength ? msg->strength : 128, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0, - msg->has_skip_backup ? msg->skip_backup : false, - msg->has_no_backup ? msg->no_backup : false - ); + reset_init(msg->has_display_random && msg->display_random, + msg->has_strength ? msg->strength : 128, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_u2f_counter ? msg->u2f_counter : 0, + msg->has_skip_backup ? msg->skip_backup : false, + msg->has_no_backup ? msg->no_backup : false); } -void fsm_msgEntropyAck(const EntropyAck *msg) -{ - if (msg->has_entropy) { - reset_entropy(msg->entropy.bytes, msg->entropy.size); - } else { - reset_entropy(0, 0); - } +void fsm_msgEntropyAck(const EntropyAck *msg) { + if (msg->has_entropy) { + reset_entropy(msg->entropy.bytes, msg->entropy.size); + } else { + reset_entropy(0, 0); + } } -void fsm_msgBackupDevice(const BackupDevice *msg) -{ - CHECK_INITIALIZED +void fsm_msgBackupDevice(const BackupDevice *msg) { + CHECK_INITIALIZED - CHECK_PIN_UNCACHED + CHECK_PIN_UNCACHED - (void)msg; - char mnemonic[MAX_MNEMONIC_LEN + 1]; - if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { - reset_backup(true, mnemonic); - } - memzero(mnemonic, sizeof(mnemonic)); + (void) + msg; + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + reset_backup(true, mnemonic); + } + memzero(mnemonic, sizeof(mnemonic)); } -void fsm_msgCancel(const Cancel *msg) -{ - (void)msg; - recovery_abort(); - signing_abort(); - ethereum_signing_abort(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); +void fsm_msgCancel(const Cancel *msg) { + (void)msg; + recovery_abort(); + signing_abort(); + ethereum_signing_abort(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } -void fsm_msgClearSession(const ClearSession *msg) -{ - (void)msg; - session_clear(true); // clear PIN as well - layoutScreensaver(); - fsm_sendSuccess(_("Session cleared")); +void fsm_msgClearSession(const ClearSession *msg) { + (void)msg; + session_clear(true); // clear PIN as well + layoutScreensaver(); + fsm_sendSuccess(_("Session cleared")); } -void fsm_msgApplySettings(const ApplySettings *msg) -{ - CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, - _("No setting provided")); +void fsm_msgApplySettings(const ApplySettings *msg) { + CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || + msg->has_homescreen || msg->has_auto_lock_delay_ms, + _("No setting provided")); - CHECK_PIN + CHECK_PIN - if (msg->has_label) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_language) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_use_passphrase) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } - if (msg->has_homescreen) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_label) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change name to"), + msg->label, "?", NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_language) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change language to"), + msg->language, "?", NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_use_passphrase) { + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), + msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), + _("protection?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + if (msg->has_homescreen) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change the home"), + _("screen?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (msg->has_auto_lock_delay_ms) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_auto_lock_delay_ms) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change auto-lock"), + _("delay?"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (msg->has_label) { - config_setLabel(msg->label); - } - if (msg->has_language) { - config_setLanguage(msg->language); - } - if (msg->has_use_passphrase) { - config_setPassphraseProtection(msg->use_passphrase); - } - if (msg->has_homescreen) { - config_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); - } - if (msg->has_auto_lock_delay_ms) { - config_setAutoLockDelayMs(msg->auto_lock_delay_ms); - } - fsm_sendSuccess(_("Settings applied")); - layoutHome(); + if (msg->has_label) { + config_setLabel(msg->label); + } + if (msg->has_language) { + config_setLanguage(msg->language); + } + if (msg->has_use_passphrase) { + config_setPassphraseProtection(msg->use_passphrase); + } + if (msg->has_homescreen) { + config_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); + } + if (msg->has_auto_lock_delay_ms) { + config_setAutoLockDelayMs(msg->auto_lock_delay_ms); + } + fsm_sendSuccess(_("Settings applied")); + layoutHome(); } -void fsm_msgApplyFlags(const ApplyFlags *msg) -{ - CHECK_PIN +void fsm_msgApplyFlags(const ApplyFlags *msg) { + CHECK_PIN - if (msg->has_flags) { - config_applyFlags(msg->flags); - } - fsm_sendSuccess(_("Flags applied")); + if (msg->has_flags) { + config_applyFlags(msg->flags); + } + fsm_sendSuccess(_("Flags applied")); } -void fsm_msgRecoveryDevice(const RecoveryDevice *msg) -{ - CHECK_PIN_UNCACHED +void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { + CHECK_PIN_UNCACHED - const bool dry_run = msg->has_dry_run ? msg->dry_run : false; - if (!dry_run) { - CHECK_NOT_INITIALIZED - } + const bool dry_run = msg->has_dry_run ? msg->dry_run : false; + if (!dry_run) { + CHECK_NOT_INITIALIZED + } - CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); + CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || + msg->word_count == 18 || msg->word_count == 24, + _("Invalid word count")); - recovery_init( - msg->has_word_count ? msg->word_count : 12, - msg->has_passphrase_protection && msg->passphrase_protection, - msg->has_pin_protection && msg->pin_protection, - msg->has_language ? msg->language : 0, - msg->has_label ? msg->label : 0, - msg->has_enforce_wordlist && msg->enforce_wordlist, - msg->has_type ? msg->type : 0, - msg->has_u2f_counter ? msg->u2f_counter : 0, - dry_run - ); + recovery_init(msg->has_word_count ? msg->word_count : 12, + msg->has_passphrase_protection && msg->passphrase_protection, + msg->has_pin_protection && msg->pin_protection, + msg->has_language ? msg->language : 0, + msg->has_label ? msg->label : 0, + msg->has_enforce_wordlist && msg->enforce_wordlist, + msg->has_type ? msg->type : 0, + msg->has_u2f_counter ? msg->u2f_counter : 0, dry_run); } -void fsm_msgWordAck(const WordAck *msg) -{ - recovery_word(msg->word); -} +void fsm_msgWordAck(const WordAck *msg) { recovery_word(msg->word); } -void fsm_msgSetU2FCounter(const SetU2FCounter *msg) -{ - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - config_setU2FCounter(msg->u2f_counter); - fsm_sendSuccess(_("U2F counter set")); - layoutHome(); +void fsm_msgSetU2FCounter(const SetU2FCounter *msg) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you want to set"), _("the U2F counter?"), NULL, NULL, + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + config_setU2FCounter(msg->u2f_counter); + fsm_sendSuccess(_("U2F counter set")); + layoutHome(); } diff --git a/firmware/fsm_msg_crypto.h b/firmware/fsm_msg_crypto.h index b6cc5329ee..ed07840171 100644 --- a/firmware/fsm_msg_crypto.h +++ b/firmware/fsm_msg_crypto.h @@ -17,254 +17,283 @@ * along with this library. If not, see . */ -void fsm_msgCipherKeyValue(const CipherKeyValue *msg) -{ - CHECK_INITIALIZED +void fsm_msgCipherKeyValue(const CipherKeyValue *msg) { + CHECK_INITIALIZED - CHECK_PARAM(msg->has_key, _("No key provided")); - CHECK_PARAM(msg->has_value, _("No value provided")); - CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); + CHECK_PARAM(msg->has_key, _("No key provided")); + CHECK_PARAM(msg->has_value, _("No value provided")); + CHECK_PARAM(msg->value.size % 16 == 0, + _("Value length must be a multiple of 16")); - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - bool encrypt = msg->has_encrypt && msg->encrypt; - bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; - bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; - if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { - layoutCipherKeyValue(encrypt, msg->key); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + bool encrypt = msg->has_encrypt && msg->encrypt; + bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; + bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; + if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { + layoutCipherKeyValue(encrypt, msg->key); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - uint8_t data[256 + 4]; - strlcpy((char *)data, msg->key, sizeof(data)); - strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); - strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); + uint8_t data[256 + 4]; + strlcpy((char *)data, msg->key, sizeof(data)); + strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); + strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); - hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); + hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); - if (msg->iv.size == 16) { - // override iv if provided - memcpy(data + 32, msg->iv.bytes, 16); - } + if (msg->iv.size == 16) { + // override iv if provided + memcpy(data + 32, msg->iv.bytes, 16); + } - RESP_INIT(CipheredKeyValue); - if (encrypt) { - aes_encrypt_ctx ctx; - aes_encrypt_key256(data, &ctx); - aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); - } else { - aes_decrypt_ctx ctx; - aes_decrypt_key256(data, &ctx); - aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); - } - resp->has_value = true; - resp->value.size = msg->value.size; - msg_write(MessageType_MessageType_CipheredKeyValue, resp); - layoutHome(); + RESP_INIT(CipheredKeyValue); + if (encrypt) { + aes_encrypt_ctx ctx; + aes_encrypt_key256(data, &ctx); + aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, + data + 32, &ctx); + } else { + aes_decrypt_ctx ctx; + aes_decrypt_key256(data, &ctx); + aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, + data + 32, &ctx); + } + resp->has_value = true; + resp->value.size = msg->value.size; + msg_write(MessageType_MessageType_CipheredKeyValue, resp); + layoutHome(); } -void fsm_msgSignIdentity(const SignIdentity *msg) -{ - RESP_INIT(SignedIdentity); +void fsm_msgSignIdentity(const SignIdentity *msg) { + RESP_INIT(SignedIdentity); - CHECK_INITIALIZED + CHECK_INITIALIZED - layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutSignIdentity(&(msg->identity), + msg->has_challenge_visual ? msg->challenge_visual : 0); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - uint8_t hash[32]; - if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); - layoutHome(); - return; - } + uint8_t hash[32]; + if (!msg->has_identity || + cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + layoutHome(); + return; + } - uint32_t address_n[5]; - address_n[0] = 0x80000000 | 13; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 13; + address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) | + ((uint32_t)hash[3] << 24); + address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) | + ((uint32_t)hash[7] << 24); + address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) | + ((uint32_t)hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | + ((uint32_t)hash[15] << 24); - const char *curve = SECP256K1_NAME; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } - HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); - if (!node) return; + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } + HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); + if (!node) return; - bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); - bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); + bool sign_ssh = + msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); + bool sign_gpg = + msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); - int result = 0; - layoutProgressSwipe(_("Signing"), 0); - if (sign_ssh) { // SSH does not sign visual challenge - result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); - } else if (sign_gpg) { // GPG should sign a message digest - result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); - } else { - uint8_t digest[64]; - sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); - sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); - result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); - } + int result = 0; + layoutProgressSwipe(_("Signing"), 0); + if (sign_ssh) { // SSH does not sign visual challenge + result = sshMessageSign(node, msg->challenge_hidden.bytes, + msg->challenge_hidden.size, resp->signature.bytes); + } else if (sign_gpg) { // GPG should sign a message digest + result = gpgMessageSign(node, msg->challenge_hidden.bytes, + msg->challenge_hidden.size, resp->signature.bytes); + } else { + uint8_t digest[64]; + sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); + sha256_Raw((const uint8_t *)msg->challenge_visual, + strlen(msg->challenge_visual), digest + 32); + result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, + digest, 64, resp->signature.bytes); + } - if (result == 0) { - hdnode_fill_public_key(node); - if (strcmp(curve, SECP256K1_NAME) != 0) { - resp->has_address = false; - } else { - resp->has_address = true; - hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type - } - resp->has_public_key = true; - resp->public_key.size = 33; - memcpy(resp->public_key.bytes, node->public_key, 33); - if (node->public_key[0] == 1) { - /* ed25519 public key */ - resp->public_key.bytes[0] = 0; - } - resp->has_signature = true; - resp->signature.size = 65; - msg_write(MessageType_MessageType_SignedIdentity, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); - } - layoutHome(); + if (result == 0) { + hdnode_fill_public_key(node); + if (strcmp(curve, SECP256K1_NAME) != 0) { + resp->has_address = false; + } else { + resp->has_address = true; + hdnode_get_address( + node, 0x00, resp->address, + sizeof(resp->address)); // hardcoded Bitcoin address type + } + resp->has_public_key = true; + resp->public_key.size = 33; + memcpy(resp->public_key.bytes, node->public_key, 33); + if (node->public_key[0] == 1) { + /* ed25519 public key */ + resp->public_key.bytes[0] = 0; + } + resp->has_signature = true; + resp->signature.size = 65; + msg_write(MessageType_MessageType_SignedIdentity, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Error signing identity")); + } + layoutHome(); } -void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) -{ - RESP_INIT(ECDHSessionKey); +void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) { + RESP_INIT(ECDHSessionKey); - CHECK_INITIALIZED + CHECK_INITIALIZED - layoutDecryptIdentity(&msg->identity); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutDecryptIdentity(&msg->identity); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - uint8_t hash[32]; - if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); - layoutHome(); - return; - } + uint8_t hash[32]; + if (!msg->has_identity || + cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); + layoutHome(); + return; + } - uint32_t address_n[5]; - address_n[0] = 0x80000000 | 17; - address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); - address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); - address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); - address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); + uint32_t address_n[5]; + address_n[0] = 0x80000000 | 17; + address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) | + ((uint32_t)hash[3] << 24); + address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) | + ((uint32_t)hash[7] << 24); + address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) | + ((uint32_t)hash[11] << 24); + address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | + ((uint32_t)hash[15] << 24); - const char *curve = SECP256K1_NAME; - if (msg->has_ecdsa_curve_name) { - curve = msg->ecdsa_curve_name; - } + const char *curve = SECP256K1_NAME; + if (msg->has_ecdsa_curve_name) { + curve = msg->ecdsa_curve_name; + } - const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); + if (!node) return; - int result_size = 0; - if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { - resp->has_session_key = true; - resp->session_key.size = result_size; - msg_write(MessageType_MessageType_ECDHSessionKey, resp); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); - } - layoutHome(); + int result_size = 0; + if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, + resp->session_key.bytes, &result_size) == 0) { + resp->has_session_key = true; + resp->session_key.size = result_size; + msg_write(MessageType_MessageType_ECDHSessionKey, resp); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Error getting ECDH session key")); + } + layoutHome(); } -void fsm_msgCosiCommit(const CosiCommit *msg) -{ - RESP_INIT(CosiCommitment); +void fsm_msgCosiCommit(const CosiCommit *msg) { + RESP_INIT(CosiCommitment); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PARAM(msg->has_data, _("No data provided")); + CHECK_PARAM(msg->has_data, _("No data provided")); - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, + msg->data.size, false); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, &rng); - generate_rfc6979(nonce, &rng); + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); - resp->has_commitment = true; - resp->has_pubkey = true; - resp->commitment.size = 32; - resp->pubkey.size = 32; + resp->has_commitment = true; + resp->has_pubkey = true; + resp->commitment.size = 32; + resp->pubkey.size = 32; - ed25519_publickey(nonce, resp->commitment.bytes); - ed25519_publickey(node->private_key, resp->pubkey.bytes); + ed25519_publickey(nonce, resp->commitment.bytes); + ed25519_publickey(node->private_key, resp->pubkey.bytes); - msg_write(MessageType_MessageType_CosiCommitment, resp); - layoutHome(); + msg_write(MessageType_MessageType_CosiCommitment, resp); + layoutHome(); } -void fsm_msgCosiSign(const CosiSign *msg) -{ - RESP_INIT(CosiSignature); +void fsm_msgCosiSign(const CosiSign *msg) { + RESP_INIT(CosiSignature); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PARAM(msg->has_data, _("No data provided")); - CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); - CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); + CHECK_PARAM(msg->has_data, _("No data provided")); + CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, + _("Invalid global commitment")); + CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, + _("Invalid global pubkey")); - layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, + msg->data.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - uint8_t nonce[32]; - sha256_Raw(msg->data.bytes, msg->data.size, nonce); - rfc6979_state rng; - init_rfc6979(node->private_key, nonce, &rng); - generate_rfc6979(nonce, &rng); + uint8_t nonce[32]; + sha256_Raw(msg->data.bytes, msg->data.size, nonce); + rfc6979_state rng; + init_rfc6979(node->private_key, nonce, &rng); + generate_rfc6979(nonce, &rng); - resp->has_signature = true; - resp->signature.size = 32; + resp->has_signature = true; + resp->signature.size = 32; - ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); + ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, + msg->global_commitment.bytes, msg->global_pubkey.bytes, + resp->signature.bytes); - msg_write(MessageType_MessageType_CosiSignature, resp); - layoutHome(); + msg_write(MessageType_MessageType_CosiSignature, resp); + layoutHome(); } diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index e338d6eaa5..ff835b761b 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -19,89 +19,85 @@ #if DEBUG_LINK -void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) -{ - (void)msg; +void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) { + (void)msg; - // Do not use RESP_INIT because it clears msg_resp, but another message - // might be being handled - DebugLinkState resp; - memzero(&resp, sizeof(resp)); + // Do not use RESP_INIT because it clears msg_resp, but another message + // might be being handled + DebugLinkState resp; + memzero(&resp, sizeof(resp)); - resp.has_layout = true; - resp.layout.size = OLED_BUFSIZE; - memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); + resp.has_layout = true; + resp.layout.size = OLED_BUFSIZE; + memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin)); + resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin)); - resp.has_matrix = true; - strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); + resp.has_matrix = true; + strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); - resp.has_reset_entropy = true; - resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); + resp.has_reset_entropy = true; + resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); - resp.has_reset_word = true; - strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); + resp.has_reset_word = true; + strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); - resp.has_recovery_fake_word = true; - strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); + resp.has_recovery_fake_word = true; + strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), + sizeof(resp.recovery_fake_word)); - resp.has_recovery_word_pos = true; - resp.recovery_word_pos = recovery_get_word_pos(); + resp.has_recovery_word_pos = true; + resp.recovery_word_pos = recovery_get_word_pos(); - resp.has_mnemonic_secret = config_getMnemonicBytes(resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes), &resp.mnemonic_secret.size); - resp.mnemonic_type = 0; // BIP-39 + resp.has_mnemonic_secret = config_getMnemonicBytes( + resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes), + &resp.mnemonic_secret.size); + resp.mnemonic_type = 0; // BIP-39 - resp.has_node = config_dumpNode(&(resp.node)); + resp.has_node = config_dumpNode(&(resp.node)); - resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); + resp.has_passphrase_protection = + config_getPassphraseProtection(&(resp.passphrase_protection)); - msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); + msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } -void fsm_msgDebugLinkStop(const DebugLinkStop *msg) -{ - (void)msg; +void fsm_msgDebugLinkStop(const DebugLinkStop *msg) { (void)msg; } + +void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) { + RESP_INIT(DebugLinkMemory); + + uint32_t length = 1024; + if (msg->has_length && msg->length < length) length = msg->length; + resp->has_memory = true; + memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); + resp->memory.size = length; + msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); } -void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) -{ - RESP_INIT(DebugLinkMemory); - - uint32_t length = 1024; - if (msg->has_length && msg->length < length) - length = msg->length; - resp->has_memory = true; - memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); - resp->memory.size = length; - msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); -} - -void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) -{ - uint32_t length = msg->memory.size; - if (msg->flash) { - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - for (uint32_t i = 0; i < length; i += 4) { - uint32_t word; - memcpy(&word, msg->memory.bytes + i, 4); - flash_write32(msg->address + i, word); - } - uint32_t dummy = svc_flash_lock(); - (void)dummy; - } else { +void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) { + uint32_t length = msg->memory.size; + if (msg->flash) { + svc_flash_unlock(); + svc_flash_program(FLASH_CR_PROGRAM_X32); + for (uint32_t i = 0; i < length; i += 4) { + uint32_t word; + memcpy(&word, msg->memory.bytes + i, 4); + flash_write32(msg->address + i, word); + } + uint32_t dummy = svc_flash_lock(); + (void)dummy; + } else { #if !EMULATOR - memcpy((void *) msg->address, msg->memory.bytes, length); + memcpy((void *)msg->address, msg->memory.bytes, length); #endif - } + } } -void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) -{ - svc_flash_unlock(); - svc_flash_erase_sector(msg->sector); - uint32_t dummy = svc_flash_lock(); - (void)dummy; +void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) { + svc_flash_unlock(); + svc_flash_erase_sector(msg->sector); + uint32_t dummy = svc_flash_lock(); + (void)dummy; } #endif diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 2a9290772a..d5047623ea 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -17,163 +17,169 @@ * along with this library. If not, see . */ -void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) -{ - RESP_INIT(EthereumPublicKey); +void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) { + RESP_INIT(EthereumPublicKey); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - // we use Bitcoin-like format for ETH - const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); - if (!coin) return; + // we use Bitcoin-like format for ETH + const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); + if (!coin) return; - const char *curve = coin->curve_name; - uint32_t fingerprint; - HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); - if (!node) return; - hdnode_fill_public_key(node); + const char *curve = coin->curve_name; + uint32_t fingerprint; + HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, + msg->address_n_count, &fingerprint); + if (!node) return; + hdnode_fill_public_key(node); - if (msg->has_show_display && msg->show_display) { - layoutPublicKey(node->public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_show_display && msg->show_display) { + layoutPublicKey(node->public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - resp->has_node = true; - resp->node.depth = node->depth; - resp->node.fingerprint = fingerprint; - resp->node.child_num = node->child_num; - resp->node.chain_code.size = 32; - memcpy(resp->node.chain_code.bytes, node->chain_code, 32); - resp->node.has_private_key = false; - resp->node.has_public_key = true; - resp->node.public_key.size = 33; - memcpy(resp->node.public_key.bytes, node->public_key, 33); + resp->has_node = true; + resp->node.depth = node->depth; + resp->node.fingerprint = fingerprint; + resp->node.child_num = node->child_num; + resp->node.chain_code.size = 32; + memcpy(resp->node.chain_code.bytes, node->chain_code, 32); + resp->node.has_private_key = false; + resp->node.has_public_key = true; + resp->node.public_key.size = 33; + memcpy(resp->node.public_key.bytes, node->public_key, 33); - resp->has_xpub = true; - hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); + resp->has_xpub = true; + hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, + sizeof(resp->xpub)); - msg_write(MessageType_MessageType_EthereumPublicKey, resp); - layoutHome(); + msg_write(MessageType_MessageType_EthereumPublicKey, resp); + layoutHome(); } -void fsm_msgEthereumSignTx(EthereumSignTx *msg) -{ - CHECK_INITIALIZED +void fsm_msgEthereumSignTx(EthereumSignTx *msg) { + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - ethereum_signing_init(msg, node); + ethereum_signing_init(msg, node); } -void fsm_msgEthereumTxAck(const EthereumTxAck *msg) -{ - ethereum_signing_txack(msg); +void fsm_msgEthereumTxAck(const EthereumTxAck *msg) { + ethereum_signing_txack(msg); } -void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) -{ - RESP_INIT(EthereumAddress); +void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) { + RESP_INIT(EthereumAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - uint8_t pubkeyhash[20]; + uint8_t pubkeyhash[20]; - if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) - return; + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return; - uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; - bool rskip60 = false; - uint32_t chain_id = 0; - // constants from trezor-common/defs/ethereum/networks.json - switch (slip44) { - case 137: rskip60 = true; chain_id = 30; break; - case 37310: rskip60 = true; chain_id = 31; break; - } + uint32_t slip44 = + (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; + bool rskip60 = false; + uint32_t chain_id = 0; + // constants from trezor-common/defs/ethereum/networks.json + switch (slip44) { + case 137: + rskip60 = true; + chain_id = 30; + break; + case 37310: + rskip60 = true; + chain_id = 31; + break; + } - resp->has_address = true; - resp->address[0] = '0'; - resp->address[1] = 'x'; - ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id); - // ethereum_address_checksum adds trailing zero + resp->has_address = true; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id); + // ethereum_address_checksum adds trailing zero - if (msg->has_show_display && msg->show_display) { - char desc[16]; - strlcpy(desc, "Address:", sizeof(desc)); + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, "Address:", sizeof(desc)); - if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { - return; - } - } + if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, + msg->address_n_count, true)) { + return; + } + } - msg_write(MessageType_MessageType_EthereumAddress, resp); - layoutHome(); + msg_write(MessageType_MessageType_EthereumAddress, resp); + layoutHome(); } -void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) -{ - RESP_INIT(EthereumMessageSignature); +void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) { + RESP_INIT(EthereumMessageSignature); - CHECK_INITIALIZED + CHECK_INITIALIZED - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - ethereum_message_sign(msg, node, resp); - layoutHome(); + ethereum_message_sign(msg, node, resp); + layoutHome(); } -void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) -{ - CHECK_PARAM(msg->has_address, _("No address provided")); - CHECK_PARAM(msg->has_message, _("No message provided")); +void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) { + CHECK_PARAM(msg->has_address, _("No address provided")); + CHECK_PARAM(msg->has_message, _("No message provided")); - if (ethereum_message_verify(msg) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - return; - } + if (ethereum_message_verify(msg) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + return; + } - uint8_t pubkeyhash[20]; - if (!ethereum_parse(msg->address, pubkeyhash)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); - return; - } + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); + return; + } - layoutVerifyAddress(NULL, msg->address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); + layoutVerifyAddress(NULL, msg->address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); - layoutHome(); + layoutHome(); } diff --git a/firmware/fsm_msg_lisk.h b/firmware/fsm_msg_lisk.h index c8c37540ee..e95820f570 100644 --- a/firmware/fsm_msg_lisk.h +++ b/firmware/fsm_msg_lisk.h @@ -17,126 +17,128 @@ * along with this library. If not, see . */ -void fsm_msgLiskGetAddress(const LiskGetAddress *msg) -{ - CHECK_INITIALIZED +void fsm_msgLiskGetAddress(const LiskGetAddress *msg) { + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskAddress); + RESP_INIT(LiskAddress); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - resp->has_address = true; - hdnode_fill_public_key(node); - lisk_get_address_from_public_key(&node->public_key[1], resp->address); + resp->has_address = true; + hdnode_fill_public_key(node); + lisk_get_address_from_public_key(&node->public_key[1], resp->address); - if (msg->has_show_display && msg->show_display) { - if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count, false)) { - return; - } - } + if (msg->has_show_display && msg->show_display) { + if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, + msg->address_n, msg->address_n_count, false)) { + return; + } + } - msg_write(MessageType_MessageType_LiskAddress, resp); + msg_write(MessageType_MessageType_LiskAddress, resp); - layoutHome(); + layoutHome(); } -void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) -{ - CHECK_INITIALIZED +void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) { + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskPublicKey); + RESP_INIT(LiskPublicKey); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - resp->has_public_key = true; - resp->public_key.size = 32; + resp->has_public_key = true; + resp->public_key.size = 32; - if (msg->has_show_display && msg->show_display) { - layoutLiskPublicKey(&node->public_key[1]); - if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_show_display && msg->show_display) { + layoutLiskPublicKey(&node->public_key[1]); + if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); + memcpy(&resp->public_key.bytes, &node->public_key[1], + sizeof(resp->public_key.bytes)); - msg_write(MessageType_MessageType_LiskPublicKey, resp); + msg_write(MessageType_MessageType_LiskPublicKey, resp); - layoutHome(); + layoutHome(); } -void fsm_msgLiskSignMessage(const LiskSignMessage *msg) -{ - CHECK_INITIALIZED +void fsm_msgLiskSignMessage(const LiskSignMessage *msg) { + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskMessageSignature); + RESP_INIT(LiskMessageSignature); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - lisk_sign_message(node, msg, resp); + lisk_sign_message(node, msg, resp); - msg_write(MessageType_MessageType_LiskMessageSignature, resp); + msg_write(MessageType_MessageType_LiskMessageSignature, resp); - layoutHome(); + layoutHome(); } -void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) -{ - if (lisk_verify_message(msg)) { - char address[MAX_LISK_ADDRESS_SIZE]; - lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); +void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) { + if (lisk_verify_message(msg)) { + char address[MAX_LISK_ADDRESS_SIZE]; + lisk_get_address_from_public_key((const uint8_t *)&msg->public_key, + address); - layoutLiskVerifyAddress(address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - layoutVerifyMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - fsm_sendSuccess(_("Message verified")); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); - } + layoutLiskVerifyAddress(address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + layoutVerifyMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + fsm_sendSuccess(_("Message verified")); + } else { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); + } - layoutHome(); + layoutHome(); } -void fsm_msgLiskSignTx(LiskSignTx *msg) -{ - CHECK_INITIALIZED +void fsm_msgLiskSignTx(LiskSignTx *msg) { + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - RESP_INIT(LiskSignedTx); + RESP_INIT(LiskSignedTx); - HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - lisk_sign_tx(node, msg, resp); + lisk_sign_tx(node, msg, resp); - msg_write(MessageType_MessageType_LiskSignedTx, resp); + msg_write(MessageType_MessageType_LiskSignedTx, resp); - layoutHome(); + layoutHome(); } diff --git a/firmware/fsm_msg_nem.h b/firmware/fsm_msg_nem.h index 04c3a63d88..ce7f296032 100644 --- a/firmware/fsm_msg_nem.h +++ b/firmware/fsm_msg_nem.h @@ -17,290 +17,336 @@ * along with this library. If not, see . */ -void fsm_msgNEMGetAddress(NEMGetAddress *msg) -{ - if (!msg->has_network) { - msg->network = NEM_NETWORK_MAINNET; - } +void fsm_msgNEMGetAddress(NEMGetAddress *msg) { + if (!msg->has_network) { + msg->network = NEM_NETWORK_MAINNET; + } - const char *network; - CHECK_PARAM((network = nem_network_name(msg->network)), _("Invalid NEM network")); + const char *network; + CHECK_PARAM((network = nem_network_name(msg->network)), + _("Invalid NEM network")); - CHECK_INITIALIZED - CHECK_PIN + CHECK_INITIALIZED + CHECK_PIN - RESP_INIT(NEMAddress); + RESP_INIT(NEMAddress); - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - if (!hdnode_get_nem_address(node, msg->network, resp->address)) - return; + if (!hdnode_get_nem_address(node, msg->network, resp->address)) return; - if (msg->has_show_display && msg->show_display) { - char desc[16]; - strlcpy(desc, network, sizeof(desc)); - strlcat(desc, ":", sizeof(desc)); + if (msg->has_show_display && msg->show_display) { + char desc[16]; + strlcpy(desc, network, sizeof(desc)); + strlcat(desc, ":", sizeof(desc)); - if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count, false)) { - return; - } - } + if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, + msg->address_n_count, false)) { + return; + } + } - msg_write(MessageType_MessageType_NEMAddress, resp); - layoutHome(); + msg_write(MessageType_MessageType_NEMAddress, resp); + layoutHome(); } void fsm_msgNEMSignTx(NEMSignTx *msg) { - const char *reason; + const char *reason; -#define NEM_CHECK_PARAM(s) CHECK_PARAM( (reason = (s)) == NULL, reason) -#define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) +#define NEM_CHECK_PARAM(s) CHECK_PARAM((reason = (s)) == NULL, reason) +#define NEM_CHECK_PARAM_WHEN(b, s) \ + CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) - CHECK_PARAM(msg->has_transaction, _("No common provided")); + CHECK_PARAM(msg->has_transaction, _("No common provided")); - // Ensure exactly one transaction is provided - unsigned int provided = msg->has_transfer + - msg->has_provision_namespace + - msg->has_mosaic_creation + - msg->has_supply_change + - msg->has_aggregate_modification + - msg->has_importance_transfer; - CHECK_PARAM(provided != 0, _("No transaction provided")); - CHECK_PARAM(provided == 1, _("More than one transaction provided")); + // Ensure exactly one transaction is provided + unsigned int provided = msg->has_transfer + msg->has_provision_namespace + + msg->has_mosaic_creation + msg->has_supply_change + + msg->has_aggregate_modification + + msg->has_importance_transfer; + CHECK_PARAM(provided != 0, _("No transaction provided")); + CHECK_PARAM(provided == 1, _("More than one transaction provided")); - NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); - NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); - NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); - NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); - NEM_CHECK_PARAM_WHEN(msg->has_importance_transfer, nem_validate_importance_transfer(&msg->importance_transfer)); + NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); + NEM_CHECK_PARAM_WHEN( + msg->has_transfer, + nem_validate_transfer(&msg->transfer, msg->transaction.network)); + NEM_CHECK_PARAM_WHEN( + msg->has_provision_namespace, + nem_validate_provision_namespace(&msg->provision_namespace, + msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, + nem_validate_mosaic_creation(&msg->mosaic_creation, + msg->transaction.network)); + NEM_CHECK_PARAM_WHEN(msg->has_supply_change, + nem_validate_supply_change(&msg->supply_change)); + NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, + nem_validate_aggregate_modification( + &msg->aggregate_modification, !msg->has_multisig)); + NEM_CHECK_PARAM_WHEN( + msg->has_importance_transfer, + nem_validate_importance_transfer(&msg->importance_transfer)); - bool cosigning = msg->has_cosigning && msg->cosigning; - if (msg->has_multisig) { - NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); + bool cosigning = msg->has_cosigning && msg->cosigning; + if (msg->has_multisig) { + NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); - CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); - } else { - CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); - } + CHECK_PARAM(msg->transaction.network == msg->multisig.network, + _("Inner transaction network is different")); + } else { + CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); + } - CHECK_INITIALIZED - CHECK_PIN + CHECK_INITIALIZED + CHECK_PIN - const char *network = nem_network_name(msg->transaction.network); + const char *network = nem_network_name(msg->transaction.network); - if (msg->has_multisig) { - char address[NEM_ADDRESS_SIZE + 1]; - nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); + if (msg->has_multisig) { + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); - if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } - } + if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } + } - RESP_INIT(NEMSignedTx); + RESP_INIT(NEMSignedTx); - HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); - if (!node) return; + HDNode *node = + fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, + msg->transaction.address_n_count, NULL); + if (!node) return; - hdnode_fill_public_key(node); + hdnode_fill_public_key(node); - const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; + const NEMTransactionCommon *common = + msg->has_multisig ? &msg->multisig : &msg->transaction; - char address[NEM_ADDRESS_SIZE + 1]; - hdnode_get_nem_address(node, common->network, address); + char address[NEM_ADDRESS_SIZE + 1]; + hdnode_get_nem_address(node, common->network, address); - if (msg->has_transfer) { - msg->transfer.mosaics_count = nem_canonicalizeMosaics(msg->transfer.mosaics, msg->transfer.mosaics_count); - } + if (msg->has_transfer) { + msg->transfer.mosaics_count = nem_canonicalizeMosaics( + msg->transfer.mosaics, msg->transfer.mosaics_count); + } - if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_provision_namespace && + !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_mosaic_creation && + !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_supply_change && + !nem_askSupplyChange(common, &msg->supply_change, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_aggregate_modification && + !nem_askAggregateModification(common, &msg->aggregate_modification, + network, !msg->has_multisig)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); - layoutHome(); - return; - } + if (msg->has_importance_transfer && + !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, + _("Signing cancelled by user")); + layoutHome(); + return; + } - nem_transaction_ctx context; - nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); + nem_transaction_ctx context; + nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, + sizeof(resp->data.bytes)); - if (msg->has_multisig) { - uint8_t buffer[sizeof(resp->data.bytes)]; + if (msg->has_multisig) { + uint8_t buffer[sizeof(resp->data.bytes)]; - nem_transaction_ctx inner; - nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer)); + nem_transaction_ctx inner; + nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, + sizeof(buffer)); - if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { - layoutHome(); - return; - } + if (msg->has_transfer && + !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { + layoutHome(); + return; + } - if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&inner, &msg->multisig, &msg->provision_namespace)) { - layoutHome(); - return; - } + if (msg->has_provision_namespace && + !nem_fsmProvisionNamespace(&inner, &msg->multisig, + &msg->provision_namespace)) { + layoutHome(); + return; + } - if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { - layoutHome(); - return; - } + if (msg->has_mosaic_creation && + !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { + layoutHome(); + return; + } - if (msg->has_supply_change && !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { - layoutHome(); - return; - } + if (msg->has_supply_change && + !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { + layoutHome(); + return; + } - if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&inner, &msg->multisig, &msg->aggregate_modification)) { - layoutHome(); - return; - } + if (msg->has_aggregate_modification && + !nem_fsmAggregateModification(&inner, &msg->multisig, + &msg->aggregate_modification)) { + layoutHome(); + return; + } - if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&inner, &msg->multisig, &msg->importance_transfer)) { - layoutHome(); - return; - } + if (msg->has_importance_transfer && + !nem_fsmImportanceTransfer(&inner, &msg->multisig, + &msg->importance_transfer)) { + layoutHome(); + return; + } - if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { - layoutHome(); - return; - } - } else { - if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { - layoutHome(); - return; - } + if (!nem_fsmMultisig(&context, &msg->transaction, &inner, cosigning)) { + layoutHome(); + return; + } + } else { + if (msg->has_transfer && + !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { + layoutHome(); + return; + } - if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&context, &msg->transaction, &msg->provision_namespace)) { - layoutHome(); - return; - } + if (msg->has_provision_namespace && + !nem_fsmProvisionNamespace(&context, &msg->transaction, + &msg->provision_namespace)) { + layoutHome(); + return; + } - if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&context, &msg->transaction, &msg->mosaic_creation)) { - layoutHome(); - return; - } + if (msg->has_mosaic_creation && + !nem_fsmMosaicCreation(&context, &msg->transaction, + &msg->mosaic_creation)) { + layoutHome(); + return; + } - if (msg->has_supply_change && !nem_fsmSupplyChange(&context, &msg->transaction, &msg->supply_change)) { - layoutHome(); - return; - } + if (msg->has_supply_change && + !nem_fsmSupplyChange(&context, &msg->transaction, + &msg->supply_change)) { + layoutHome(); + return; + } - if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&context, &msg->transaction, &msg->aggregate_modification)) { - layoutHome(); - return; - } + if (msg->has_aggregate_modification && + !nem_fsmAggregateModification(&context, &msg->transaction, + &msg->aggregate_modification)) { + layoutHome(); + return; + } - if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&context, &msg->transaction, &msg->importance_transfer)) { - layoutHome(); - return; - } - } + if (msg->has_importance_transfer && + !nem_fsmImportanceTransfer(&context, &msg->transaction, + &msg->importance_transfer)) { + layoutHome(); + return; + } + } - resp->has_data = true; - resp->data.size = nem_transaction_end(&context, node->private_key, resp->signature.bytes); + resp->has_data = true; + resp->data.size = + nem_transaction_end(&context, node->private_key, resp->signature.bytes); - resp->has_signature = true; - resp->signature.size = sizeof(ed25519_signature); + resp->has_signature = true; + resp->signature.size = sizeof(ed25519_signature); - msg_write(MessageType_MessageType_NEMSignedTx, resp); - layoutHome(); + msg_write(MessageType_MessageType_NEMSignedTx, resp); + layoutHome(); } -void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) -{ - RESP_INIT(NEMDecryptedMessage); +void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) { + RESP_INIT(NEMDecryptedMessage); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); - CHECK_PARAM(msg->has_payload, _("No payload provided")); - CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), _("Invalid encrypted payload")); - CHECK_PARAM(msg->has_public_key, _("No public key provided")); - CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); + CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); + CHECK_PARAM(msg->has_payload, _("No payload provided")); + CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), + _("Invalid encrypted payload")); + CHECK_PARAM(msg->has_public_key, _("No public key provided")); + CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); - char address[NEM_ADDRESS_SIZE + 1]; - nem_get_address(msg->public_key.bytes, msg->network, address); + char address[NEM_ADDRESS_SIZE + 1]; + nem_get_address(msg->public_key.bytes, msg->network, address); - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - _("Decrypt message"), - _("Confirm address?"), - address); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Decrypt message"), _("Confirm address?"), address); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - CHECK_PIN + CHECK_PIN - const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) return; + const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, + msg->address_n_count, NULL); + if (!node) return; - const uint8_t *salt = msg->payload.bytes; - uint8_t *iv = &msg->payload.bytes[NEM_SALT_SIZE]; + const uint8_t *salt = msg->payload.bytes; + uint8_t *iv = &msg->payload.bytes[NEM_SALT_SIZE]; - const uint8_t *payload = &msg->payload.bytes[NEM_SALT_SIZE + AES_BLOCK_SIZE]; - size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; + const uint8_t *payload = &msg->payload.bytes[NEM_SALT_SIZE + AES_BLOCK_SIZE]; + size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; - // hdnode_nem_decrypt mutates the IV, so this will modify msg - bool ret = hdnode_nem_decrypt(node, - msg->public_key.bytes, - iv, - salt, - payload, - size, - resp->payload.bytes); - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); - layoutHome(); - return; - } + // hdnode_nem_decrypt mutates the IV, so this will modify msg + bool ret = hdnode_nem_decrypt(node, msg->public_key.bytes, iv, salt, payload, + size, resp->payload.bytes); + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to decrypt payload")); + layoutHome(); + return; + } - resp->has_payload = true; - resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); + resp->has_payload = true; + resp->payload.size = NEM_DECRYPTED_SIZE(resp->payload.bytes, size); - layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutNEMTransferPayload(resp->payload.bytes, resp->payload.size, true); + if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); - layoutHome(); + msg_write(MessageType_MessageType_NEMDecryptedMessage, resp); + layoutHome(); } diff --git a/firmware/fsm_msg_stellar.h b/firmware/fsm_msg_stellar.h index 0c989f4b37..1aa1bbf829 100644 --- a/firmware/fsm_msg_stellar.h +++ b/firmware/fsm_msg_stellar.h @@ -17,271 +17,258 @@ * along with this library. If not, see . */ -void fsm_msgStellarGetAddress(const StellarGetAddress *msg) -{ - RESP_INIT(StellarAddress); +void fsm_msgStellarGetAddress(const StellarGetAddress *msg) { + RESP_INIT(StellarAddress); - CHECK_INITIALIZED + CHECK_INITIALIZED - CHECK_PIN + CHECK_PIN - const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); - if (!node) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); - return; - } + const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to derive private key")); + return; + } - if (msg->has_show_display && msg->show_display) { - const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2], - NULL, - NULL, NULL - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (msg->has_show_display && msg->show_display) { + const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Share public account ID?"), str_addr_rows[0], + str_addr_rows[1], str_addr_rows[2], NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - resp->has_address = true; - stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); + resp->has_address = true; + stellar_publicAddressAsStr(node->public_key + 1, resp->address, + sizeof(resp->address)); - msg_write(MessageType_MessageType_StellarAddress, resp); + msg_write(MessageType_MessageType_StellarAddress, resp); - layoutHome(); + layoutHome(); } -void fsm_msgStellarSignTx(const StellarSignTx *msg) -{ - CHECK_INITIALIZED - CHECK_PIN +void fsm_msgStellarSignTx(const StellarSignTx *msg) { + CHECK_INITIALIZED + CHECK_PIN - if (!stellar_signingInit(msg)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); - layoutHome(); - return; - } + if (!stellar_signingInit(msg)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to derive private key")); + layoutHome(); + return; + } - // Confirm transaction basics - stellar_layoutTransactionSummary(msg); + // Confirm transaction basics + stellar_layoutTransactionSummary(msg); - // Respond with a request for the first operation - RESP_INIT(StellarTxOpRequest); + // Respond with a request for the first operation + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); } -void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) -{ - if (!stellar_confirmCreateAccountOp(msg)) return; +void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) { + if (!stellar_confirmCreateAccountOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) -{ - // This will display additional dialogs to the user - if (!stellar_confirmPaymentOp(msg)) return; +void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) { + // This will display additional dialogs to the user + if (!stellar_confirmPaymentOp(msg)) return; - // Last operation was confirmed, send a StellarSignedTx - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + // Last operation was confirmed, send a StellarSignedTx + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) -{ - if (!stellar_confirmPathPaymentOp(msg)) return; +void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) { + if (!stellar_confirmPathPaymentOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) -{ - if (!stellar_confirmManageOfferOp(msg)) return; +void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) { + if (!stellar_confirmManageOfferOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) -{ - if (!stellar_confirmCreatePassiveOfferOp(msg)) return; +void fsm_msgStellarCreatePassiveOfferOp( + const StellarCreatePassiveOfferOp *msg) { + if (!stellar_confirmCreatePassiveOfferOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) -{ - if (!stellar_confirmSetOptionsOp(msg)) return; +void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) { + if (!stellar_confirmSetOptionsOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) -{ - if (!stellar_confirmChangeTrustOp(msg)) return; +void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) { + if (!stellar_confirmChangeTrustOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) -{ - if (!stellar_confirmAllowTrustOp(msg)) return; +void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) { + if (!stellar_confirmAllowTrustOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) -{ - if (!stellar_confirmAccountMergeOp(msg)) return; +void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) { + if (!stellar_confirmAccountMergeOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) -{ - if (!stellar_confirmManageDataOp(msg)) return; +void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) { + if (!stellar_confirmManageDataOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } -void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) -{ - if (!stellar_confirmBumpSequenceOp(msg)) return; +void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) { + if (!stellar_confirmBumpSequenceOp(msg)) return; - if (stellar_allOperationsConfirmed()) { - RESP_INIT(StellarSignedTx); + if (stellar_allOperationsConfirmed()) { + RESP_INIT(StellarSignedTx); - stellar_fillSignedTx(resp); - msg_write(MessageType_MessageType_StellarSignedTx, resp); - layoutHome(); - } - // Request the next operation to sign - else { - RESP_INIT(StellarTxOpRequest); + stellar_fillSignedTx(resp); + msg_write(MessageType_MessageType_StellarSignedTx, resp); + layoutHome(); + } + // Request the next operation to sign + else { + RESP_INIT(StellarTxOpRequest); - msg_write(MessageType_MessageType_StellarTxOpRequest, resp); - } + msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + } } diff --git a/firmware/layout2.c b/firmware/layout2.c index b61a467902..234d27b50b 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -17,957 +17,926 @@ * along with this library. If not, see . */ +#include #include #include -#include -#include "layout2.h" -#include "config.h" -#include "oled.h" -#include "bitmaps.h" -#include "string.h" -#include "util.h" -#include "qrcodegen.h" -#include "timer.h" #include "bignum.h" -#include "secp256k1.h" -#include "nem2.h" +#include "bitmaps.h" +#include "config.h" #include "gettext.h" +#include "layout2.h" #include "memzero.h" +#include "nem2.h" +#include "oled.h" +#include "qrcodegen.h" +#include "secp256k1.h" +#include "string.h" +#include "timer.h" +#include "util.h" #define BITCOIN_DIVISIBILITY (8) -static const char *slip44_extras(uint32_t coin_type) -{ - if ((coin_type & 0x80000000) == 0) { - return 0; - } - switch (coin_type & 0x7fffffff) { - case 40: return "EXP"; // Expanse - case 43: return "NEM"; // NEM - case 60: return "ETH"; // Ethereum Mainnet - case 61: return "ETC"; // Ethereum Classic Mainnet - case 108: return "UBQ"; // UBIQ - case 137: return "RSK"; // Rootstock Mainnet - case 37310: return "tRSK"; // Rootstock Testnet - } - return 0; +static const char *slip44_extras(uint32_t coin_type) { + if ((coin_type & 0x80000000) == 0) { + return 0; + } + switch (coin_type & 0x7fffffff) { + case 40: + return "EXP"; // Expanse + case 43: + return "NEM"; // NEM + case 60: + return "ETH"; // Ethereum Mainnet + case 61: + return "ETC"; // Ethereum Classic Mainnet + case 108: + return "UBQ"; // UBIQ + case 137: + return "RSK"; // Rootstock Mainnet + case 37310: + return "tRSK"; // Rootstock Testnet + } + return 0; } #define BIP32_MAX_LAST_ELEMENT 1000000 -static const char *address_n_str(const uint32_t *address_n, size_t address_n_count, bool address_is_account) -{ - if (address_n_count > 8) { - return _("Unknown long path"); - } - if (address_n_count == 0) { - return _("Path: m"); - } +static const char *address_n_str(const uint32_t *address_n, + size_t address_n_count, + bool address_is_account) { + if (address_n_count > 8) { + return _("Unknown long path"); + } + if (address_n_count == 0) { + return _("Path: m"); + } - // known BIP44/49 path - static char path[100]; - if (address_n_count == 5 && - (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) && - (address_n[1] & 0x80000000) && - (address_n[2] & 0x80000000) && - (address_n[3] <= 1) && - (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { - bool native_segwit = (address_n[0] == (0x80000000 + 84)); - bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); - bool legacy = false; - const CoinInfo *coin = coinBySlip44(address_n[1]); - const char *abbr = 0; - if (native_segwit) { - if (coin && coin->has_segwit && coin->bech32_prefix) { - abbr = coin->coin_shortcut + 1; - } - } else - if (p2sh_segwit) { - if (coin && coin->has_segwit && coin->has_address_type_p2sh) { - abbr = coin->coin_shortcut + 1; - } - } else { - if (coin) { - if (coin->has_segwit && coin->has_address_type_p2sh) { - legacy = true; - } - abbr = coin->coin_shortcut + 1; - } else { - abbr = slip44_extras(address_n[1]); - } - } - const uint32_t accnum = address_is_account ? ((address_n[4] & 0x7fffffff) + 1) : (address_n[2] & 0x7fffffff) + 1; - if (abbr && accnum < 100) { - memzero(path, sizeof(path)); - strlcpy(path, abbr, sizeof(path)); - // TODO: how to name accounts? - // currently we have "legacy account", "account" and "segwit account" - // for BIP44/P2PKH, BIP49/P2SH-P2WPKH and BIP84/P2WPKH respectivelly - if (legacy) { - strlcat(path, " legacy", sizeof(path)); - } - if (native_segwit) { - strlcat(path, " segwit", sizeof(path)); - } - if (address_is_account) { - strlcat(path, " address #", sizeof(path)); - } else { - strlcat(path, " account #", sizeof(path)); - } - char acc[3]; - memzero(acc, sizeof(acc)); - if (accnum < 10) { - acc[0] = '0' + accnum; - } else { - acc[0] = '0' + (accnum / 10); - acc[1] = '0' + (accnum % 10); - } - strlcat(path, acc, sizeof(path)); - return path; - } - } + // known BIP44/49 path + static char path[100]; + if (address_n_count == 5 && + (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || + address_n[0] == (0x80000000 + 84)) && + (address_n[1] & 0x80000000) && (address_n[2] & 0x80000000) && + (address_n[3] <= 1) && (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) { + bool native_segwit = (address_n[0] == (0x80000000 + 84)); + bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); + bool legacy = false; + const CoinInfo *coin = coinBySlip44(address_n[1]); + const char *abbr = 0; + if (native_segwit) { + if (coin && coin->has_segwit && coin->bech32_prefix) { + abbr = coin->coin_shortcut + 1; + } + } else if (p2sh_segwit) { + if (coin && coin->has_segwit && coin->has_address_type_p2sh) { + abbr = coin->coin_shortcut + 1; + } + } else { + if (coin) { + if (coin->has_segwit && coin->has_address_type_p2sh) { + legacy = true; + } + abbr = coin->coin_shortcut + 1; + } else { + abbr = slip44_extras(address_n[1]); + } + } + const uint32_t accnum = address_is_account + ? ((address_n[4] & 0x7fffffff) + 1) + : (address_n[2] & 0x7fffffff) + 1; + if (abbr && accnum < 100) { + memzero(path, sizeof(path)); + strlcpy(path, abbr, sizeof(path)); + // TODO: how to name accounts? + // currently we have "legacy account", "account" and "segwit account" + // for BIP44/P2PKH, BIP49/P2SH-P2WPKH and BIP84/P2WPKH respectivelly + if (legacy) { + strlcat(path, " legacy", sizeof(path)); + } + if (native_segwit) { + strlcat(path, " segwit", sizeof(path)); + } + if (address_is_account) { + strlcat(path, " address #", sizeof(path)); + } else { + strlcat(path, " account #", sizeof(path)); + } + char acc[3]; + memzero(acc, sizeof(acc)); + if (accnum < 10) { + acc[0] = '0' + accnum; + } else { + acc[0] = '0' + (accnum / 10); + acc[1] = '0' + (accnum % 10); + } + strlcat(path, acc, sizeof(path)); + return path; + } + } - // "Path: m" / i ' - static char address_str[7 + 8 * (1 + 10 + 1) + 1]; - char *c = address_str + sizeof(address_str) - 1; + // "Path: m" / i ' + static char address_str[7 + 8 * (1 + 10 + 1) + 1]; + char *c = address_str + sizeof(address_str) - 1; - *c = 0; c--; + *c = 0; + c--; - for (int n = (int)address_n_count - 1; n >= 0; n--) { - uint32_t i = address_n[n]; - if (i & 0x80000000) { - *c = '\''; c--; - } - i = i & 0x7fffffff; - do { - *c = '0' + (i % 10); c--; - i /= 10; - } while (i > 0); - *c = '/'; c--; - } - *c = 'm'; c--; - *c = ' '; c--; - *c = ':'; c--; - *c = 'h'; c--; - *c = 't'; c--; - *c = 'a'; c--; - *c = 'P'; + for (int n = (int)address_n_count - 1; n >= 0; n--) { + uint32_t i = address_n[n]; + if (i & 0x80000000) { + *c = '\''; + c--; + } + i = i & 0x7fffffff; + do { + *c = '0' + (i % 10); + c--; + i /= 10; + } while (i > 0); + *c = '/'; + c--; + } + *c = 'm'; + c--; + *c = ' '; + c--; + *c = ':'; + c--; + *c = 'h'; + c--; + *c = 't'; + c--; + *c = 'a'; + c--; + *c = 'P'; - return c; + return c; } // split longer string into 4 rows, rowlen chars each -const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) -{ - static char str[4][32 + 1]; - if (rowlen > 32) { - rowlen = 32; - } - memzero(str, sizeof(str)); - strlcpy(str[0], (char *)msg, rowlen + 1); - if (len > rowlen) { - strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); - } - if (len > rowlen * 2) { - strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); - } - if (len > rowlen * 3) { - strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); - } - if (len > rowlen * 4) { - str[3][rowlen - 1] = '.'; - str[3][rowlen - 2] = '.'; - str[3][rowlen - 3] = '.'; - } - static const char *ret[4] = { str[0], str[1], str[2], str[3] }; - return ret; +const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) { + static char str[4][32 + 1]; + if (rowlen > 32) { + rowlen = 32; + } + memzero(str, sizeof(str)); + strlcpy(str[0], (char *)msg, rowlen + 1); + if (len > rowlen) { + strlcpy(str[1], (char *)msg + rowlen, rowlen + 1); + } + if (len > rowlen * 2) { + strlcpy(str[2], (char *)msg + rowlen * 2, rowlen + 1); + } + if (len > rowlen * 3) { + strlcpy(str[3], (char *)msg + rowlen * 3, rowlen + 1); + } + if (len > rowlen * 4) { + str[3][rowlen - 1] = '.'; + str[3][rowlen - 2] = '.'; + str[3][rowlen - 3] = '.'; + } + static const char *ret[4] = {str[0], str[1], str[2], str[3]}; + return ret; } -const char **split_message_hex(const uint8_t *msg, uint32_t len) -{ - char hex[32 * 2 + 1]; - memzero(hex, sizeof(hex)); - uint32_t size = len; - if (len > 32) { - size = 32; - } - data2hex(msg, size, hex); - if (len > 32) { - hex[63] = '.'; - hex[62] = '.'; - } - return split_message((const uint8_t *)hex, size * 2, 16); +const char **split_message_hex(const uint8_t *msg, uint32_t len) { + char hex[32 * 2 + 1]; + memzero(hex, sizeof(hex)); + uint32_t size = len; + if (len > 32) { + size = 32; + } + data2hex(msg, size, hex); + if (len > 32) { + hex[63] = '.'; + hex[62] = '.'; + } + return split_message((const uint8_t *)hex, size * 2, 16); } void *layoutLast = layoutHome; -void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) -{ - layoutLast = layoutDialogSwipe; - layoutSwipe(); - layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, line6); +void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, + const char *btnYes, const char *desc, const char *line1, + const char *line2, const char *line3, const char *line4, + const char *line5, const char *line6) { + layoutLast = layoutDialogSwipe; + layoutSwipe(); + layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, + line6); } -void layoutProgressSwipe(const char *desc, int permil) -{ - if (layoutLast == layoutProgressSwipe) { - oledClear(); - } else { - layoutLast = layoutProgressSwipe; - layoutSwipe(); - } - layoutProgress(desc, permil); +void layoutProgressSwipe(const char *desc, int permil) { + if (layoutLast == layoutProgressSwipe) { + oledClear(); + } else { + layoutLast = layoutProgressSwipe; + layoutSwipe(); + } + layoutProgress(desc, permil); } -void layoutScreensaver(void) -{ - layoutLast = layoutScreensaver; - oledClear(); - oledRefresh(); +void layoutScreensaver(void) { + layoutLast = layoutScreensaver; + oledClear(); + oledRefresh(); } -void layoutHome(void) -{ - if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { - oledClear(); - } else { - layoutSwipe(); - } - layoutLast = layoutHome; +void layoutHome(void) { + if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { + oledClear(); + } else { + layoutSwipe(); + } + layoutLast = layoutHome; - char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); - if (config_isInitialized()) { - config_getLabel(label, sizeof(label)); - } + char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); + if (config_isInitialized()) { + config_getLabel(label, sizeof(label)); + } - uint8_t homescreen[HOMESCREEN_SIZE]; - if (config_getHomescreen(homescreen, sizeof(homescreen))) { - BITMAP b; - b.width = 128; - b.height = 64; - b.data = homescreen; - oledDrawBitmap(0, 0, &b); - } else { - if (label[0] != '\0') { - oledDrawBitmap(44, 4, &bmp_logo48); - oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, FONT_STANDARD); - } else { - oledDrawBitmap(40, 0, &bmp_logo64); - } - } + uint8_t homescreen[HOMESCREEN_SIZE]; + if (config_getHomescreen(homescreen, sizeof(homescreen))) { + BITMAP b; + b.width = 128; + b.height = 64; + b.data = homescreen; + oledDrawBitmap(0, 0, &b); + } else { + if (label[0] != '\0') { + oledDrawBitmap(44, 4, &bmp_logo48); + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, + FONT_STANDARD); + } else { + oledDrawBitmap(40, 0, &bmp_logo64); + } + } - bool no_backup = false; - bool unfinished_backup = false; - bool needs_backup = false; - config_getNoBackup(&no_backup); - config_getUnfinishedBackup(&unfinished_backup); - config_getNeedsBackup(&needs_backup); - if (no_backup) { - oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); - } else if (unfinished_backup) { - oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); - } else if (needs_backup) { - oledBox(0, 0, 127, 8, false); - oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); - } - oledRefresh(); + bool no_backup = false; + bool unfinished_backup = false; + bool needs_backup = false; + config_getNoBackup(&no_backup); + config_getUnfinishedBackup(&unfinished_backup); + config_getNeedsBackup(&needs_backup); + if (no_backup) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); + } else if (unfinished_backup) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); + } else if (needs_backup) { + oledBox(0, 0, 127, 8, false); + oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); + } + oledRefresh(); - // Reset lock screen timeout - system_millis_lock_start = timer_ms(); + // Reset lock screen timeout + system_millis_lock_start = timer_ms(); } -static void render_address_dialog(const CoinInfo *coin, const char *address, const char *line1, const char *line2, const char *extra_line) -{ - if (coin && coin->cashaddr_prefix) { - /* If this is a cashaddr address, remove the prefix from the - * string presented to the user - */ - int prefix_len = strlen(coin->cashaddr_prefix); - if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 - && address[prefix_len] == ':') { - address += prefix_len + 1; - } - } - int addrlen = strlen(address); - int numlines = addrlen <= 42 ? 2 : 3; - int linelen = (addrlen - 1) / numlines + 1; - if (linelen > 21) { - linelen = 21; - } - const char **str = split_message((const uint8_t *)address, addrlen, linelen); - layoutLast = layoutDialogSwipe; - layoutSwipe(); - oledClear(); - oledDrawBitmap(0, 0, &bmp_icon_question); - oledDrawString(20, 0 * 9, line1, FONT_STANDARD); - oledDrawString(20, 1 * 9, line2, FONT_STANDARD); - int left = linelen > 18 ? 0 : 20; - oledDrawString(left, 2 * 9, str[0], FONT_FIXED); - oledDrawString(left, 3 * 9, str[1], FONT_FIXED); - oledDrawString(left, 4 * 9, str[2], FONT_FIXED); - oledDrawString(left, 5 * 9, str[3], FONT_FIXED); - if (!str[3][0]) { - if (extra_line) { - oledDrawString(0, 5 * 9, extra_line, FONT_STANDARD); - } else { - oledHLine(OLED_HEIGHT - 13); - } - } - layoutButtonNo(_("Cancel")); - layoutButtonYes(_("Confirm")); - oledRefresh(); +static void render_address_dialog(const CoinInfo *coin, const char *address, + const char *line1, const char *line2, + const char *extra_line) { + if (coin && coin->cashaddr_prefix) { + /* If this is a cashaddr address, remove the prefix from the + * string presented to the user + */ + int prefix_len = strlen(coin->cashaddr_prefix); + if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 && + address[prefix_len] == ':') { + address += prefix_len + 1; + } + } + int addrlen = strlen(address); + int numlines = addrlen <= 42 ? 2 : 3; + int linelen = (addrlen - 1) / numlines + 1; + if (linelen > 21) { + linelen = 21; + } + const char **str = split_message((const uint8_t *)address, addrlen, linelen); + layoutLast = layoutDialogSwipe; + layoutSwipe(); + oledClear(); + oledDrawBitmap(0, 0, &bmp_icon_question); + oledDrawString(20, 0 * 9, line1, FONT_STANDARD); + oledDrawString(20, 1 * 9, line2, FONT_STANDARD); + int left = linelen > 18 ? 0 : 20; + oledDrawString(left, 2 * 9, str[0], FONT_FIXED); + oledDrawString(left, 3 * 9, str[1], FONT_FIXED); + oledDrawString(left, 4 * 9, str[2], FONT_FIXED); + oledDrawString(left, 5 * 9, str[3], FONT_FIXED); + if (!str[3][0]) { + if (extra_line) { + oledDrawString(0, 5 * 9, extra_line, FONT_STANDARD); + } else { + oledHLine(OLED_HEIGHT - 13); + } + } + layoutButtonNo(_("Cancel")); + layoutButtonYes(_("Confirm")); + oledRefresh(); } -void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) -{ - char str_out[32 + 3]; - bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); - strlcat(str_out, " to", sizeof(str_out)); - const char *address = out->address; - const char *extra_line = (out->address_n_count > 0) ? address_n_str(out->address_n, out->address_n_count, false) : 0; - render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); +void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { + char str_out[32 + 3]; + bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, + 0, false, str_out, sizeof(str_out) - 3); + strlcat(str_out, " to", sizeof(str_out)); + const char *address = out->address; + const char *extra_line = + (out->address_n_count > 0) + ? address_n_str(out->address_n, out->address_n_count, false) + : 0; + render_address_dialog(coin, address, _("Confirm sending"), str_out, + extra_line); } -void layoutConfirmOmni(const uint8_t *data, uint32_t size) -{ - const char *desc; - char str_out[32]; - const uint32_t tx_type = *(const uint32_t *)(data + 4); - if (tx_type == 0x00000000 && size == 20) { // OMNI simple send - desc = _("Simple send of "); - const uint32_t currency = *(const uint32_t *)(data + 8); - const char *suffix = "UNKN"; - switch (currency) { - case 1: - suffix = "OMNI"; - break; - case 2: - suffix = "tOMNI"; - break; - case 3: - suffix = "MAID"; - break; - case 31: - suffix = "USDT"; - break; - } - const uint64_t amount = *(const uint64_t *)(data + 12); - bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); - } else { - desc = _("Unknown transaction"); - str_out[0] = 0; - } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Confirm OMNI Transaction:"), - NULL, - desc, - NULL, - str_out, - NULL - ); +void layoutConfirmOmni(const uint8_t *data, uint32_t size) { + const char *desc; + char str_out[32]; + const uint32_t tx_type = *(const uint32_t *)(data + 4); + if (tx_type == 0x00000000 && size == 20) { // OMNI simple send + desc = _("Simple send of "); + const uint32_t currency = *(const uint32_t *)(data + 8); + const char *suffix = "UNKN"; + switch (currency) { + case 1: + suffix = "OMNI"; + break; + case 2: + suffix = "tOMNI"; + break; + case 3: + suffix = "MAID"; + break; + case 31: + suffix = "USDT"; + break; + } + const uint64_t amount = *(const uint64_t *)(data + 12); + bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, + str_out, sizeof(str_out)); + } else { + desc = _("Unknown transaction"); + str_out[0] = 0; + } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm OMNI Transaction:"), NULL, desc, NULL, str_out, + NULL); } -static bool is_valid_ascii(const uint8_t *data, uint32_t size) -{ - for (uint32_t i = 0; i < size; i++) { - if (data[i] < ' ' || data[i] > '~') { - return false; - } - } - return true; +static bool is_valid_ascii(const uint8_t *data, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + if (data[i] < ' ' || data[i] > '~') { + return false; + } + } + return true; } -void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) -{ - const char **str; - if (!is_valid_ascii(data, size)) { - str = split_message_hex(data, size); - } else { - str = split_message(data, size, 20); - } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Confirm OP_RETURN:"), - str[0], - str[1], - str[2], - str[3], - NULL - ); +void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) { + const char **str; + if (!is_valid_ascii(data, size)) { + str = split_message_hex(data, size); + } else { + str = split_message(data, size, 20); + } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm OP_RETURN:"), str[0], str[1], str[2], str[3], + NULL); } -void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee) -{ - char str_out[32], str_fee[32]; - bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); - bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Really send"), - str_out, - _("from your wallet?"), - _("Fee included:"), - str_fee, - NULL - ); +void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, + uint64_t amount_fee) { + char str_out[32], str_fee[32]; + bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, + 0, false, str_out, sizeof(str_out)); + bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, + 0, false, str_fee, sizeof(str_fee)); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Really send"), str_out, _("from your wallet?"), + _("Fee included:"), str_fee, NULL); } -void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) -{ - char str_fee[32]; - bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - NULL, - _("Fee"), - str_fee, - _("is unexpectedly high."), - NULL, - _("Send anyway?"), - NULL - ); +void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) { + char str_fee[32]; + bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, + false, str_fee, sizeof(str_fee)); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Fee"), str_fee, _("is unexpectedly high."), NULL, + _("Send anyway?"), NULL); } -void layoutSignMessage(const uint8_t *msg, uint32_t len) -{ - const char **str; - if (!is_valid_ascii(msg, len)) { - str = split_message_hex(msg, len); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - _("Sign binary message?"), - str[0], str[1], str[2], str[3], NULL, NULL); - } else { - str = split_message(msg, len, 20); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - _("Sign message?"), - str[0], str[1], str[2], str[3], NULL, NULL); - } +void layoutSignMessage(const uint8_t *msg, uint32_t len) { + const char **str; + if (!is_valid_ascii(msg, len)) { + str = split_message_hex(msg, len); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Sign binary message?"), str[0], str[1], str[2], str[3], + NULL, NULL); + } else { + str = split_message(msg, len, 20); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Sign message?"), str[0], str[1], str[2], str[3], NULL, + NULL); + } } -void layoutVerifyMessage(const uint8_t *msg, uint32_t len) -{ - const char **str; - if (!is_valid_ascii(msg, len)) { - str = split_message_hex(msg, len); - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), - _("Verified binary message"), - str[0], str[1], str[2], str[3], NULL, NULL); - } else { - str = split_message(msg, len, 20); - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), - _("Verified message"), - str[0], str[1], str[2], str[3], NULL, NULL); - } +void layoutVerifyMessage(const uint8_t *msg, uint32_t len) { + const char **str; + if (!is_valid_ascii(msg, len)) { + str = split_message_hex(msg, len); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Verified binary message"), str[0], str[1], str[2], + str[3], NULL, NULL); + } else { + str = split_message(msg, len, 20); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Verified message"), str[0], str[1], str[2], str[3], + NULL, NULL); + } } -void layoutVerifyAddress(const CoinInfo *coin, const char *address) -{ - render_address_dialog(coin, address, _("Confirm address?"), _("Message signed by:"), 0); +void layoutVerifyAddress(const CoinInfo *coin, const char *address) { + render_address_dialog(coin, address, _("Confirm address?"), + _("Message signed by:"), 0); } -void layoutCipherKeyValue(bool encrypt, const char *key) -{ - const char **str = split_message((const uint8_t *)key, strlen(key), 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - encrypt ? _("Encrypt value of this key?") : _("Decrypt value of this key?"), - str[0], str[1], str[2], str[3], NULL, NULL); +void layoutCipherKeyValue(bool encrypt, const char *key) { + const char **str = split_message((const uint8_t *)key, strlen(key), 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + encrypt ? _("Encrypt value of this key?") + : _("Decrypt value of this key?"), + str[0], str[1], str[2], str[3], NULL, NULL); } -void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) -{ - const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - signing ? _("Encrypt+Sign message?") : _("Encrypt message?"), - str[0], str[1], str[2], str[3], NULL, NULL); +void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) { + const char **str = split_message(msg, len, 16); + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Confirm"), + signing ? _("Encrypt+Sign message?") : _("Encrypt message?"), str[0], + str[1], str[2], str[3], NULL, NULL); } -void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) -{ - const char **str = split_message(msg, len, 16); - layoutDialogSwipe(&bmp_icon_info, NULL, _("OK"), - address ? _("Decrypted signed message") : _("Decrypted message"), - str[0], str[1], str[2], str[3], NULL, NULL); +void layoutDecryptMessage(const uint8_t *msg, uint32_t len, + const char *address) { + const char **str = split_message(msg, len, 16); + layoutDialogSwipe( + &bmp_icon_info, NULL, _("OK"), + address ? _("Decrypted signed message") : _("Decrypted message"), str[0], + str[1], str[2], str[3], NULL, NULL); } -void layoutResetWord(const char *word, int pass, int word_pos, bool last) -{ - layoutLast = layoutResetWord; - layoutSwipe(); +void layoutResetWord(const char *word, int pass, int word_pos, bool last) { + layoutLast = layoutResetWord; + layoutSwipe(); - const char *btnYes; - if (last) { - if (pass == 1) { - btnYes = _("Finish"); - } else { - btnYes = _("Again"); - } - } else { - btnYes = _("Next"); - } + const char *btnYes; + if (last) { + if (pass == 1) { + btnYes = _("Finish"); + } else { + btnYes = _("Again"); + } + } else { + btnYes = _("Next"); + } - const char *action; - if (pass == 1) { - action = _("Please check the seed"); - } else { - action = _("Write down the seed"); - } + const char *action; + if (pass == 1) { + action = _("Please check the seed"); + } else { + action = _("Write down the seed"); + } - char index_str[] = "##th word is:"; - if (word_pos < 10) { - index_str[0] = ' '; - } else { - index_str[0] = '0' + word_pos / 10; - } - index_str[1] = '0' + word_pos % 10; - if (word_pos == 1 || word_pos == 21) { - index_str[2] = 's'; index_str[3] = 't'; - } else - if (word_pos == 2 || word_pos == 22) { - index_str[2] = 'n'; index_str[3] = 'd'; - } else - if (word_pos == 3 || word_pos == 23) { - index_str[2] = 'r'; index_str[3] = 'd'; - } + char index_str[] = "##th word is:"; + if (word_pos < 10) { + index_str[0] = ' '; + } else { + index_str[0] = '0' + word_pos / 10; + } + index_str[1] = '0' + word_pos % 10; + if (word_pos == 1 || word_pos == 21) { + index_str[2] = 's'; + index_str[3] = 't'; + } else if (word_pos == 2 || word_pos == 22) { + index_str[2] = 'n'; + index_str[3] = 'd'; + } else if (word_pos == 3 || word_pos == 23) { + index_str[2] = 'r'; + index_str[3] = 'd'; + } - int left = 0; - oledClear(); - oledDrawBitmap(0, 0, &bmp_icon_info); - left = bmp_icon_info.width + 4; + int left = 0; + oledClear(); + oledDrawBitmap(0, 0, &bmp_icon_info); + left = bmp_icon_info.width + 4; - oledDrawString(left, 0 * 9, action, FONT_STANDARD); - oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, FONT_STANDARD); - oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); - oledHLine(OLED_HEIGHT - 13); - layoutButtonYes(btnYes); - oledRefresh(); + oledDrawString(left, 0 * 9, action, FONT_STANDARD); + oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, + FONT_STANDARD); + oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); + oledHLine(OLED_HEIGHT - 13); + layoutButtonYes(btnYes); + oledRefresh(); } #define QR_MAX_VERSION 9 -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account) -{ - if (layoutLast != layoutAddress) { - layoutSwipe(); - } else { - oledClear(); - } - layoutLast = layoutAddress; +void layoutAddress(const char *address, const char *desc, bool qrcode, + bool ignorecase, const uint32_t *address_n, + size_t address_n_count, bool address_is_account) { + if (layoutLast != layoutAddress) { + layoutSwipe(); + } else { + oledClear(); + } + layoutLast = layoutAddress; - uint32_t addrlen = strlen(address); - if (qrcode) { - char address_upcase[addrlen + 1]; - if (ignorecase) { - for (uint32_t i = 0; i < addrlen + 1; i++) { - address_upcase[i] = address[i] >= 'a' && address[i] <= 'z' ? - address[i] + 'A' - 'a' : address[i]; - } - } - uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; - uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + uint32_t addrlen = strlen(address); + if (qrcode) { + char address_upcase[addrlen + 1]; + if (ignorecase) { + for (uint32_t i = 0; i < addrlen + 1; i++) { + address_upcase[i] = address[i] >= 'a' && address[i] <= 'z' + ? address[i] + 'A' - 'a' + : address[i]; + } + } + uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; + uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; - int side = 0; - if (qrcodegen_encodeText( - ignorecase ? address_upcase : address, - tempdata, - codedata, - qrcodegen_Ecc_LOW, - qrcodegen_VERSION_MIN, - QR_MAX_VERSION, - qrcodegen_Mask_AUTO, - true)) { - side = qrcodegen_getSize(codedata); - } + int side = 0; + if (qrcodegen_encodeText(ignorecase ? address_upcase : address, tempdata, + codedata, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN, + QR_MAX_VERSION, qrcodegen_Mask_AUTO, true)) { + side = qrcodegen_getSize(codedata); + } - oledInvert(0, 0, 63, 63); - if (side > 0 && side <= 29) { - int offset = 32 - side; - for (int i = 0; i < side; i++) { - for (int j = 0; j< side; j++) { - if (qrcodegen_getModule(codedata, i, j)) { - oledBox(offset + i * 2, offset + j * 2, - offset + 1 + i * 2, offset + 1 + j * 2, false); - } - } - } - } else if (side > 0 && side <= 60) { - int offset = 32 - (side / 2); - for (int i = 0; i < side; i++) { - for (int j = 0; j< side; j++) { - if (qrcodegen_getModule(codedata, i, j)) { - oledClearPixel(offset + i, offset + j); - } - } - } - } - } else { - if (desc) { - oledDrawString(0, 0 * 9, desc, FONT_STANDARD); - } - if (addrlen > 10) { // don't split short addresses - uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; - const char **str = split_message((const uint8_t *)address, addrlen, rowlen); - for (int i = 0; i < 4; i++) { - oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); - } - } else { - oledDrawString(0, (0 + 1) * 9 + 4, address, FONT_FIXED); - } - oledDrawString(0, 42, address_n_str(address_n, address_n_count, address_is_account), FONT_STANDARD); - } + oledInvert(0, 0, 63, 63); + if (side > 0 && side <= 29) { + int offset = 32 - side; + for (int i = 0; i < side; i++) { + for (int j = 0; j < side; j++) { + if (qrcodegen_getModule(codedata, i, j)) { + oledBox(offset + i * 2, offset + j * 2, offset + 1 + i * 2, + offset + 1 + j * 2, false); + } + } + } + } else if (side > 0 && side <= 60) { + int offset = 32 - (side / 2); + for (int i = 0; i < side; i++) { + for (int j = 0; j < side; j++) { + if (qrcodegen_getModule(codedata, i, j)) { + oledClearPixel(offset + i, offset + j); + } + } + } + } + } else { + if (desc) { + oledDrawString(0, 0 * 9, desc, FONT_STANDARD); + } + if (addrlen > 10) { // don't split short addresses + uint32_t rowlen = + (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; + const char **str = + split_message((const uint8_t *)address, addrlen, rowlen); + for (int i = 0; i < 4; i++) { + oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); + } + } else { + oledDrawString(0, (0 + 1) * 9 + 4, address, FONT_FIXED); + } + oledDrawString( + 0, 42, address_n_str(address_n, address_n_count, address_is_account), + FONT_STANDARD); + } - if (!qrcode) { - layoutButtonNo(_("QR Code")); - } + if (!qrcode) { + layoutButtonNo(_("QR Code")); + } - layoutButtonYes(_("Continue")); - oledRefresh(); + layoutButtonYes(_("Continue")); + oledRefresh(); } -void layoutPublicKey(const uint8_t *pubkey) -{ - char desc[16]; - strlcpy(desc, "Public Key: 00", sizeof(desc)); - if (pubkey[0] == 1) { - /* ed25519 public key */ - // pass - leave 00 - } else { - data2hex(pubkey, 1, desc + 12); - } - const char **str = split_message_hex(pubkey + 1, 32 * 2); - layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, - desc, str[0], str[1], str[2], str[3], NULL); +void layoutPublicKey(const uint8_t *pubkey) { + char desc[16]; + strlcpy(desc, "Public Key: 00", sizeof(desc)); + if (pubkey[0] == 1) { + /* ed25519 public key */ + // pass - leave 00 + } else { + data2hex(pubkey, 1, desc + 12); + } + const char **str = split_message_hex(pubkey + 1, 32 * 2); + layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0], + str[1], str[2], str[3], NULL); } -void layoutSignIdentity(const IdentityType *identity, const char *challenge) -{ - char row_proto[8 + 11 + 1]; - char row_hostport[64 + 6 + 1]; - char row_user[64 + 8 + 1]; +void layoutSignIdentity(const IdentityType *identity, const char *challenge) { + char row_proto[8 + 11 + 1]; + char row_hostport[64 + 6 + 1]; + char row_user[64 + 8 + 1]; - bool is_gpg = (strcmp(identity->proto, "gpg") == 0); + bool is_gpg = (strcmp(identity->proto, "gpg") == 0); - if (identity->has_proto && identity->proto[0]) { - if (strcmp(identity->proto, "https") == 0) { - strlcpy(row_proto, _("Web sign in to:"), sizeof(row_proto)); - } else if (is_gpg) { - strlcpy(row_proto, _("GPG sign for:"), sizeof(row_proto)); - } else { - strlcpy(row_proto, identity->proto, sizeof(row_proto)); - char *p = row_proto; - while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, _(" login to:"), sizeof(row_proto)); - } - } else { - strlcpy(row_proto, _("Login to:"), sizeof(row_proto)); - } + if (identity->has_proto && identity->proto[0]) { + if (strcmp(identity->proto, "https") == 0) { + strlcpy(row_proto, _("Web sign in to:"), sizeof(row_proto)); + } else if (is_gpg) { + strlcpy(row_proto, _("GPG sign for:"), sizeof(row_proto)); + } else { + strlcpy(row_proto, identity->proto, sizeof(row_proto)); + char *p = row_proto; + while (*p) { + *p = toupper((int)*p); + p++; + } + strlcat(row_proto, _(" login to:"), sizeof(row_proto)); + } + } else { + strlcpy(row_proto, _("Login to:"), sizeof(row_proto)); + } - if (identity->has_host && identity->host[0]) { - strlcpy(row_hostport, identity->host, sizeof(row_hostport)); - if (identity->has_port && identity->port[0]) { - strlcat(row_hostport, ":", sizeof(row_hostport)); - strlcat(row_hostport, identity->port, sizeof(row_hostport)); - } - } else { - row_hostport[0] = 0; - } + if (identity->has_host && identity->host[0]) { + strlcpy(row_hostport, identity->host, sizeof(row_hostport)); + if (identity->has_port && identity->port[0]) { + strlcat(row_hostport, ":", sizeof(row_hostport)); + strlcat(row_hostport, identity->port, sizeof(row_hostport)); + } + } else { + row_hostport[0] = 0; + } - if (identity->has_user && identity->user[0]) { - strlcpy(row_user, _("user: "), sizeof(row_user)); - strlcat(row_user, identity->user, sizeof(row_user)); - } else { - row_user[0] = 0; - } + if (identity->has_user && identity->user[0]) { + strlcpy(row_user, _("user: "), sizeof(row_user)); + strlcat(row_user, identity->user, sizeof(row_user)); + } else { + row_user[0] = 0; + } - if (is_gpg) { - // Split "First Last " into 2 lines: - // "First Last" - // "first@last.com" - char *email_start = strchr(row_hostport, '<'); - if (email_start) { - strlcpy(row_user, email_start + 1, sizeof(row_user)); - *email_start = 0; - char *email_end = strchr(row_user, '>'); - if (email_end) { - *email_end = 0; - } - } - } + if (is_gpg) { + // Split "First Last " into 2 lines: + // "First Last" + // "first@last.com" + char *email_start = strchr(row_hostport, '<'); + if (email_start) { + strlcpy(row_user, email_start + 1, sizeof(row_user)); + *email_start = 0; + char *email_end = strchr(row_user, '>'); + if (email_end) { + *email_end = 0; + } + } + } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - _("Do you want to sign in?"), - row_proto[0] ? row_proto : NULL, - row_hostport[0] ? row_hostport : NULL, - row_user[0] ? row_user : NULL, - challenge, - NULL, - NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Do you want to sign in?"), + row_proto[0] ? row_proto : NULL, + row_hostport[0] ? row_hostport : NULL, + row_user[0] ? row_user : NULL, challenge, NULL, NULL); } -void layoutDecryptIdentity(const IdentityType *identity) -{ - char row_proto[8 + 11 + 1]; - char row_hostport[64 + 6 + 1]; - char row_user[64 + 8 + 1]; +void layoutDecryptIdentity(const IdentityType *identity) { + char row_proto[8 + 11 + 1]; + char row_hostport[64 + 6 + 1]; + char row_user[64 + 8 + 1]; - if (identity->has_proto && identity->proto[0]) { - strlcpy(row_proto, identity->proto, sizeof(row_proto)); - char *p = row_proto; - while (*p) { *p = toupper((int)*p); p++; } - strlcat(row_proto, _(" decrypt for:"), sizeof(row_proto)); - } else { - strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto)); - } + if (identity->has_proto && identity->proto[0]) { + strlcpy(row_proto, identity->proto, sizeof(row_proto)); + char *p = row_proto; + while (*p) { + *p = toupper((int)*p); + p++; + } + strlcat(row_proto, _(" decrypt for:"), sizeof(row_proto)); + } else { + strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto)); + } - if (identity->has_host && identity->host[0]) { - strlcpy(row_hostport, identity->host, sizeof(row_hostport)); - if (identity->has_port && identity->port[0]) { - strlcat(row_hostport, ":", sizeof(row_hostport)); - strlcat(row_hostport, identity->port, sizeof(row_hostport)); - } - } else { - row_hostport[0] = 0; - } + if (identity->has_host && identity->host[0]) { + strlcpy(row_hostport, identity->host, sizeof(row_hostport)); + if (identity->has_port && identity->port[0]) { + strlcat(row_hostport, ":", sizeof(row_hostport)); + strlcat(row_hostport, identity->port, sizeof(row_hostport)); + } + } else { + row_hostport[0] = 0; + } - if (identity->has_user && identity->user[0]) { - strlcpy(row_user, _("user: "), sizeof(row_user)); - strlcat(row_user, identity->user, sizeof(row_user)); - } else { - row_user[0] = 0; - } + if (identity->has_user && identity->user[0]) { + strlcpy(row_user, _("user: "), sizeof(row_user)); + strlcat(row_user, identity->user, sizeof(row_user)); + } else { + row_user[0] = 0; + } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - _("Do you want to decrypt?"), - row_proto[0] ? row_proto : NULL, - row_hostport[0] ? row_hostport : NULL, - row_user[0] ? row_user : NULL, - NULL, - NULL, - NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), + _("Do you want to decrypt?"), + row_proto[0] ? row_proto : NULL, + row_hostport[0] ? row_hostport : NULL, + row_user[0] ? row_user : NULL, NULL, NULL, NULL); } void layoutU2FDialog(const char *verb, const char *appname) { - layoutDialog(&bmp_webauthn, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); + layoutDialog(&bmp_webauthn, NULL, verb, NULL, verb, _("U2F security key?"), + NULL, appname, NULL, NULL); } -void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address) { - static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; - strlcpy(first_third, address, sizeof(first_third)); +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, + const char *desc, const char *line1, const char *address) { + static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(first_third, address, sizeof(first_third)); - static char second_third[NEM_ADDRESS_SIZE / 3 + 1]; - strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third)); + static char second_third[NEM_ADDRESS_SIZE / 3 + 1]; + strlcpy(second_third, &address[NEM_ADDRESS_SIZE / 3], sizeof(second_third)); - const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; + const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; - layoutDialogSwipe(icon, - btnNo, - btnYes, - desc, - line1, - first_third, - second_third, - third_third, - NULL, - NULL); + layoutDialogSwipe(icon, btnNo, btnYes, desc, line1, first_third, second_third, + third_third, NULL, NULL); } -void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee) { - char str_out[32], str_fee[32]; +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, + const bignum256 *multiplier, uint64_t fee) { + char str_out[32], str_fee[32]; - nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier, str_out, sizeof(str_out)); - nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee, sizeof(str_fee)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier, + str_out, sizeof(str_out)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee, + sizeof(str_fee)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - _("Confirm transfer of"), - str_out, - _("and network fee of"), - str_fee, - NULL, - NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, + _("Confirm transfer of"), str_out, _("and network fee of"), + str_fee, NULL, NULL); } -void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2) { - char str_fee1[32], str_fee2[32]; +void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, + uint64_t fee1, const char *fee2_desc, uint64_t fee2) { + char str_fee1[32], str_fee2[32]; - nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee1, NULL, str_fee1, sizeof(str_fee1)); + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee1, NULL, str_fee1, + sizeof(str_fee1)); - if (fee2_desc) { - nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2, sizeof(str_fee2)); - } + if (fee2_desc) { + nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2, + sizeof(str_fee2)); + } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - confirm ? _("Confirm") : _("Next"), - desc, - fee1_desc, - str_fee1, - fee2_desc, - fee2_desc ? str_fee2 : NULL, - NULL, - NULL); + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), confirm ? _("Confirm") : _("Next"), desc, + fee1_desc, str_fee1, fee2_desc, fee2_desc ? str_fee2 : NULL, NULL, NULL); } -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { - char str_out[32], str_levy[32]; +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + uint8_t network) { + char str_out[32], str_levy[32]; - nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); + nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, + sizeof(str_out)); - if (definition->has_levy) { - nem_mosaicFormatLevy(definition, quantity, multiplier, network, str_levy, sizeof(str_levy)); - } + if (definition->has_levy) { + nem_mosaicFormatLevy(definition, quantity, multiplier, network, str_levy, + sizeof(str_levy)); + } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - definition->has_name ? definition->name : _("Mosaic"), - _("Confirm transfer of"), - str_out, - definition->has_levy ? _("and levy of") : NULL, - definition->has_levy ? str_levy : NULL, - NULL, - NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + definition->has_name ? definition->name : _("Mosaic"), + _("Confirm transfer of"), str_out, + definition->has_levy ? _("and levy of") : NULL, + definition->has_levy ? str_levy : NULL, NULL, NULL); } -void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier) { - char mosaic_name[32]; - nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name)); +void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, + uint64_t quantity, + const bignum256 *multiplier) { + char mosaic_name[32]; + nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name)); - char str_out[32]; - nem_mosaicFormatAmount(NULL, quantity, multiplier, str_out, sizeof(str_out)); + char str_out[32]; + nem_mosaicFormatAmount(NULL, quantity, multiplier, str_out, sizeof(str_out)); - char *decimal = strchr(str_out, '.'); - if (decimal != NULL) { - *decimal = '\0'; - } + char *decimal = strchr(str_out, '.'); + if (decimal != NULL) { + *decimal = '\0'; + } - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("I take the risk"), - _("Unknown Mosaic"), - _("Confirm transfer of"), - str_out, - _("raw units of"), - mosaic_name, - NULL, - NULL); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), + _("Unknown Mosaic"), _("Confirm transfer of"), str_out, + _("raw units of"), mosaic_name, NULL, NULL); } -void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted) { - if (length >= 1 && payload[0] == 0xFE) { - char encoded[(length - 1) * 2 + 1]; - data2hex(&payload[1], length - 1, encoded); +void layoutNEMTransferPayload(const uint8_t *payload, size_t length, + bool encrypted) { + if (length >= 1 && payload[0] == 0xFE) { + char encoded[(length - 1) * 2 + 1]; + data2hex(&payload[1], length - 1, encoded); - const char **str = split_message((uint8_t *) encoded, sizeof(encoded) - 1, 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), - encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), - str[0], str[1], str[2], str[3], NULL, NULL); - } else { - const char **str = split_message(payload, length, 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), - encrypted ? _("Encrypted message") : _("Unencrypted message"), - str[0], str[1], str[2], str[3], NULL, NULL); - } + const char **str = + split_message((uint8_t *)encoded, sizeof(encoded) - 1, 16); + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), + encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), str[0], + str[1], str[2], str[3], NULL, NULL); + } else { + const char **str = split_message(payload, length, 16); + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), + encrypted ? _("Encrypted message") : _("Unencrypted message"), str[0], + str[1], str[2], str[3], NULL, NULL); + } } void layoutNEMMosaicDescription(const char *description) { - const char **str = split_message((uint8_t *) description, strlen(description), 16); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), - _("Mosaic Description"), - str[0], str[1], str[2], str[3], NULL, NULL); + const char **str = + split_message((uint8_t *)description, strlen(description), 16); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + _("Mosaic Description"), str[0], str[1], str[2], str[3], + NULL, NULL); } void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { - const NEMMosaicDefinition *mosaic; - if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic, network)) { - mosaic = definition; - } else { - mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); - } + const NEMMosaicDefinition *mosaic; + if (nem_mosaicMatches(definition, definition->levy_namespace, + definition->levy_mosaic, network)) { + mosaic = definition; + } else { + mosaic = nem_mosaicByName(definition->levy_namespace, + definition->levy_mosaic, network); + } - char mosaic_name[32]; - if (mosaic == NULL) { - nem_mosaicFormatName(definition->levy_namespace, definition->levy_mosaic, mosaic_name, sizeof(mosaic_name)); - } + char mosaic_name[32]; + if (mosaic == NULL) { + nem_mosaicFormatName(definition->levy_namespace, definition->levy_mosaic, + mosaic_name, sizeof(mosaic_name)); + } - char str_out[32]; + char str_out[32]; - switch (definition->levy) { - case NEMMosaicLevy_MosaicLevy_Percentile: - bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); + switch (definition->levy) { + case NEMMosaicLevy_MosaicLevy_Percentile: + bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, + sizeof(str_out)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - _("Percentile Levy"), - _("Raw levy value is"), - str_out, - _("in"), - mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name) : mosaic_name, - NULL, - NULL); - break; + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), _("Percentile Levy"), + _("Raw levy value is"), str_out, _("in"), + mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name) + : mosaic_name, + NULL, NULL); + break; - case NEMMosaicLevy_MosaicLevy_Absolute: - default: - nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - _("Absolute Levy"), - _("Levy is"), - str_out, - mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL) : _("in raw units of"), - mosaic ? NULL : mosaic_name, - NULL, - NULL); - break; - } + case NEMMosaicLevy_MosaicLevy_Absolute: + default: + nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, + sizeof(str_out)); + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), _("Absolute Levy"), + _("Levy is"), str_out, + mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL) + : _("in raw units of"), + mosaic ? NULL : mosaic_name, NULL, NULL); + break; + } } -static inline bool is_slip18(const uint32_t *address_n, size_t address_n_count) -{ - return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9; +static inline bool is_slip18(const uint32_t *address_n, + size_t address_n_count) { + return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && + (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9; } -void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign) -{ - char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); - char desc_buf[32]; - if (is_slip18(address_n, address_n_count)) { - if (final_sign) { - strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); - desc_buf[16] = '0' + (address_n[1] & 0x7FFFFFFF); - } else { - strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf)); - desc_buf[18] = '0' + (address_n[1] & 0x7FFFFFFF); - } - desc = desc_buf; - } - char str[4][17]; - if (len == 32) { - data2hex(data , 8, str[0]); - data2hex(data + 8, 8, str[1]); - data2hex(data + 16, 8, str[2]); - data2hex(data + 24, 8, str[3]); - } else { - strlcpy(str[0], "Data", sizeof(str[0])); - strlcpy(str[1], "of", sizeof(str[1])); - strlcpy(str[2], "unsupported", sizeof(str[2])); - strlcpy(str[3], "length", sizeof(str[3])); - } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, - str[0], str[1], str[2], str[3], NULL, NULL); +void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, + const uint8_t *data, uint32_t len, bool final_sign) { + char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); + char desc_buf[32]; + if (is_slip18(address_n, address_n_count)) { + if (final_sign) { + strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf)); + desc_buf[16] = '0' + (address_n[1] & 0x7FFFFFFF); + } else { + strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf)); + desc_buf[18] = '0' + (address_n[1] & 0x7FFFFFFF); + } + desc = desc_buf; + } + char str[4][17]; + if (len == 32) { + data2hex(data, 8, str[0]); + data2hex(data + 8, 8, str[1]); + data2hex(data + 16, 8, str[2]); + data2hex(data + 24, 8, str[3]); + } else { + strlcpy(str[0], "Data", sizeof(str[0])); + strlcpy(str[1], "of", sizeof(str[1])); + strlcpy(str[2], "unsupported", sizeof(str[2])); + strlcpy(str[3], "length", sizeof(str[3])); + } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, str[0], + str[1], str[2], str[3], NULL, NULL); } diff --git a/firmware/layout2.h b/firmware/layout2.h index f3935f4094..54b32baee6 100644 --- a/firmware/layout2.h +++ b/firmware/layout2.h @@ -20,10 +20,10 @@ #ifndef __LAYOUT2_H__ #define __LAYOUT2_H__ -#include "layout.h" -#include "coins.h" -#include "bitmaps.h" #include "bignum.h" +#include "bitmaps.h" +#include "coins.h" +#include "layout.h" #include "trezor.h" #include "messages-bitcoin.pb.h" @@ -38,7 +38,10 @@ extern void *layoutLast; #define layoutSwipe oledSwipeLeft #endif -void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, + const char *btnYes, const char *desc, const char *line1, + const char *line2, const char *line3, const char *line4, + const char *line5, const char *line6); void layoutProgressSwipe(const char *desc, int permil); void layoutScreensaver(void); @@ -46,31 +49,44 @@ void layoutHome(void); void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); void layoutConfirmOmni(const uint8_t *data, uint32_t size); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); -void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); +void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, + uint64_t amount_fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutVerifyAddress(const CoinInfo *coin, const char *address); void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutCipherKeyValue(bool encrypt, const char *key); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); -void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); +void layoutDecryptMessage(const uint8_t *msg, uint32_t len, + const char *address); void layoutResetWord(const char *word, int pass, int word_pos, bool last); -void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account); +void layoutAddress(const char *address, const char *desc, bool qrcode, + bool ignorecase, const uint32_t *address_n, + size_t address_n_count, bool address_is_account); void layoutPublicKey(const uint8_t *pubkey); void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutDecryptIdentity(const IdentityType *identity); void layoutU2FDialog(const char *verb, const char *appname); -void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); -void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); -void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); -void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); -void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); -void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); +void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, + const char *desc, const char *line1, const char *address); +void layoutNEMTransferXEM(const char *desc, uint64_t quantity, + const bignum256 *multiplier, uint64_t fee); +void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, + uint64_t fee1, const char *fee2_desc, uint64_t fee2); +void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + uint8_t network); +void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, + uint64_t quantity, + const bignum256 *multiplier); +void layoutNEMTransferPayload(const uint8_t *payload, size_t length, + bool encrypted); void layoutNEMMosaicDescription(const char *description); void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); -void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); +void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, + const uint8_t *data, uint32_t len, bool final_sign); const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); const char **split_message_hex(const uint8_t *msg, uint32_t len); diff --git a/firmware/lisk.c b/firmware/lisk.c index efc8721108..054b352667 100644 --- a/firmware/lisk.c +++ b/firmware/lisk.c @@ -18,353 +18,337 @@ */ #include "lisk.h" -#include "fsm.h" -#include "curves.h" -#include "layout2.h" #include "bitmaps.h" -#include "util.h" -#include "gettext.h" #include "crypto.h" -#include "protect.h" +#include "curves.h" +#include "fsm.h" +#include "gettext.h" +#include "layout2.h" #include "messages.pb.h" +#include "protect.h" +#include "util.h" -void lisk_get_address_from_public_key(const uint8_t *public_key, char *address) { - uint64_t digest[4]; - sha256_Raw(public_key, 32, (uint8_t *)digest); - bn_format_uint64(digest[0], NULL, "L", 0, 0, false, address, MAX_LISK_ADDRESS_SIZE); +void lisk_get_address_from_public_key(const uint8_t *public_key, + char *address) { + uint64_t digest[4]; + sha256_Raw(public_key, 32, (uint8_t *)digest); + bn_format_uint64(digest[0], NULL, "L", 0, 0, false, address, + MAX_LISK_ADDRESS_SIZE); } -void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) { - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22); - uint8_t varint[5]; - uint32_t l = ser_length(message_len, varint); - sha256_Update(&ctx, varint, l); - sha256_Update(&ctx, message, message_len); - sha256_Final(&ctx, hash); - sha256_Raw(hash, 32, hash); +void lisk_message_hash(const uint8_t *message, size_t message_len, + uint8_t hash[32]) { + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22); + uint8_t varint[5]; + uint32_t l = ser_length(message_len, varint); + sha256_Update(&ctx, varint, l); + sha256_Update(&ctx, message, message_len); + sha256_Final(&ctx, hash); + sha256_Raw(hash, 32, hash); } -void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp) -{ - layoutSignMessage(msg->message.bytes, msg->message.size); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } +void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, + LiskMessageSignature *resp) { + layoutSignMessage(msg->message.bytes, msg->message.size); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - layoutProgressSwipe(_("Signing"), 0); + layoutProgressSwipe(_("Signing"), 0); - uint8_t signature[64]; - uint8_t hash[32]; - lisk_message_hash(msg->message.bytes, msg->message.size, hash); + uint8_t signature[64]; + uint8_t hash[32]; + lisk_message_hash(msg->message.bytes, msg->message.size, hash); - ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], signature); - memcpy(resp->signature.bytes, signature, sizeof(signature)); - memcpy(resp->public_key.bytes, &node->public_key[1], 32); + memcpy(resp->signature.bytes, signature, sizeof(signature)); + memcpy(resp->public_key.bytes, &node->public_key[1], 32); - resp->has_signature = true; - resp->signature.size = 64; - resp->has_public_key = true; - resp->public_key.size = 32; + resp->has_signature = true; + resp->signature.size = 64; + resp->has_public_key = true; + resp->public_key.size = 32; } -bool lisk_verify_message(const LiskVerifyMessage *msg) -{ - uint8_t hash[32]; - lisk_message_hash(msg->message.bytes, msg->message.size, hash); - return 0 == ed25519_sign_open(hash, 32, msg->public_key.bytes, msg->signature.bytes ); +bool lisk_verify_message(const LiskVerifyMessage *msg) { + uint8_t hash[32]; + lisk_message_hash(msg->message.bytes, msg->message.size, hash); + return 0 == ed25519_sign_open(hash, 32, msg->public_key.bytes, + msg->signature.bytes); } -static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) -{ - if(!msg->transaction.has_sender_public_key) { - memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32); - } +static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) { + if (!msg->transaction.has_sender_public_key) { + memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32); + } - // For CastVotes transactions, recipientId should be equal to transaction creator address. - if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) { - msg->transaction.has_recipient_id = true; - lisk_get_address_from_public_key(&node->public_key[1], msg->transaction.recipient_id); - } + // For CastVotes transactions, recipientId should be equal to transaction + // creator address. + if (msg->transaction.type == LiskTransactionType_CastVotes && + !msg->transaction.has_recipient_id) { + msg->transaction.has_recipient_id = true; + lisk_get_address_from_public_key(&node->public_key[1], + msg->transaction.recipient_id); + } } -static void lisk_hashupdate_uint32(SHA256_CTX *ctx, uint32_t value) -{ - uint8_t data[4]; - write_le(data, value); - sha256_Update(ctx, data, sizeof(data)); +static void lisk_hashupdate_uint32(SHA256_CTX *ctx, uint32_t value) { + uint8_t data[4]; + write_le(data, value); + sha256_Update(ctx, data, sizeof(data)); } -static void lisk_hashupdate_uint64_le(SHA256_CTX *ctx, uint64_t value) -{ - sha256_Update(ctx, (uint8_t *)&value, sizeof(uint64_t)); +static void lisk_hashupdate_uint64_le(SHA256_CTX *ctx, uint64_t value) { + sha256_Update(ctx, (uint8_t *)&value, sizeof(uint64_t)); } -static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value) -{ - uint8_t data[8]; - data[0] = value >> 56; - data[1] = value >> 48; - data[2] = value >> 40; - data[3] = value >> 32; - data[4] = value >> 24; - data[5] = value >> 16; - data[6] = value >> 8; - data[7] = value; - sha256_Update(ctx, data, sizeof(data)); +static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value) { + uint8_t data[8]; + data[0] = value >> 56; + data[1] = value >> 48; + data[2] = value >> 40; + data[3] = value >> 32; + data[4] = value >> 24; + data[5] = value >> 16; + data[6] = value >> 8; + data[7] = value; + sha256_Update(ctx, data, sizeof(data)); } -static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, LiskTransactionAsset *asset) -{ - switch (type) { - case LiskTransactionType_Transfer: - if (asset->has_data) { - sha256_Update(ctx, (const uint8_t *)asset->data, strlen(asset->data)); - } - break; - case LiskTransactionType_RegisterDelegate: - if (asset->has_delegate && asset->delegate.has_username) { - sha256_Update(ctx, (const uint8_t *)asset->delegate.username, strlen(asset->delegate.username)); - } - break; - case LiskTransactionType_CastVotes: { - for (int i = 0; i < asset->votes_count; i++) { - sha256_Update(ctx, (uint8_t *)asset->votes[i], strlen(asset->votes[i])); - } - break; - } - case LiskTransactionType_RegisterSecondPassphrase: - if (asset->has_signature && asset->signature.has_public_key) { - sha256_Update(ctx, asset->signature.public_key.bytes, asset->signature.public_key.size); - } - break; - case LiskTransactionType_RegisterMultisignatureAccount: - if (asset->has_multisignature) { - sha256_Update(ctx, (uint8_t *)&(asset->multisignature.min), 1); - sha256_Update(ctx, (uint8_t *)&(asset->multisignature.life_time), 1); - for (int i = 0; i < asset->multisignature.keys_group_count; i++) { - sha256_Update(ctx, (uint8_t *)asset->multisignature.keys_group[i], strlen(asset->multisignature.keys_group[i])); - }; - } - break; - default: - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); - break; - } +static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, + LiskTransactionAsset *asset) { + switch (type) { + case LiskTransactionType_Transfer: + if (asset->has_data) { + sha256_Update(ctx, (const uint8_t *)asset->data, strlen(asset->data)); + } + break; + case LiskTransactionType_RegisterDelegate: + if (asset->has_delegate && asset->delegate.has_username) { + sha256_Update(ctx, (const uint8_t *)asset->delegate.username, + strlen(asset->delegate.username)); + } + break; + case LiskTransactionType_CastVotes: { + for (int i = 0; i < asset->votes_count; i++) { + sha256_Update(ctx, (uint8_t *)asset->votes[i], strlen(asset->votes[i])); + } + break; + } + case LiskTransactionType_RegisterSecondPassphrase: + if (asset->has_signature && asset->signature.has_public_key) { + sha256_Update(ctx, asset->signature.public_key.bytes, + asset->signature.public_key.size); + } + break; + case LiskTransactionType_RegisterMultisignatureAccount: + if (asset->has_multisignature) { + sha256_Update(ctx, (uint8_t *)&(asset->multisignature.min), 1); + sha256_Update(ctx, (uint8_t *)&(asset->multisignature.life_time), 1); + for (int i = 0; i < asset->multisignature.keys_group_count; i++) { + sha256_Update(ctx, (uint8_t *)asset->multisignature.keys_group[i], + strlen(asset->multisignature.keys_group[i])); + }; + } + break; + default: + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid transaction type")); + break; + } } #define MAX_LISK_VALUE_SIZE 20 -static void lisk_format_value(uint64_t value, char *formated_value) -{ - bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, MAX_LISK_VALUE_SIZE); +static void lisk_format_value(uint64_t value, char *formated_value) { + bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, + MAX_LISK_VALUE_SIZE); } -void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) -{ - lisk_update_raw_tx(node, msg); +void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) { + lisk_update_raw_tx(node, msg); - if(msg->has_transaction) { - SHA256_CTX ctx; - sha256_Init(&ctx); + if (msg->has_transaction) { + SHA256_CTX ctx; + sha256_Init(&ctx); - switch (msg->transaction.type) { - case LiskTransactionType_Transfer: - layoutRequireConfirmTx(msg->transaction.recipient_id, msg->transaction.amount); - break; - case LiskTransactionType_RegisterDelegate: - layoutRequireConfirmDelegateRegistration(&msg->transaction.asset); - break; - case LiskTransactionType_CastVotes: - layoutRequireConfirmCastVotes(&msg->transaction.asset); - break; - case LiskTransactionType_RegisterSecondPassphrase: - layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes); - break; - case LiskTransactionType_RegisterMultisignatureAccount: - layoutRequireConfirmMultisig(&msg->transaction.asset); - break; - default: - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); - layoutHome(); - break; - } - if (!protectButton(( - msg->transaction.type == LiskTransactionType_RegisterSecondPassphrase ? - ButtonRequestType_ButtonRequest_PublicKey : - ButtonRequestType_ButtonRequest_SignTx), - false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; - } + switch (msg->transaction.type) { + case LiskTransactionType_Transfer: + layoutRequireConfirmTx(msg->transaction.recipient_id, + msg->transaction.amount); + break; + case LiskTransactionType_RegisterDelegate: + layoutRequireConfirmDelegateRegistration(&msg->transaction.asset); + break; + case LiskTransactionType_CastVotes: + layoutRequireConfirmCastVotes(&msg->transaction.asset); + break; + case LiskTransactionType_RegisterSecondPassphrase: + layoutLiskPublicKey(msg->transaction.asset.signature.public_key.bytes); + break; + case LiskTransactionType_RegisterMultisignatureAccount: + layoutRequireConfirmMultisig(&msg->transaction.asset); + break; + default: + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid transaction type")); + layoutHome(); + break; + } + if (!protectButton((msg->transaction.type == + LiskTransactionType_RegisterSecondPassphrase + ? ButtonRequestType_ButtonRequest_PublicKey + : ButtonRequestType_ButtonRequest_SignTx), + false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); + layoutHome(); + return; + } - layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); - layoutHome(); - return; - } - layoutProgressSwipe(_("Signing transaction"), 0); + layoutRequireConfirmFee(msg->transaction.fee, msg->transaction.amount); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); + layoutHome(); + return; + } + layoutProgressSwipe(_("Signing transaction"), 0); - sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1); + sha256_Update(&ctx, (const uint8_t *)&msg->transaction.type, 1); - lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp); + lisk_hashupdate_uint32(&ctx, msg->transaction.timestamp); - sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32); + sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32); - if (msg->transaction.has_requester_public_key) { - sha256_Update(&ctx, msg->transaction.requester_public_key.bytes, msg->transaction.requester_public_key.size); - } + if (msg->transaction.has_requester_public_key) { + sha256_Update(&ctx, msg->transaction.requester_public_key.bytes, + msg->transaction.requester_public_key.size); + } - uint64_t recipient_id = 0; - if (msg->transaction.has_recipient_id && msg->transaction.recipient_id[0] != 0) { - // parse integer from lisk address ("123L" -> 123) - for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) { - if (msg->transaction.recipient_id[i] < '0' || msg->transaction.recipient_id[i] > '9') { - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid recipient_id")); - layoutHome(); - return; - } - recipient_id *= 10; - recipient_id += (msg->transaction.recipient_id[i] - '0'); - } - } - lisk_hashupdate_uint64_be(&ctx, recipient_id); - lisk_hashupdate_uint64_le(&ctx, msg->transaction.amount); + uint64_t recipient_id = 0; + if (msg->transaction.has_recipient_id && + msg->transaction.recipient_id[0] != 0) { + // parse integer from lisk address ("123L" -> 123) + for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) { + if (msg->transaction.recipient_id[i] < '0' || + msg->transaction.recipient_id[i] > '9') { + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid recipient_id")); + layoutHome(); + return; + } + recipient_id *= 10; + recipient_id += (msg->transaction.recipient_id[i] - '0'); + } + } + lisk_hashupdate_uint64_be(&ctx, recipient_id); + lisk_hashupdate_uint64_le(&ctx, msg->transaction.amount); - lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset); + lisk_hashupdate_asset(&ctx, msg->transaction.type, &msg->transaction.asset); - // if signature exist calculate second signature - if (msg->transaction.has_signature) { - sha256_Update(&ctx, msg->transaction.signature.bytes, msg->transaction.signature.size); - } + // if signature exist calculate second signature + if (msg->transaction.has_signature) { + sha256_Update(&ctx, msg->transaction.signature.bytes, + msg->transaction.signature.size); + } - uint8_t hash[32]; - sha256_Final(&ctx, hash); - ed25519_sign(hash, 32, node->private_key, &node->public_key[1], resp->signature.bytes); + uint8_t hash[32]; + sha256_Final(&ctx, hash); + ed25519_sign(hash, 32, node->private_key, &node->public_key[1], + resp->signature.bytes); - resp->has_signature = true; - resp->signature.size = 64; - } + resp->has_signature = true; + resp->signature.size = 64; + } } // Layouts -void layoutLiskPublicKey(const uint8_t *pubkey) -{ - const char **str = split_message_hex(pubkey, 32); - layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, - _("Public Key:"), str[0], str[1], str[2], str[3], NULL); +void layoutLiskPublicKey(const uint8_t *pubkey) { + const char **str = split_message_hex(pubkey, 32); + layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, + _("Public Key:"), str[0], str[1], str[2], str[3], NULL); } -void layoutLiskVerifyAddress(const char *address) -{ - const char **str = split_message((const uint8_t *)address, strlen(address), 10); - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), - _("Confirm address?"), - _("Message signed by:"), - str[0], str[1], NULL, NULL, NULL); +void layoutLiskVerifyAddress(const char *address) { + const char **str = + split_message((const uint8_t *)address, strlen(address), 10); + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), + _("Confirm address?"), _("Message signed by:"), str[0], + str[1], NULL, NULL, NULL); } -void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) -{ - char formated_amount[MAX_LISK_VALUE_SIZE]; - const char **str = split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16); - lisk_format_value(amount, formated_amount); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - NULL, - _("Confirm sending"), - formated_amount, - _("to:"), - str[0], - str[1], - NULL - ); +void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) { + char formated_amount[MAX_LISK_VALUE_SIZE]; + const char **str = + split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16); + lisk_format_value(amount, formated_amount); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm sending"), formated_amount, _("to:"), str[0], + str[1], NULL); } -void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) -{ - char formated_amount[MAX_LISK_VALUE_SIZE]; - char formated_fee[MAX_LISK_VALUE_SIZE]; - lisk_format_value(amount, formated_amount); - lisk_format_value(fee, formated_fee); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - NULL, - _("Confirm transaction"), - formated_amount, - _("fee:"), - formated_fee, - NULL, - NULL - ); +void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) { + char formated_amount[MAX_LISK_VALUE_SIZE]; + char formated_fee[MAX_LISK_VALUE_SIZE]; + lisk_format_value(amount, formated_amount); + lisk_format_value(fee, formated_fee); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm transaction"), formated_amount, _("fee:"), + formated_fee, NULL, NULL); } -void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) -{ - if (asset->has_delegate && asset->delegate.has_username) { - const char **str = split_message((const uint8_t *)asset->delegate.username, strlen(asset->delegate.username), 20); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - NULL, - _("Confirm transaction"), - _("Do you really want to"), - _("register a delegate?"), - str[0], - str[1], - NULL - ); - } +void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) { + if (asset->has_delegate && asset->delegate.has_username) { + const char **str = split_message((const uint8_t *)asset->delegate.username, + strlen(asset->delegate.username), 20); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm transaction"), _("Do you really want to"), + _("register a delegate?"), str[0], str[1], NULL); + } } -void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) -{ - uint8_t plus = 0; - uint8_t minus = 0; - char add_votes_txt[13]; - char remove_votes_txt[16]; +void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) { + uint8_t plus = 0; + uint8_t minus = 0; + char add_votes_txt[13]; + char remove_votes_txt[16]; - for (int i = 0; i < asset->votes_count; i++) { - if (asset->votes[i][0] == '+') { - plus += 1; - } else { - minus += 1; - } - } + for (int i = 0; i < asset->votes_count; i++) { + if (asset->votes[i][0] == '+') { + plus += 1; + } else { + minus += 1; + } + } - bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_votes_txt, sizeof(add_votes_txt)); - bn_format_uint64(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt, sizeof(remove_votes_txt)); + bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_votes_txt, + sizeof(add_votes_txt)); + bn_format_uint64(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt, + sizeof(remove_votes_txt)); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - NULL, - _("Confirm transaction"), - add_votes_txt, - remove_votes_txt, - NULL, - NULL, - NULL - ); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm transaction"), add_votes_txt, remove_votes_txt, + NULL, NULL, NULL); } -void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) -{ - char keys_group_str[25]; - char life_time_str[14]; - char min_str[8]; +void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) { + char keys_group_str[25]; + char life_time_str[14]; + char min_str[8]; - bn_format_uint64(asset->multisignature.keys_group_count, "Keys group length: ", NULL, 0, 0, false, keys_group_str, sizeof(keys_group_str)); - bn_format_uint64(asset->multisignature.life_time, "Life time: ", NULL, 0, 0, false, life_time_str, sizeof(life_time_str)); - bn_format_uint64(asset->multisignature.min, "Min: ", NULL, 0, 0, false, min_str, sizeof(min_str)); + bn_format_uint64(asset->multisignature.keys_group_count, + "Keys group length: ", NULL, 0, 0, false, keys_group_str, + sizeof(keys_group_str)); + bn_format_uint64(asset->multisignature.life_time, "Life time: ", NULL, 0, 0, + false, life_time_str, sizeof(life_time_str)); + bn_format_uint64(asset->multisignature.min, "Min: ", NULL, 0, 0, false, + min_str, sizeof(min_str)); - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), - NULL, - _("Confirm transaction"), - keys_group_str, - life_time_str, - min_str, - NULL, - NULL - ); + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Confirm transaction"), keys_group_str, life_time_str, + min_str, NULL, NULL); } \ No newline at end of file diff --git a/firmware/lisk.h b/firmware/lisk.h index bac931eff2..bf0456b58a 100644 --- a/firmware/lisk.h +++ b/firmware/lisk.h @@ -26,7 +26,8 @@ #define MAX_LISK_ADDRESS_SIZE 23 -void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp); +void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, + LiskMessageSignature *resp); bool lisk_verify_message(const LiskVerifyMessage *msg); void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); diff --git a/firmware/messages.c b/firmware/messages.c index d944ccbe45..f04b07291a 100644 --- a/firmware/messages.c +++ b/firmware/messages.c @@ -19,56 +19,53 @@ #include -#include "trezor.h" -#include "messages.h" #include "debug.h" #include "fsm.h" -#include "util.h" #include "gettext.h" #include "memzero.h" +#include "messages.h" +#include "trezor.h" +#include "util.h" +#include "messages.pb.h" #include "pb_decode.h" #include "pb_encode.h" -#include "messages.pb.h" struct MessagesMap_t { - char type; // n = normal, d = debug - char dir; // i = in, o = out - uint16_t msg_id; - const pb_field_t *fields; - void (*process_func)(const void *ptr); + char type; // n = normal, d = debug + char dir; // i = in, o = out + uint16_t msg_id; + const pb_field_t *fields; + void (*process_func)(const void *ptr); }; static const struct MessagesMap_t MessagesMap[] = { #include "messages_map.h" - // end - {0, 0, 0, 0, 0} -}; + // end + {0, 0, 0, 0, 0}}; #include "messages_map_limits.h" -const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) -{ - const struct MessagesMap_t *m = MessagesMap; - while (m->type) { - if (type == m->type && dir == m->dir && msg_id == m->msg_id) { - return m->fields; - } - m++; - } - return 0; +const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) { + const struct MessagesMap_t *m = MessagesMap; + while (m->type) { + if (type == m->type && dir == m->dir && msg_id == m->msg_id) { + return m->fields; + } + m++; + } + return 0; } -void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) -{ - const struct MessagesMap_t *m = MessagesMap; - while (m->type) { - if (type == m->type && dir == m->dir && msg_id == m->msg_id) { - m->process_func(ptr); - return; - } - m++; - } +void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) { + const struct MessagesMap_t *m = MessagesMap; + while (m->type) { + if (type == m->type && dir == m->dir && msg_id == m->msg_id) { + m->process_func(ptr); + return; + } + m++; + } } static uint32_t msg_out_start = 0; @@ -85,225 +82,219 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE]; #endif -static inline void msg_out_append(uint8_t c) -{ - if (msg_out_cur == 0) { - msg_out[msg_out_end * 64] = '?'; - msg_out_cur = 1; - } - msg_out[msg_out_end * 64 + msg_out_cur] = c; - msg_out_cur++; - if (msg_out_cur == 64) { - msg_out_cur = 0; - msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); - } +static inline void msg_out_append(uint8_t c) { + if (msg_out_cur == 0) { + msg_out[msg_out_end * 64] = '?'; + msg_out_cur = 1; + } + msg_out[msg_out_end * 64 + msg_out_cur] = c; + msg_out_cur++; + if (msg_out_cur == 64) { + msg_out_cur = 0; + msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); + } } #if DEBUG_LINK -static inline void msg_debug_out_append(uint8_t c) -{ - if (msg_debug_out_cur == 0) { - msg_debug_out[msg_debug_out_end * 64] = '?'; - msg_debug_out_cur = 1; - } - msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = c; - msg_debug_out_cur++; - if (msg_debug_out_cur == 64) { - msg_debug_out_cur = 0; - msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); - } +static inline void msg_debug_out_append(uint8_t c) { + if (msg_debug_out_cur == 0) { + msg_debug_out[msg_debug_out_end * 64] = '?'; + msg_debug_out_cur = 1; + } + msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = c; + msg_debug_out_cur++; + if (msg_debug_out_cur == 64) { + msg_debug_out_cur = 0; + msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); + } } #endif -static inline void msg_out_pad(void) -{ - if (msg_out_cur == 0) return; - while (msg_out_cur < 64) { - msg_out[msg_out_end * 64 + msg_out_cur] = 0; - msg_out_cur++; - } - msg_out_cur = 0; - msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); +static inline void msg_out_pad(void) { + if (msg_out_cur == 0) return; + while (msg_out_cur < 64) { + msg_out[msg_out_end * 64 + msg_out_cur] = 0; + msg_out_cur++; + } + msg_out_cur = 0; + msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); } #if DEBUG_LINK -static inline void msg_debug_out_pad(void) -{ - if (msg_debug_out_cur == 0) return; - while (msg_debug_out_cur < 64) { - msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0; - msg_debug_out_cur++; - } - msg_debug_out_cur = 0; - msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); +static inline void msg_debug_out_pad(void) { + if (msg_debug_out_cur == 0) return; + while (msg_debug_out_cur < 64) { + msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0; + msg_debug_out_cur++; + } + msg_debug_out_cur = 0; + msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); } #endif -static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - (void)stream; - for (size_t i = 0; i < count; i++) { - msg_out_append(buf[i]); - } - return true; +static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, + size_t count) { + (void)stream; + for (size_t i = 0; i < count; i++) { + msg_out_append(buf[i]); + } + return true; } #if DEBUG_LINK -static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - (void)stream; - for (size_t i = 0; i < count; i++) { - msg_debug_out_append(buf[i]); - } - return true; +static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, + size_t count) { + (void)stream; + for (size_t i = 0; i < count; i++) { + msg_debug_out_append(buf[i]); + } + return true; } #endif -bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) -{ - const pb_field_t *fields = MessageFields(type, 'o', msg_id); - if (!fields) { // unknown message - return false; - } +bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) { + const pb_field_t *fields = MessageFields(type, 'o', msg_id); + if (!fields) { // unknown message + return false; + } - size_t len; - if (!pb_get_encoded_size(&len, fields, msg_ptr)) { - return false; - } + size_t len; + if (!pb_get_encoded_size(&len, fields, msg_ptr)) { + return false; + } - void (*append)(uint8_t); - bool (*pb_callback)(pb_ostream_t *, const uint8_t *, size_t); + void (*append)(uint8_t); + bool (*pb_callback)(pb_ostream_t *, const uint8_t *, size_t); - if (type == 'n') { - append = msg_out_append; - pb_callback = pb_callback_out; - } else + if (type == 'n') { + append = msg_out_append; + pb_callback = pb_callback_out; + } else #if DEBUG_LINK - if (type == 'd') { - append = msg_debug_out_append; - pb_callback = pb_debug_callback_out; - } else + if (type == 'd') { + append = msg_debug_out_append; + pb_callback = pb_debug_callback_out; + } else #endif - { - return false; - } + { + return false; + } - append('#'); - append('#'); - append((msg_id >> 8) & 0xFF); - append(msg_id & 0xFF); - append((len >> 24) & 0xFF); - append((len >> 16) & 0xFF); - append((len >> 8) & 0xFF); - append(len & 0xFF); - pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0}; - bool status = pb_encode(&stream, fields, msg_ptr); - if (type == 'n') { - msg_out_pad(); - } + append('#'); + append('#'); + append((msg_id >> 8) & 0xFF); + append(msg_id & 0xFF); + append((len >> 24) & 0xFF); + append((len >> 16) & 0xFF); + append((len >> 8) & 0xFF); + append(len & 0xFF); + pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0}; + bool status = pb_encode(&stream, fields, msg_ptr); + if (type == 'n') { + msg_out_pad(); + } #if DEBUG_LINK - else if (type == 'd') { - msg_debug_out_pad(); - } + else if (type == 'd') { + msg_debug_out_pad(); + } #endif - return status; + return status; } enum { - READSTATE_IDLE, - READSTATE_READING, + READSTATE_IDLE, + READSTATE_READING, }; -void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) -{ - static uint8_t msg_data[MSG_IN_SIZE]; - memzero(msg_data, sizeof(msg_data)); - pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); - bool status = pb_decode(&stream, fields, msg_data); - if (status) { - MessageProcessFunc(type, 'i', msg_id, msg_data); - } else { - fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); - } +void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, + uint8_t *msg_raw, uint32_t msg_size) { + static uint8_t msg_data[MSG_IN_SIZE]; + memzero(msg_data, sizeof(msg_data)); + pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); + bool status = pb_decode(&stream, fields, msg_data); + if (status) { + MessageProcessFunc(type, 'i', msg_id, msg_data); + } else { + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); + } } -void msg_read_common(char type, const uint8_t *buf, uint32_t len) -{ - static char read_state = READSTATE_IDLE; - static uint8_t msg_in[MSG_IN_SIZE]; - static uint16_t msg_id = 0xFFFF; - static uint32_t msg_size = 0; - static uint32_t msg_pos = 0; - static const pb_field_t *fields = 0; +void msg_read_common(char type, const uint8_t *buf, uint32_t len) { + static char read_state = READSTATE_IDLE; + static uint8_t msg_in[MSG_IN_SIZE]; + static uint16_t msg_id = 0xFFFF; + static uint32_t msg_size = 0; + static uint32_t msg_pos = 0; + static const pb_field_t *fields = 0; - if (len != 64) return; + if (len != 64) return; - if (read_state == READSTATE_IDLE) { - if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard - return; - } - msg_id = (buf[3] << 8) + buf[4]; - msg_size = ((uint32_t) buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; + if (read_state == READSTATE_IDLE) { + if (buf[0] != '?' || buf[1] != '#' || + buf[2] != '#') { // invalid start - discard + return; + } + msg_id = (buf[3] << 8) + buf[4]; + msg_size = + ((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; - fields = MessageFields(type, 'i', msg_id); - if (!fields) { // unknown message - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); - return; - } - if (msg_size > MSG_IN_SIZE) { // message is too big :( - fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); - return; - } + fields = MessageFields(type, 'i', msg_id); + if (!fields) { // unknown message + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Unknown message")); + return; + } + if (msg_size > MSG_IN_SIZE) { // message is too big :( + fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); + return; + } - read_state = READSTATE_READING; + read_state = READSTATE_READING; - memcpy(msg_in, buf + 9, len - 9); - msg_pos = len - 9; - } else - if (read_state == READSTATE_READING) { - if (buf[0] != '?') { // invalid contents - read_state = READSTATE_IDLE; - return; - } - /* raw data starts at buf + 1 with len - 1 bytes */ - buf++; - len = MIN(len - 1, MSG_IN_SIZE - msg_pos); + memcpy(msg_in, buf + 9, len - 9); + msg_pos = len - 9; + } else if (read_state == READSTATE_READING) { + if (buf[0] != '?') { // invalid contents + read_state = READSTATE_IDLE; + return; + } + /* raw data starts at buf + 1 with len - 1 bytes */ + buf++; + len = MIN(len - 1, MSG_IN_SIZE - msg_pos); - memcpy(msg_in + msg_pos, buf, len); - msg_pos += len; - } + memcpy(msg_in + msg_pos, buf, len); + msg_pos += len; + } - if (msg_pos >= msg_size) { - msg_process(type, msg_id, fields, msg_in, msg_size); - msg_pos = 0; - read_state = READSTATE_IDLE; - } + if (msg_pos >= msg_size) { + msg_process(type, msg_id, fields, msg_in, msg_size); + msg_pos = 0; + read_state = READSTATE_IDLE; + } } -const uint8_t *msg_out_data(void) -{ - if (msg_out_start == msg_out_end) return 0; - uint8_t *data = msg_out + (msg_out_start * 64); - msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64); - debugLog(0, "", "msg_out_data"); - return data; +const uint8_t *msg_out_data(void) { + if (msg_out_start == msg_out_end) return 0; + uint8_t *data = msg_out + (msg_out_start * 64); + msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64); + debugLog(0, "", "msg_out_data"); + return data; } #if DEBUG_LINK -const uint8_t *msg_debug_out_data(void) -{ - if (msg_debug_out_start == msg_debug_out_end) return 0; - uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); - msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64); - debugLog(0, "", "msg_debug_out_data"); - return data; +const uint8_t *msg_debug_out_data(void) { + if (msg_debug_out_start == msg_debug_out_end) return 0; + uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); + msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64); + debugLog(0, "", "msg_debug_out_data"); + return data; } #endif @@ -315,61 +306,64 @@ _Static_assert(sizeof(msg_tiny) >= sizeof(PassphraseAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny"); #if DEBUG_LINK -_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), "msg_tiny too tiny"); -_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), + "msg_tiny too tiny"); +_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), + "msg_tiny too tiny"); #endif uint16_t msg_tiny_id = 0xFFFF; -void msg_read_tiny(const uint8_t *buf, int len) -{ - if (len != 64) return; - if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { - return; - } - uint16_t msg_id = (buf[3] << 8) + buf[4]; - uint32_t msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; - if (msg_size > 64 || len - msg_size < 9) { - return; - } +void msg_read_tiny(const uint8_t *buf, int len) { + if (len != 64) return; + if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { + return; + } + uint16_t msg_id = (buf[3] << 8) + buf[4]; + uint32_t msg_size = + ((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; + if (msg_size > 64 || len - msg_size < 9) { + return; + } - const pb_field_t *fields = 0; - pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); + const pb_field_t *fields = 0; + pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); - switch (msg_id) { - case MessageType_MessageType_PinMatrixAck: - fields = PinMatrixAck_fields; - break; - case MessageType_MessageType_ButtonAck: - fields = ButtonAck_fields; - break; - case MessageType_MessageType_PassphraseAck: - fields = PassphraseAck_fields; - break; - case MessageType_MessageType_Cancel: - fields = Cancel_fields; - break; - case MessageType_MessageType_Initialize: - fields = Initialize_fields; - break; + switch (msg_id) { + case MessageType_MessageType_PinMatrixAck: + fields = PinMatrixAck_fields; + break; + case MessageType_MessageType_ButtonAck: + fields = ButtonAck_fields; + break; + case MessageType_MessageType_PassphraseAck: + fields = PassphraseAck_fields; + break; + case MessageType_MessageType_Cancel: + fields = Cancel_fields; + break; + case MessageType_MessageType_Initialize: + fields = Initialize_fields; + break; #if DEBUG_LINK - case MessageType_MessageType_DebugLinkDecision: - fields = DebugLinkDecision_fields; - break; - case MessageType_MessageType_DebugLinkGetState: - fields = DebugLinkGetState_fields; - break; + case MessageType_MessageType_DebugLinkDecision: + fields = DebugLinkDecision_fields; + break; + case MessageType_MessageType_DebugLinkGetState: + fields = DebugLinkGetState_fields; + break; #endif - } - if (fields) { - bool status = pb_decode(&stream, fields, msg_tiny); - if (status) { - msg_tiny_id = msg_id; - } else { - fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); - msg_tiny_id = 0xFFFF; - } - } else { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); - msg_tiny_id = 0xFFFF; - } + } + if (fields) { + bool status = pb_decode(&stream, fields, msg_tiny); + if (status) { + msg_tiny_id = msg_id; + } else { + fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); + msg_tiny_id = 0xFFFF; + } + } else { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Unknown message")); + msg_tiny_id = 0xFFFF; + } } diff --git a/firmware/messages.h b/firmware/messages.h index 1806a7daee..fe3ca2898b 100644 --- a/firmware/messages.h +++ b/firmware/messages.h @@ -20,8 +20,8 @@ #ifndef __MESSAGES_H__ #define __MESSAGES_H__ -#include #include +#include #include "trezor.h" #define MSG_IN_SIZE (15 * 1024) diff --git a/firmware/nem2.c b/firmware/nem2.c index 65c3cf77bd..b9b3a61444 100644 --- a/firmware/nem2.c +++ b/firmware/nem2.c @@ -23,788 +23,768 @@ #include "fsm.h" #include "gettext.h" #include "layout2.h" +#include "memzero.h" #include "protect.h" #include "rng.h" #include "secp256k1.h" -#include "memzero.h" const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { - if (!common->has_network) { - common->has_network = true; - common->network = NEM_NETWORK_MAINNET; - } + if (!common->has_network) { + common->has_network = true; + common->network = NEM_NETWORK_MAINNET; + } - if (common->network > 0xFF || nem_network_name(common->network) == NULL) { - return inner ? _("Invalid NEM network in inner transaction") : _("Invalid NEM network"); - } + if (common->network > 0xFF || nem_network_name(common->network) == NULL) { + return inner ? _("Invalid NEM network in inner transaction") + : _("Invalid NEM network"); + } - if (!common->has_timestamp) { - return inner ? _("No timestamp provided in inner transaction") : _("No timestamp provided"); - } + if (!common->has_timestamp) { + return inner ? _("No timestamp provided in inner transaction") + : _("No timestamp provided"); + } - if (!common->has_fee) { - return inner ? _("No fee provided in inner transaction") : _("No fee provided"); - } + if (!common->has_fee) { + return inner ? _("No fee provided in inner transaction") + : _("No fee provided"); + } - if (!common->has_deadline) { - return inner ? _("No deadline provided in inner transaction") : _("No deadline provided"); - } + if (!common->has_deadline) { + return inner ? _("No deadline provided in inner transaction") + : _("No deadline provided"); + } - if (inner != common->has_signer) { - return inner ? _("No signer provided in inner transaction") : _("Signer not allowed in outer transaction"); - } + if (inner != common->has_signer) { + return inner ? _("No signer provided in inner transaction") + : _("Signer not allowed in outer transaction"); + } - if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) { - return _("Invalid signer public key in inner transaction"); - } + if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) { + return _("Invalid signer public key in inner transaction"); + } - return NULL; + return NULL; } -const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { - if (!transfer->has_recipient) return _("No recipient provided"); - if (!transfer->has_amount) return _("No amount provided"); +const char *nem_validate_transfer(const NEMTransfer *transfer, + uint8_t network) { + if (!transfer->has_recipient) return _("No recipient provided"); + if (!transfer->has_amount) return _("No amount provided"); - if (transfer->has_public_key && transfer->public_key.size != sizeof(ed25519_public_key)) { - return _("Invalid recipient public key"); - } + if (transfer->has_public_key && + transfer->public_key.size != sizeof(ed25519_public_key)) { + return _("Invalid recipient public key"); + } - if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); + if (!nem_validate_address(transfer->recipient, network)) + return _("Invalid recipient address"); - for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; - if (!mosaic->has_namespace) return _("No mosaic namespace provided"); - if (!mosaic->has_mosaic) return _("No mosaic name provided"); - if (!mosaic->has_quantity) return _("No mosaic quantity provided"); - } + if (!mosaic->has_namespace) return _("No mosaic namespace provided"); + if (!mosaic->has_mosaic) return _("No mosaic name provided"); + if (!mosaic->has_quantity) return _("No mosaic quantity provided"); + } - return NULL; + return NULL; } -const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network) { - if (!provision_namespace->has_namespace) return _("No namespace provided"); - if (!provision_namespace->has_sink) return _("No rental sink provided"); - if (!provision_namespace->has_fee) return _("No rental sink fee provided"); +const char *nem_validate_provision_namespace( + const NEMProvisionNamespace *provision_namespace, uint8_t network) { + if (!provision_namespace->has_namespace) return _("No namespace provided"); + if (!provision_namespace->has_sink) return _("No rental sink provided"); + if (!provision_namespace->has_fee) return _("No rental sink fee provided"); - if (!nem_validate_address(provision_namespace->sink, network)) return _("Invalid rental sink address"); + if (!nem_validate_address(provision_namespace->sink, network)) + return _("Invalid rental sink address"); - return NULL; + return NULL; } -const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) { - if (!mosaic_creation->has_definition) return _("No mosaic definition provided"); - if (!mosaic_creation->has_sink) return _("No creation sink provided"); - if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); +const char *nem_validate_mosaic_creation( + const NEMMosaicCreation *mosaic_creation, uint8_t network) { + if (!mosaic_creation->has_definition) + return _("No mosaic definition provided"); + if (!mosaic_creation->has_sink) return _("No creation sink provided"); + if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); - if (!nem_validate_address(mosaic_creation->sink, network)) return _("Invalid creation sink address"); + if (!nem_validate_address(mosaic_creation->sink, network)) + return _("Invalid creation sink address"); - if (mosaic_creation->definition.has_name) return _("Name not allowed in mosaic creation transactions"); - if (mosaic_creation->definition.has_ticker) return _("Ticker not allowed in mosaic creation transactions"); - if (mosaic_creation->definition.networks_count) return _("Networks not allowed in mosaic creation transactions"); + if (mosaic_creation->definition.has_name) + return _("Name not allowed in mosaic creation transactions"); + if (mosaic_creation->definition.has_ticker) + return _("Ticker not allowed in mosaic creation transactions"); + if (mosaic_creation->definition.networks_count) + return _("Networks not allowed in mosaic creation transactions"); - if (!mosaic_creation->definition.has_namespace) return _("No mosaic namespace provided"); - if (!mosaic_creation->definition.has_mosaic) return _("No mosaic name provided"); + if (!mosaic_creation->definition.has_namespace) + return _("No mosaic namespace provided"); + if (!mosaic_creation->definition.has_mosaic) + return _("No mosaic name provided"); - if (mosaic_creation->definition.has_levy) { - if (!mosaic_creation->definition.has_fee) return _("No levy address provided"); - if (!mosaic_creation->definition.has_levy_address) return _("No levy address provided"); - if (!mosaic_creation->definition.has_levy_namespace) return _("No levy namespace provided"); - if (!mosaic_creation->definition.has_levy_mosaic) return _("No levy mosaic name provided"); + if (mosaic_creation->definition.has_levy) { + if (!mosaic_creation->definition.has_fee) + return _("No levy address provided"); + if (!mosaic_creation->definition.has_levy_address) + return _("No levy address provided"); + if (!mosaic_creation->definition.has_levy_namespace) + return _("No levy namespace provided"); + if (!mosaic_creation->definition.has_levy_mosaic) + return _("No levy mosaic name provided"); - if (!mosaic_creation->definition.has_divisibility) return _("No divisibility provided"); - if (!mosaic_creation->definition.has_supply) return _("No supply provided"); - if (!mosaic_creation->definition.has_mutable_supply) return _("No supply mutability provided"); - if (!mosaic_creation->definition.has_transferable) return _("No mosaic transferability provided"); - if (!mosaic_creation->definition.has_description) return _("No description provided"); + if (!mosaic_creation->definition.has_divisibility) + return _("No divisibility provided"); + if (!mosaic_creation->definition.has_supply) return _("No supply provided"); + if (!mosaic_creation->definition.has_mutable_supply) + return _("No supply mutability provided"); + if (!mosaic_creation->definition.has_transferable) + return _("No mosaic transferability provided"); + if (!mosaic_creation->definition.has_description) + return _("No description provided"); - if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY) return _("Invalid divisibility provided"); - if (mosaic_creation->definition.supply > NEM_MAX_SUPPLY) return _("Invalid supply provided"); + if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY) + return _("Invalid divisibility provided"); + if (mosaic_creation->definition.supply > NEM_MAX_SUPPLY) + return _("Invalid supply provided"); - if (!nem_validate_address(mosaic_creation->definition.levy_address, network)) return _("Invalid levy address"); - } + if (!nem_validate_address(mosaic_creation->definition.levy_address, + network)) + return _("Invalid levy address"); + } - return NULL; + return NULL; } -const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change) { - if (!supply_change->has_namespace) return _("No namespace provided"); - if (!supply_change->has_mosaic) return _("No mosaic provided"); - if (!supply_change->has_type) return _("No type provided"); - if (!supply_change->has_delta) return _("No delta provided"); +const char *nem_validate_supply_change( + const NEMMosaicSupplyChange *supply_change) { + if (!supply_change->has_namespace) return _("No namespace provided"); + if (!supply_change->has_mosaic) return _("No mosaic provided"); + if (!supply_change->has_type) return _("No type provided"); + if (!supply_change->has_delta) return _("No delta provided"); - return NULL; + return NULL; } -const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation) { - if (creation && aggregate_modification->modifications_count == 0) { - return _("No modifications provided"); - } +const char *nem_validate_aggregate_modification( + const NEMAggregateModification *aggregate_modification, bool creation) { + if (creation && aggregate_modification->modifications_count == 0) { + return _("No modifications provided"); + } - for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = + &aggregate_modification->modifications[i]; - if (!modification->has_type) return _("No modification type provided"); - if (!modification->has_public_key) return _("No cosignatory public key provided"); - if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided"); + if (!modification->has_type) return _("No modification type provided"); + if (!modification->has_public_key) + return _("No cosignatory public key provided"); + if (modification->public_key.size != 32) + return _("Invalid cosignatory public key provided"); - if (creation && modification->type == NEMModificationType_CosignatoryModification_Delete) { - return _("Cannot remove cosignatory when converting account"); - } - } + if (creation && modification->type == + NEMModificationType_CosignatoryModification_Delete) { + return _("Cannot remove cosignatory when converting account"); + } + } - return NULL; + return NULL; } -const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer) { - if (!importance_transfer->has_mode) return _("No mode provided"); - if (!importance_transfer->has_public_key) return _("No remote account provided"); - if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided"); +const char *nem_validate_importance_transfer( + const NEMImportanceTransfer *importance_transfer) { + if (!importance_transfer->has_mode) return _("No mode provided"); + if (!importance_transfer->has_public_key) + return _("No remote account provided"); + if (importance_transfer->public_key.size != 32) + return _("Invalid remote account provided"); - return NULL; + return NULL; } -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { - if (transfer->mosaics_count) { - const NEMMosaic *xem = NULL; - bool unknownMosaic = false; +bool nem_askTransfer(const NEMTransactionCommon *common, + const NEMTransfer *transfer, const char *desc) { + if (transfer->mosaics_count) { + const NEMMosaic *xem = NULL; + bool unknownMosaic = false; - const NEMMosaicDefinition *definitions[transfer->mosaics_count]; + const NEMMosaicDefinition *definitions[transfer->mosaics_count]; - for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; - definitions[i] = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); + definitions[i] = + nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); - if (definitions[i] == NEM_MOSAIC_DEFINITION_XEM) { - xem = mosaic; - } else if (definitions[i] == NULL) { - unknownMosaic = true; - } - } + if (definitions[i] == NEM_MOSAIC_DEFINITION_XEM) { + xem = mosaic; + } else if (definitions[i] == NULL) { + unknownMosaic = true; + } + } - bignum256 multiplier; - bn_read_uint64(transfer->amount, &multiplier); + bignum256 multiplier; + bn_read_uint64(transfer->amount, &multiplier); - if (unknownMosaic) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("I take the risk"), - _("Unknown Mosaics"), - _("Divisibility and levy"), - _("cannot be shown for"), - _("unknown mosaics!"), - NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + if (unknownMosaic) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), + _("Unknown Mosaics"), _("Divisibility and levy"), + _("cannot be shown for"), _("unknown mosaics!"), NULL, + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, + false)) { + return false; + } + } - layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, + common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; - if (mosaic == xem) { - continue; - } + if (mosaic == xem) { + continue; + } - if (definitions[i]) { - layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier, common->network); - } else { - layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaic->quantity, &multiplier); - } + if (definitions[i]) { + layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier, + common->network); + } else { + layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, + mosaic->quantity, &multiplier); + } - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } - } else { - layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, + false)) { + return false; + } + } + } else { + layoutNEMTransferXEM(desc, transfer->amount, NULL, common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - if (transfer->has_payload) { - layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, transfer->has_public_key); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + if (transfer->has_payload) { + layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, + transfer->has_public_key); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Confirm"), - desc, - _("Confirm transfer to"), - transfer->recipient); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, + _("Confirm transfer to"), transfer->recipient); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) { - static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, + const NEMTransactionCommon *common, + const NEMTransfer *transfer) { + static uint8_t + encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; - const uint8_t *payload = transfer->payload.bytes; - size_t size = transfer->payload.size; + const uint8_t *payload = transfer->payload.bytes; + size_t size = transfer->payload.size; - if (transfer->has_public_key) { - if (node == NULL) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); - return false; - } + if (transfer->has_public_key) { + if (node == NULL) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Private key unavailable for encrypted message")); + return false; + } - random_buffer(encrypted, NEM_SALT_SIZE + AES_BLOCK_SIZE); + random_buffer(encrypted, NEM_SALT_SIZE + AES_BLOCK_SIZE); - const uint8_t *salt = encrypted; - const uint8_t *iv = &encrypted[NEM_SALT_SIZE]; - uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE]; + const uint8_t *salt = encrypted; + const uint8_t *iv = &encrypted[NEM_SALT_SIZE]; + uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE]; - bool ret = hdnode_nem_encrypt(node, - transfer->public_key.bytes, - iv, - salt, - payload, - size, - buffer); + bool ret = hdnode_nem_encrypt(node, transfer->public_key.bytes, iv, salt, + payload, size, buffer); - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload")); - return false; - } + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to encrypt payload")); + return false; + } - payload = encrypted; - size = NEM_ENCRYPTED_PAYLOAD_SIZE(size); - } + payload = encrypted; + size = NEM_ENCRYPTED_PAYLOAD_SIZE(size); + } - bool ret = nem_transaction_create_transfer(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - transfer->recipient, - transfer->amount, - payload, - size, - transfer->has_public_key, - transfer->mosaics_count); + bool ret = nem_transaction_create_transfer( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, transfer->recipient, transfer->amount, payload, size, + transfer->has_public_key, transfer->mosaics_count); - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); - return false; - } + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to create transfer transaction")); + return false; + } - for (size_t i = 0; i < transfer->mosaics_count; i++) { - const NEMMosaic *mosaic = &transfer->mosaics[i]; + for (size_t i = 0; i < transfer->mosaics_count; i++) { + const NEMMosaic *mosaic = &transfer->mosaics[i]; - ret = nem_transaction_write_mosaic(context, - mosaic->namespace, - mosaic->mosaic, - mosaic->quantity); + ret = nem_transaction_write_mosaic(context, mosaic->namespace, + mosaic->mosaic, mosaic->quantity); - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics")); - return false; - } - } + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to attach mosaics")); + return false; + } + } - return true; + return true; } -bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - _("Create namespace"), - provision_namespace->namespace, - provision_namespace->has_parent ? _("under namespace") : NULL, - provision_namespace->has_parent ? provision_namespace->parent : NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, + const NEMProvisionNamespace *provision_namespace, + const char *desc) { + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), desc, _("Create namespace"), + provision_namespace->namespace, + provision_namespace->has_parent ? _("under namespace") : NULL, + provision_namespace->has_parent ? provision_namespace->parent : NULL, + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), provision_namespace->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), + provision_namespace->fee, _("and network fee of"), + common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) { - return nem_transaction_create_provision_namespace(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - provision_namespace->namespace, - provision_namespace->has_parent ? provision_namespace->parent : NULL, - provision_namespace->sink, - provision_namespace->fee); +bool nem_fsmProvisionNamespace( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMProvisionNamespace *provision_namespace) { + return nem_transaction_create_provision_namespace( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, provision_namespace->namespace, + provision_namespace->has_parent ? provision_namespace->parent : NULL, + provision_namespace->sink, provision_namespace->fee); } -bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - _("Create mosaic"), - mosaic_creation->definition.mosaic, - _("under namespace"), - mosaic_creation->definition.namespace, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } +bool nem_askMosaicCreation(const NEMTransactionCommon *common, + const NEMMosaicCreation *mosaic_creation, + const char *desc, const char *address) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, + _("Create mosaic"), mosaic_creation->definition.mosaic, + _("under namespace"), mosaic_creation->definition.namespace, + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - layoutNEMMosaicDescription(mosaic_creation->definition.description); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + layoutNEMMosaicDescription(mosaic_creation->definition.description); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - char str_out[32]; + char str_out[32]; - bn_format_uint64(mosaic_creation->definition.supply, - NULL, - NULL, - mosaic_creation->definition.divisibility, - mosaic_creation->definition.divisibility, - true, - str_out, - sizeof(str_out)); + bn_format_uint64(mosaic_creation->definition.supply, NULL, NULL, + mosaic_creation->definition.divisibility, + mosaic_creation->definition.divisibility, true, str_out, + sizeof(str_out)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - _("Properties"), - mosaic_creation->definition.mutable_supply ? _("Mutable supply:") : _("Immutable supply:"), - str_out, - _("Mosaic will be"), - mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"), - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), _("Properties"), + mosaic_creation->definition.mutable_supply ? _("Mutable supply:") + : _("Immutable supply:"), + str_out, _("Mosaic will be"), + mosaic_creation->definition.transferable ? _("transferable") + : _("non-transferable"), + NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - if (mosaic_creation->definition.has_levy) { - layoutNEMLevy(&mosaic_creation->definition, common->network); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + if (mosaic_creation->definition.has_levy) { + layoutNEMLevy(&mosaic_creation->definition, common->network); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - if (strcmp(address, mosaic_creation->definition.levy_address) == 0) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - _("Levy Recipient"), - _("Levy will be paid to"), - _("yourself"), - NULL, - NULL, - NULL, - NULL); - } else { - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Next"), - _("Levy Recipient"), - _("Levy will be paid to"), - mosaic_creation->definition.levy_address); - } + if (strcmp(address, mosaic_creation->definition.levy_address) == 0) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), + _("Levy Recipient"), _("Levy will be paid to"), + _("yourself"), NULL, NULL, NULL, NULL); + } else { + layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Next"), + _("Levy Recipient"), _("Levy will be paid to"), + mosaic_creation->definition.levy_address); + } - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), + mosaic_creation->fee, _("and network fee of"), + common->fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) { - return nem_transaction_create_mosaic_creation(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - mosaic_creation->definition.namespace, - mosaic_creation->definition.mosaic, - mosaic_creation->definition.description, - mosaic_creation->definition.divisibility, - mosaic_creation->definition.supply, - mosaic_creation->definition.mutable_supply, - mosaic_creation->definition.transferable, - mosaic_creation->definition.levy, - mosaic_creation->definition.fee, - mosaic_creation->definition.levy_address, - mosaic_creation->definition.levy_namespace, - mosaic_creation->definition.levy_mosaic, - mosaic_creation->sink, - mosaic_creation->fee); +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const NEMMosaicCreation *mosaic_creation) { + return nem_transaction_create_mosaic_creation( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, mosaic_creation->definition.namespace, + mosaic_creation->definition.mosaic, + mosaic_creation->definition.description, + mosaic_creation->definition.divisibility, + mosaic_creation->definition.supply, + mosaic_creation->definition.mutable_supply, + mosaic_creation->definition.transferable, + mosaic_creation->definition.levy, mosaic_creation->definition.fee, + mosaic_creation->definition.levy_address, + mosaic_creation->definition.levy_namespace, + mosaic_creation->definition.levy_mosaic, mosaic_creation->sink, + mosaic_creation->fee); } -bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - _("Modify supply for"), - supply_change->mosaic, - _("under namespace"), - supply_change->namespace, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } +bool nem_askSupplyChange(const NEMTransactionCommon *common, + const NEMMosaicSupplyChange *supply_change, + const char *desc) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, + _("Modify supply for"), supply_change->mosaic, + _("under namespace"), supply_change->namespace, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - char str_out[32]; - bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); + char str_out[32]; + bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out, + sizeof(str_out)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), - str_out, - _("whole units"), - NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), desc, + supply_change->type == NEMSupplyChangeType_SupplyChange_Increase + ? _("Increase supply by") + : _("Decrease supply by"), + str_out, _("whole units"), NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, + 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) { - return nem_transaction_create_mosaic_supply_change(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - supply_change->namespace, - supply_change->mosaic, - supply_change->type, - supply_change->delta); +bool nem_fsmSupplyChange(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const NEMMosaicSupplyChange *supply_change) { + return nem_transaction_create_mosaic_supply_change( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, supply_change->namespace, supply_change->mosaic, + supply_change->type, supply_change->delta); } -bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { - if (creation) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - _("Convert account to"), - _("multisig account?"), - NULL, - NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } +bool nem_askAggregateModification( + const NEMTransactionCommon *common, + const NEMAggregateModification *aggregate_modification, const char *desc, + bool creation) { + if (creation) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, + _("Convert account to"), _("multisig account?"), NULL, + NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - char address[NEM_ADDRESS_SIZE + 1]; + char address[NEM_ADDRESS_SIZE + 1]; - for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; - nem_get_address(modification->public_key.bytes, common->network, address); + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = + &aggregate_modification->modifications[i]; + nem_get_address(modification->public_key.bytes, common->network, address); - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), - address); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + layoutNEMDialog( + &bmp_icon_question, _("Cancel"), _("Next"), desc, + modification->type == NEMModificationType_CosignatoryModification_Add + ? _("Add cosignatory") + : _("Remove cosignatory"), + address); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - int32_t relative_change = aggregate_modification->relative_change; - if (relative_change) { - char str_out[32]; - bn_format_uint64(relative_change < 0 ? -relative_change : relative_change, - NULL, - NULL, - 0, - 0, - false, - str_out, - sizeof(str_out)); + int32_t relative_change = aggregate_modification->relative_change; + if (relative_change) { + char str_out[32]; + bn_format_uint64(relative_change < 0 ? -relative_change : relative_change, + NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - creation ? _("Set minimum") : (relative_change < 0 ? _("Decrease minimum") : _("Increase minimum")), - creation ? _("cosignatories to") : _("cosignatories by"), - str_out, - NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } - } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc, + creation ? _("Set minimum") + : (relative_change < 0 ? _("Decrease minimum") + : _("Increase minimum")), + creation ? _("cosignatories to") : _("cosignatories by"), + str_out, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } + } - layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, + 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) { - bool ret = nem_transaction_create_aggregate_modification(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - aggregate_modification->modifications_count, - aggregate_modification->relative_change != 0); - if (!ret) return false; +bool nem_fsmAggregateModification( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMAggregateModification *aggregate_modification) { + bool ret = nem_transaction_create_aggregate_modification( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, aggregate_modification->modifications_count, + aggregate_modification->relative_change != 0); + if (!ret) return false; - for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { - const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; + for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { + const NEMCosignatoryModification *modification = + &aggregate_modification->modifications[i]; - ret = nem_transaction_write_cosignatory_modification(context, - modification->type, - modification->public_key.bytes); - if (!ret) return false; - } + ret = nem_transaction_write_cosignatory_modification( + context, modification->type, modification->public_key.bytes); + if (!ret) return false; + } - if (aggregate_modification->relative_change) { - ret = nem_transaction_write_minimum_cosignatories(context, aggregate_modification->relative_change); - if (!ret) return false; - } + if (aggregate_modification->relative_change) { + ret = nem_transaction_write_minimum_cosignatories( + context, aggregate_modification->relative_change); + if (!ret) return false; + } - return true; + return true; } -bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) { - layoutDialogSwipe(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), - _("harvesting?"), - NULL, - NULL, - NULL, - NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, + const NEMImportanceTransfer *importance_transfer, + const char *desc) { + layoutDialogSwipe( + &bmp_icon_question, _("Cancel"), _("Next"), desc, + importance_transfer->mode == + NEMImportanceTransferMode_ImportanceTransfer_Activate + ? _("Activate remote") + : _("Deactivate remote"), + _("harvesting?"), NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - return false; - } + layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, + 0); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + return false; + } - return true; + return true; } -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) { - return nem_transaction_create_importance_transfer(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - importance_transfer->mode, - importance_transfer->public_key.bytes); +bool nem_fsmImportanceTransfer( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMImportanceTransfer *importance_transfer) { + return nem_transaction_create_importance_transfer( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, importance_transfer->mode, + importance_transfer->public_key.bytes); } -bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { - layoutNEMDialog(&bmp_icon_question, - _("Cancel"), - _("Next"), - desc, - cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), - address); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } +bool nem_askMultisig(const char *address, const char *desc, bool cosigning, + uint64_t fee) { + layoutNEMDialog( + &bmp_icon_question, _("Cancel"), _("Next"), desc, + cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), + address); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return false; - } + layoutNEMNetworkFee(desc, false, _("Confirm multisig fee"), fee, NULL, 0); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return false; + } - return true; + return true; } -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { - bool ret; - if (cosigning) { - ret = nem_transaction_create_multisig_signature(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - inner); - } else { - ret = nem_transaction_create_multisig(context, - common->network, - common->timestamp, - NULL, - common->fee, - common->deadline, - inner); - } +bool nem_fsmMultisig(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const nem_transaction_ctx *inner, bool cosigning) { + bool ret; + if (cosigning) { + ret = nem_transaction_create_multisig_signature( + context, common->network, common->timestamp, NULL, common->fee, + common->deadline, inner); + } else { + ret = nem_transaction_create_multisig(context, common->network, + common->timestamp, NULL, common->fee, + common->deadline, inner); + } - if (!ret) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); - return false; - } + if (!ret) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to create multisig transaction")); + return false; + } - return true; + return true; } -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { - for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { - const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, + const char *mosaic, + uint8_t network) { + for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { + const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; - if (nem_mosaicMatches(definition, namespace, mosaic, network)) { - return definition; - } - } + if (nem_mosaicMatches(definition, namespace, mosaic, network)) { + return definition; + } + } - return NULL; + return NULL; } -static inline size_t format_amount(const NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { - bignum256 val; - memcpy(&val, amnt, sizeof(bignum256)); +static inline size_t format_amount(const NEMMosaicDefinition *definition, + const bignum256 *amnt, + const bignum256 *multiplier, int divisor, + char *str_out, size_t size) { + bignum256 val; + memcpy(&val, amnt, sizeof(bignum256)); - if (multiplier) { - bn_multiply(multiplier, &val, &secp256k1.prime); - divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility; - } + if (multiplier) { + bn_multiply(multiplier, &val, &secp256k1.prime); + divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility; + } - return bn_format(&val, - NULL, - definition && definition->has_ticker ? definition->ticker : NULL, - definition && definition->has_divisibility ? definition->divisibility : 0, - -divisor, - false, - str_out, - size); + return bn_format( + &val, NULL, + definition && definition->has_ticker ? definition->ticker : NULL, + definition && definition->has_divisibility ? definition->divisibility : 0, + -divisor, false, str_out, size); } size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { - if (mosaics_count <= 1) { - return mosaics_count; - } + if (mosaics_count <= 1) { + return mosaics_count; + } - size_t actual_count = 0; + size_t actual_count = 0; - bool skip[mosaics_count]; - memzero(skip, sizeof(skip)); + bool skip[mosaics_count]; + memzero(skip, sizeof(skip)); - // Merge duplicates - for (size_t i = 0; i < mosaics_count; i++) { - if (skip[i]) continue; + // Merge duplicates + for (size_t i = 0; i < mosaics_count; i++) { + if (skip[i]) continue; - NEMMosaic *mosaic = &mosaics[actual_count]; + NEMMosaic *mosaic = &mosaics[actual_count]; - if (actual_count++ != i) { - memcpy(mosaic, &mosaics[i], sizeof(NEMMosaic)); - } + if (actual_count++ != i) { + memcpy(mosaic, &mosaics[i], sizeof(NEMMosaic)); + } - for (size_t j = i + 1; j < mosaics_count; j++) { - if (skip[j]) continue; + for (size_t j = i + 1; j < mosaics_count; j++) { + if (skip[j]) continue; - const NEMMosaic *new_mosaic = &mosaics[j]; + const NEMMosaic *new_mosaic = &mosaics[j]; - if (nem_mosaicCompare(mosaic, new_mosaic) == 0) { - skip[j] = true; - mosaic->quantity += new_mosaic->quantity; - } - } - } + if (nem_mosaicCompare(mosaic, new_mosaic) == 0) { + skip[j] = true; + mosaic->quantity += new_mosaic->quantity; + } + } + } - NEMMosaic temp; + NEMMosaic temp; - // Sort mosaics - for (size_t i = 0; i < actual_count - 1; i++) { - NEMMosaic *a = &mosaics[i]; + // Sort mosaics + for (size_t i = 0; i < actual_count - 1; i++) { + NEMMosaic *a = &mosaics[i]; - for (size_t j = i + 1; j < actual_count; j++) { - NEMMosaic *b = &mosaics[j]; + for (size_t j = i + 1; j < actual_count; j++) { + NEMMosaic *b = &mosaics[j]; - if (nem_mosaicCompare(a, b) > 0) { - memcpy(&temp, a, sizeof(NEMMosaic)); - memcpy(a, b, sizeof(NEMMosaic)); - memcpy(b, &temp, sizeof(NEMMosaic)); - } - } - } + if (nem_mosaicCompare(a, b) > 0) { + memcpy(&temp, a, sizeof(NEMMosaic)); + memcpy(a, b, sizeof(NEMMosaic)); + memcpy(b, &temp, sizeof(NEMMosaic)); + } + } + } - return actual_count; + return actual_count; } -void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { - bignum256 amnt; - bn_read_uint64(quantity, &amnt); +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + char *str_out, size_t size) { + bignum256 amnt; + bn_read_uint64(quantity, &amnt); - format_amount(definition, &amnt, multiplier, 0, str_out, size); + format_amount(definition, &amnt, multiplier, 0, str_out, size); } -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { - if (!definition->has_levy || !definition->has_fee) { - return false; - } +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + uint8_t network, char *str_out, size_t size) { + if (!definition->has_levy || !definition->has_fee) { + return false; + } - bignum256 amnt, fee; - bn_read_uint64(quantity, &amnt); - bn_read_uint64(definition->fee, &fee); + bignum256 amnt, fee; + bn_read_uint64(quantity, &amnt); + bn_read_uint64(definition->fee, &fee); - const NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); + const NEMMosaicDefinition *mosaic = nem_mosaicByName( + definition->levy_namespace, definition->levy_mosaic, network); - switch (definition->levy) { - case NEMMosaicLevy_MosaicLevy_Absolute: - return format_amount(mosaic, &fee, NULL, 0, str_out, size); + switch (definition->levy) { + case NEMMosaicLevy_MosaicLevy_Absolute: + return format_amount(mosaic, &fee, NULL, 0, str_out, size); - case NEMMosaicLevy_MosaicLevy_Percentile: - bn_multiply(&fee, &amnt, &secp256k1.prime); - return format_amount(mosaic, &amnt, multiplier, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); + case NEMMosaicLevy_MosaicLevy_Percentile: + bn_multiply(&fee, &amnt, &secp256k1.prime); + return format_amount(mosaic, &amnt, multiplier, + NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); - default: - return false; - } + default: + return false; + } } diff --git a/firmware/nem2.h b/firmware/nem2.h index 13f0390fab..a4a9597a1c 100644 --- a/firmware/nem2.h +++ b/firmware/nem2.h @@ -29,82 +29,125 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); -const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); -const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); -const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); -const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); -const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); +const char *nem_validate_provision_namespace( + const NEMProvisionNamespace *provision_namespace, uint8_t network); +const char *nem_validate_mosaic_creation( + const NEMMosaicCreation *mosaic_creation, uint8_t network); +const char *nem_validate_supply_change( + const NEMMosaicSupplyChange *supply_change); +const char *nem_validate_aggregate_modification( + const NEMAggregateModification *aggregate_modification, bool creation); +const char *nem_validate_importance_transfer( + const NEMImportanceTransfer *importance_transfer); -bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); -bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); +bool nem_askTransfer(const NEMTransactionCommon *common, + const NEMTransfer *transfer, const char *desc); +bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, + const NEMTransactionCommon *common, + const NEMTransfer *transfer); -bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); -bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); +bool nem_askProvisionNamespace(const NEMTransactionCommon *common, + const NEMProvisionNamespace *provision_namespace, + const char *desc); +bool nem_fsmProvisionNamespace( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMProvisionNamespace *provision_namespace); -bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); -bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); +bool nem_askMosaicCreation(const NEMTransactionCommon *common, + const NEMMosaicCreation *mosaic_creation, + const char *desc, const char *address); +bool nem_fsmMosaicCreation(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const NEMMosaicCreation *mosaic_creation); -bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); -bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); +bool nem_askSupplyChange(const NEMTransactionCommon *common, + const NEMMosaicSupplyChange *supply_change, + const char *desc); +bool nem_fsmSupplyChange(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const NEMMosaicSupplyChange *supply_change); -bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); -bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); +bool nem_askAggregateModification( + const NEMTransactionCommon *common, + const NEMAggregateModification *aggregate_modification, const char *desc, + bool creation); +bool nem_fsmAggregateModification( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMAggregateModification *aggregate_modification); -bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); -bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); +bool nem_askImportanceTransfer(const NEMTransactionCommon *common, + const NEMImportanceTransfer *importance_transfer, + const char *desc); +bool nem_fsmImportanceTransfer( + nem_transaction_ctx *context, const NEMTransactionCommon *common, + const NEMImportanceTransfer *importance_transfer); -bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); -bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); +bool nem_askMultisig(const char *address, const char *desc, bool cosigning, + uint64_t fee); +bool nem_fsmMultisig(nem_transaction_ctx *context, + const NEMTransactionCommon *common, + const nem_transaction_ctx *inner, bool cosigning); -const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); +const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, + const char *mosaic, + uint8_t network); size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); -void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); -bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); +void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + char *str_out, size_t size); +bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, + uint64_t quantity, const bignum256 *multiplier, + uint8_t network, char *str_out, size_t size); -static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { - strlcpy(str_out, namespace, size); - strlcat(str_out, ".", size); - strlcat(str_out, mosaic, size); +static inline void nem_mosaicFormatName(const char *namespace, + const char *mosaic, char *str_out, + size_t size) { + strlcpy(str_out, namespace, size); + strlcat(str_out, ".", size); + strlcat(str_out, mosaic, size); } -static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { - if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { - if (definition->networks_count == 0) { - return true; - } +static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, + const char *namespace, const char *mosaic, + uint8_t network) { + if (strcmp(namespace, definition->namespace) == 0 && + strcmp(mosaic, definition->mosaic) == 0) { + if (definition->networks_count == 0) { + return true; + } - for (size_t i = 0; i < definition->networks_count; i++) { - if (definition->networks[i] == network) { - return true; - } - } - } + for (size_t i = 0; i < definition->networks_count; i++) { + if (definition->networks[i] == network) { + return true; + } + } + } - return false; + return false; } static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) { - size_t namespace_length = strlen(a->namespace); + size_t namespace_length = strlen(a->namespace); - // Ensure that strlen(a->namespace) <= strlen(b->namespace) - if (namespace_length > strlen(b->namespace)) { - return -nem_mosaicCompare(b, a); - } + // Ensure that strlen(a->namespace) <= strlen(b->namespace) + if (namespace_length > strlen(b->namespace)) { + return -nem_mosaicCompare(b, a); + } - int r = strncmp(a->namespace, b->namespace, namespace_length); + int r = strncmp(a->namespace, b->namespace, namespace_length); - if (r == 0 && b->namespace[namespace_length] != '\0') { - // The next character would be the separator - r = (':' - b->namespace[namespace_length]); - } + if (r == 0 && b->namespace[namespace_length] != '\0') { + // The next character would be the separator + r = (':' - b->namespace[namespace_length]); + } - if (r == 0) { - // Finally compare the mosaic - r = strcmp(a->mosaic, b->mosaic); - } + if (r == 0) { + // Finally compare the mosaic + r = strcmp(a->mosaic, b->mosaic); + } - return r; + return r; } #endif diff --git a/firmware/otp.c b/firmware/otp.c index 74810f6686..195b977697 100644 --- a/firmware/otp.c +++ b/firmware/otp.c @@ -17,49 +17,51 @@ * along with this library. If not, see . */ -#include #include "otp.h" +#include -#define FLASH_OTP_BASE 0x1FFF7800U -#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U +#define FLASH_OTP_BASE 0x1FFF7800U +#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U -bool flash_otp_is_locked(uint8_t block) -{ - return 0x00 == *(volatile uint8_t *)(FLASH_OTP_LOCK_BASE + block); +bool flash_otp_is_locked(uint8_t block) { + return 0x00 == *(volatile uint8_t *)(FLASH_OTP_LOCK_BASE + block); } -bool flash_otp_lock(uint8_t block) -{ - if (block >= FLASH_OTP_NUM_BLOCKS) { - return false; - } - flash_unlock(); - flash_program_byte(FLASH_OTP_LOCK_BASE + block, 0x00); - flash_lock(); - return true; +bool flash_otp_lock(uint8_t block) { + if (block >= FLASH_OTP_NUM_BLOCKS) { + return false; + } + flash_unlock(); + flash_program_byte(FLASH_OTP_LOCK_BASE + block, 0x00); + flash_lock(); + return true; } -bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen) -{ - if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { - return false; - } - for (uint8_t i = 0; i < datalen; i++) { - data[i] = *(volatile uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); - } - return true; +bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return false; + } + for (uint8_t i = 0; i < datalen; i++) { + data[i] = *(volatile uint8_t *)(FLASH_OTP_BASE + + block * FLASH_OTP_BLOCK_SIZE + offset + i); + } + return true; } -bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen) -{ - if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { - return false; - } - flash_unlock(); - for (uint8_t i = 0; i < datalen; i++) { - uint32_t address = FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; - flash_program_byte(address, data[i]); - } - flash_lock(); - return true; +bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return false; + } + flash_unlock(); + for (uint8_t i = 0; i < datalen; i++) { + uint32_t address = + FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; + flash_program_byte(address, data[i]); + } + flash_lock(); + return true; } diff --git a/firmware/otp.h b/firmware/otp.h index 471e230c0f..d329f94251 100644 --- a/firmware/otp.h +++ b/firmware/otp.h @@ -20,17 +20,19 @@ #ifndef __OTP_H__ #define __OTP_H__ -#include #include +#include -#define FLASH_OTP_NUM_BLOCKS 16 -#define FLASH_OTP_BLOCK_SIZE 32 +#define FLASH_OTP_NUM_BLOCKS 16 +#define FLASH_OTP_BLOCK_SIZE 32 -#define FLASH_OTP_BLOCK_RANDOMNESS 3 +#define FLASH_OTP_BLOCK_RANDOMNESS 3 bool flash_otp_is_locked(uint8_t block); bool flash_otp_lock(uint8_t block); -bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen); -bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen); +bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen); +bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen); #endif diff --git a/firmware/pinmatrix.c b/firmware/pinmatrix.c index 94f8a06cc6..f45fa20244 100644 --- a/firmware/pinmatrix.c +++ b/firmware/pinmatrix.c @@ -19,64 +19,60 @@ #include -#include "pinmatrix.h" #include "layout2.h" #include "oled.h" +#include "pinmatrix.h" #include "rng.h" static char pinmatrix_perm[10] = "XXXXXXXXX"; -void pinmatrix_draw(const char *text) -{ - const BITMAP *bmp_digits[10] = { - &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, - &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, - }; - layoutSwipe(); - const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - // use (2 - j) instead of j to achieve 789456123 layout - int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; - if (text) { - oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD); - } - oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); - } - } - oledRefresh(); +void pinmatrix_draw(const char *text) { + const BITMAP *bmp_digits[10] = { + &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, + &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, + }; + layoutSwipe(); + const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + // use (2 - j) instead of j to achieve 789456123 layout + int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; + if (text) { + oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD); + } + oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), + OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), + bmp_digits[k]); + } + } + oledRefresh(); } -void pinmatrix_start(const char *text) -{ - for (int i = 0; i < 9; i++) { - pinmatrix_perm[i] = '1' + i; - } - pinmatrix_perm[9] = 0; - random_permute(pinmatrix_perm, 9); - pinmatrix_draw(text); +void pinmatrix_start(const char *text) { + for (int i = 0; i < 9; i++) { + pinmatrix_perm[i] = '1' + i; + } + pinmatrix_perm[9] = 0; + random_permute(pinmatrix_perm, 9); + pinmatrix_draw(text); } -void pinmatrix_done(char *pin) -{ - int k, i = 0; - while (pin && pin[i]) { - k = pin[i] - '1'; - if (k >= 0 && k <= 8) { - pin[i] = pinmatrix_perm[k]; - } else { - pin[i] = 'X'; - } - i++; - } - memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm) - 1); +void pinmatrix_done(char *pin) { + int k, i = 0; + while (pin && pin[i]) { + k = pin[i] - '1'; + if (k >= 0 && k <= 8) { + pin[i] = pinmatrix_perm[k]; + } else { + pin[i] = 'X'; + } + i++; + } + memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm) - 1); } #if DEBUG_LINK -const char *pinmatrix_get(void) -{ - return pinmatrix_perm; -} +const char *pinmatrix_get(void) { return pinmatrix_perm; } #endif diff --git a/firmware/protect.c b/firmware/protect.c index 548504b8bd..7617d2ab2c 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -18,296 +18,303 @@ */ #include "protect.h" -#include "config.h" -#include "memory.h" -#include "messages.h" -#include "usb.h" -#include "oled.h" #include "buttons.h" -#include "pinmatrix.h" -#include "fsm.h" -#include "layout2.h" -#include "util.h" +#include "config.h" #include "debug.h" +#include "fsm.h" #include "gettext.h" +#include "layout2.h" +#include "memory.h" #include "memzero.h" +#include "messages.h" #include "messages.pb.h" +#include "oled.h" +#include "pinmatrix.h" +#include "usb.h" +#include "util.h" #define MAX_WRONG_PINS 15 bool protectAbortedByCancel = false; bool protectAbortedByInitialize = false; -bool protectButton(ButtonRequestType type, bool confirm_only) -{ - ButtonRequest resp; - bool result = false; - bool acked = false; +bool protectButton(ButtonRequestType type, bool confirm_only) { + ButtonRequest resp; + bool result = false; + bool acked = false; #if DEBUG_LINK - bool debug_decided = false; + bool debug_decided = false; #endif - memzero(&resp, sizeof(ButtonRequest)); - resp.has_code = true; - resp.code = type; - usbTiny(1); - buttonUpdate(); // Clear button state - msg_write(MessageType_MessageType_ButtonRequest, &resp); + memzero(&resp, sizeof(ButtonRequest)); + resp.has_code = true; + resp.code = type; + usbTiny(1); + buttonUpdate(); // Clear button state + msg_write(MessageType_MessageType_ButtonRequest, &resp); - for (;;) { - usbPoll(); + for (;;) { + usbPoll(); - // check for ButtonAck - if (msg_tiny_id == MessageType_MessageType_ButtonAck) { - msg_tiny_id = 0xFFFF; - acked = true; - } + // check for ButtonAck + if (msg_tiny_id == MessageType_MessageType_ButtonAck) { + msg_tiny_id = 0xFFFF; + acked = true; + } - // button acked - check buttons - if (acked) { - usbSleep(5); - buttonUpdate(); - if (button.YesUp) { - result = true; - break; - } - if (!confirm_only && button.NoUp) { - result = false; - break; - } - } + // button acked - check buttons + if (acked) { + usbSleep(5); + buttonUpdate(); + if (button.YesUp) { + result = true; + break; + } + if (!confirm_only && button.NoUp) { + result = false; + break; + } + } - // check for Cancel / Initialize - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - msg_tiny_id = 0xFFFF; - result = false; - break; - } + // check for Cancel / Initialize + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = + (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + msg_tiny_id = 0xFFFF; + result = false; + break; + } #if DEBUG_LINK - // check DebugLink - if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) { - msg_tiny_id = 0xFFFF; - DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny; - result = dld->yes_no; - debug_decided = true; - } + // check DebugLink + if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) { + msg_tiny_id = 0xFFFF; + DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny; + result = dld->yes_no; + debug_decided = true; + } - if (acked && debug_decided) { - break; - } + if (acked && debug_decided) { + break; + } - if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { - msg_tiny_id = 0xFFFF; - fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); - } + if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { + msg_tiny_id = 0xFFFF; + fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); + } #endif - } + } - usbTiny(0); + usbTiny(0); - return result; + return result; } -const char *requestPin(PinMatrixRequestType type, const char *text) -{ - PinMatrixRequest resp; - memzero(&resp, sizeof(PinMatrixRequest)); - resp.has_type = true; - resp.type = type; - usbTiny(1); - msg_write(MessageType_MessageType_PinMatrixRequest, &resp); - pinmatrix_start(text); - for (;;) { - usbPoll(); - if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) { - msg_tiny_id = 0xFFFF; - PinMatrixAck *pma = (PinMatrixAck *)msg_tiny; - pinmatrix_done(pma->pin); // convert via pinmatrix - usbTiny(0); - return pma->pin; - } - // check for Cancel / Initialize - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - pinmatrix_done(0); - msg_tiny_id = 0xFFFF; - usbTiny(0); - return 0; - } +const char *requestPin(PinMatrixRequestType type, const char *text) { + PinMatrixRequest resp; + memzero(&resp, sizeof(PinMatrixRequest)); + resp.has_type = true; + resp.type = type; + usbTiny(1); + msg_write(MessageType_MessageType_PinMatrixRequest, &resp); + pinmatrix_start(text); + for (;;) { + usbPoll(); + if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) { + msg_tiny_id = 0xFFFF; + PinMatrixAck *pma = (PinMatrixAck *)msg_tiny; + pinmatrix_done(pma->pin); // convert via pinmatrix + usbTiny(0); + return pma->pin; + } + // check for Cancel / Initialize + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = + (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + pinmatrix_done(0); + msg_tiny_id = 0xFFFF; + usbTiny(0); + return 0; + } #if DEBUG_LINK - if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { - msg_tiny_id = 0xFFFF; - fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); - } + if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { + msg_tiny_id = 0xFFFF; + fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); + } #endif - } + } } -secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message) -{ - // Convert wait to secstr string. - char secstrbuf[] = _("________0 seconds"); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - do { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } while (secs > 0 && secstr >= secstrbuf); - if (wait == 1) { - // Change "seconds" to "second". - secstrbuf[16] = 0; - } - oledClear(); - oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD); - oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); - oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); - oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), FONT_STANDARD); - // progressbar - oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); - oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); - progress = progress * (OLED_WIDTH - 4) / 1000; - if (progress > OLED_WIDTH - 4) { - progress = OLED_WIDTH - 4; - } - oledBox(2, OLED_HEIGHT - 6, 1 + progress, OLED_HEIGHT - 3, 1); - oledRefresh(); - // Check for Cancel / Initialize. - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - msg_tiny_id = 0xFFFF; - usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return sectrue; - } +secbool protectPinUiCallback(uint32_t wait, uint32_t progress, + const char *message) { + // Convert wait to secstr string. + char secstrbuf[] = _("________0 seconds"); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + do { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } while (secs > 0 && secstr >= secstrbuf); + if (wait == 1) { + // Change "seconds" to "second". + secstrbuf[16] = 0; + } + oledClear(); + oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), + FONT_STANDARD); + // progressbar + oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); + progress = progress * (OLED_WIDTH - 4) / 1000; + if (progress > OLED_WIDTH - 4) { + progress = OLED_WIDTH - 4; + } + oledBox(2, OLED_HEIGHT - 6, 1 + progress, OLED_HEIGHT - 3, 1); + oledRefresh(); + // Check for Cancel / Initialize. + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = + (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return sectrue; + } - return secfalse; + return secfalse; } -bool protectPin(bool use_cached) -{ - if (use_cached && session_isUnlocked()) { - return true; - } +bool protectPin(bool use_cached) { + if (use_cached && session_isUnlocked()) { + return true; + } - const char *pin = ""; - if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - } + const char *pin = ""; + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, + _("Please enter current PIN:")); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + } - bool ret = config_unlock(pin); - if (!ret) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - } - return ret; + bool ret = config_unlock(pin); + if (!ret) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } -bool protectChangePin(bool removal) -{ - static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; - static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; - const char* pin = NULL; +bool protectChangePin(bool removal) { + static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; + const char *pin = NULL; - if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (pin == NULL) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, + _("Please enter current PIN:")); + if (pin == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - // If removing, defer the check to config_changePin(). - if (!removal) { - usbTiny(1); - bool ret = config_unlock(pin); - usbTiny(0); - if (ret == false) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; - } - } + // If removing, defer the check to config_changePin(). + if (!removal) { + usbTiny(1); + bool ret = config_unlock(pin); + usbTiny(0); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; + } + } - strlcpy(old_pin, pin, sizeof(old_pin)); - } + strlcpy(old_pin, pin, sizeof(old_pin)); + } - if (!removal) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - strlcpy(new_pin, pin, sizeof(new_pin)); + if (!removal) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, + _("Please enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(new_pin, pin, sizeof(new_pin)); - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, + _("Please re-enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - return false; - } - } + if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + return false; + } + } - bool ret = config_changePin(old_pin, new_pin); - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - if (ret == false) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - } - return ret; + bool ret = config_changePin(old_pin, new_pin); + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } -bool protectPassphrase(void) -{ - bool passphrase_protection = false; - config_getPassphraseProtection(&passphrase_protection); - if (!passphrase_protection || session_isPassphraseCached()) { - return true; - } +bool protectPassphrase(void) { + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (!passphrase_protection || session_isPassphraseCached()) { + return true; + } - PassphraseRequest resp; - memzero(&resp, sizeof(PassphraseRequest)); - usbTiny(1); - msg_write(MessageType_MessageType_PassphraseRequest, &resp); + PassphraseRequest resp; + memzero(&resp, sizeof(PassphraseRequest)); + usbTiny(1); + msg_write(MessageType_MessageType_PassphraseRequest, &resp); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"), _("passphrase using"), _("the computer's"), _("keyboard."), NULL, NULL); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"), + _("passphrase using"), _("the computer's"), _("keyboard."), + NULL, NULL); - bool result; - for (;;) { - usbPoll(); - // TODO: correctly process PassphraseAck with state field set (mismatch => Failure) - if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { - msg_tiny_id = 0xFFFF; - PassphraseAck *ppa = (PassphraseAck *)msg_tiny; - session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : ""); - result = true; - break; - } - // check for Cancel / Initialize - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - msg_tiny_id = 0xFFFF; - result = false; - break; - } - } - usbTiny(0); - layoutHome(); - return result; + bool result; + for (;;) { + usbPoll(); + // TODO: correctly process PassphraseAck with state field set (mismatch => + // Failure) + if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { + msg_tiny_id = 0xFFFF; + PassphraseAck *ppa = (PassphraseAck *)msg_tiny; + session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : ""); + result = true; + break; + } + // check for Cancel / Initialize + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = + (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + msg_tiny_id = 0xFFFF; + result = false; + break; + } + } + usbTiny(0); + layoutHome(); + return result; } diff --git a/firmware/protect.h b/firmware/protect.h index fb269468fc..b948d8e6f8 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -25,7 +25,8 @@ #include "secbool.h" bool protectButton(ButtonRequestType type, bool confirm_only); -secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message); +secbool protectPinUiCallback(uint32_t wait, uint32_t progress, + const char* message); bool protectPin(bool use_cached); bool protectChangePin(bool removal); bool protectPassphrase(void); diff --git a/firmware/recovery-table.h b/firmware/recovery-table.h index 0efb114553..05cb2334b0 100644 --- a/firmware/recovery-table.h +++ b/firmware/recovery-table.h @@ -1,3 +1,4 @@ +// clang-format off /* * This file is part of the TREZOR project, https://trezor.io/ * diff --git a/firmware/recovery.c b/firmware/recovery.c index dd3b7edb09..e9f1c5e0cb 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -18,21 +18,21 @@ * along with this library. If not, see . */ -#include #include "recovery.h" -#include "fsm.h" -#include "config.h" -#include "layout2.h" -#include "protect.h" -#include "messages.h" -#include "rng.h" +#include #include "bip39.h" -#include "oled.h" -#include "usb.h" +#include "config.h" +#include "fsm.h" #include "gettext.h" -#include "recovery-table.h" +#include "layout2.h" #include "memzero.h" +#include "messages.h" #include "messages.pb.h" +#include "oled.h" +#include "protect.h" +#include "recovery-table.h" +#include "rng.h" +#include "usb.h" /* number of words expected in the new seed */ static uint32_t word_count; @@ -112,7 +112,7 @@ static uint8_t word_matrix[9]; * prefix length or table for the very first level, as the prefix length * is always one and there are always nine choices on the second level. */ -#define MASK_IDX(x) ((x) & 0xfff) +#define MASK_IDX(x) ((x)&0xfff) #define TABLE1(x) MASK_IDX(word_table1[x]) #define TABLE2(x) MASK_IDX(word_table2[x]) @@ -122,93 +122,102 @@ static uint8_t word_matrix[9]; * Parameter number gives the number that we should format. */ static void format_number(char *dest, int number) { - if (number < 10) { - dest[0] = ' '; - } else { - dest[0] = '0' + number / 10; - } - dest[1] = '0' + number % 10; - if (number == 1 || number == 21) { - dest[2] = 's'; dest[3] = 't'; - } else if (number == 2 || number == 22) { - dest[2] = 'n'; dest[3] = 'd'; - } else if (number == 3 || number == 23) { - dest[2] = 'r'; dest[3] = 'd'; - } + if (number < 10) { + dest[0] = ' '; + } else { + dest[0] = '0' + number / 10; + } + dest[1] = '0' + number % 10; + if (number == 1 || number == 21) { + dest[2] = 's'; + dest[3] = 't'; + } else if (number == 2 || number == 22) { + dest[2] = 'n'; + dest[3] = 'd'; + } else if (number == 3 || number == 23) { + dest[2] = 'r'; + dest[3] = 'd'; + } } /* Send a request for a new word/matrix code to the PC. */ static void recovery_request(void) { - WordRequest resp; - memzero(&resp, sizeof(WordRequest)); - resp.has_type = true; - resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain - : (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 - : WordRequestType_WordRequestType_Matrix9; - msg_write(MessageType_MessageType_WordRequest, &resp); + WordRequest resp; + memzero(&resp, sizeof(WordRequest)); + resp.has_type = true; + resp.type = awaiting_word == 1 + ? WordRequestType_WordRequestType_Plain + : (word_index % 4 == 3) + ? WordRequestType_WordRequestType_Matrix6 + : WordRequestType_WordRequestType_Matrix9; + msg_write(MessageType_MessageType_WordRequest, &resp); } /* Called when the last word was entered. * Check mnemonic and send success/failure. */ static void recovery_done(void) { - char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0}; + char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0}; - strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); - for (uint32_t i = 1; i < word_count; i++) { - strlcat(new_mnemonic, " ", sizeof(new_mnemonic)); - strlcat(new_mnemonic, words[i], sizeof(new_mnemonic)); - } - if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { - // New mnemonic is valid. - if (!dry_run) { - // Update mnemonic on config. - if (config_setMnemonic(new_mnemonic)) { - if (!enforce_wordlist) { - // not enforcing => mark config as imported - config_setImported(true); - } - fsm_sendSuccess(_("Device recovered")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } - memzero(new_mnemonic, sizeof(new_mnemonic)); - } else { - // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); - memzero(new_mnemonic, sizeof(new_mnemonic)); - if (match) { - layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, - _("The seed is valid"), - _("and MATCHES"), - _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - fsm_sendSuccess(_("The seed is valid and matches the one in the device")); - } else { - layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, - _("The seed is valid"), - _("but does NOT MATCH"), - _("the one in the device."), NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - fsm_sendFailure(FailureType_Failure_DataError, - _("The seed is valid but does not match the one in the device")); - } - } - } else { - // New mnemonic is invalid. - memzero(new_mnemonic, sizeof(new_mnemonic)); - if (!dry_run) { - session_clear(true); - } else { - layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, - _("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); - protectButton(ButtonRequestType_ButtonRequest_Other, true); - } - fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); - } - awaiting_word = 0; - layoutHome(); + strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); + for (uint32_t i = 1; i < word_count; i++) { + strlcat(new_mnemonic, " ", sizeof(new_mnemonic)); + strlcat(new_mnemonic, words[i], sizeof(new_mnemonic)); + } + if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { + // New mnemonic is valid. + if (!dry_run) { + // Update mnemonic on config. + if (config_setMnemonic(new_mnemonic)) { + if (!enforce_wordlist) { + // not enforcing => mark config as imported + config_setImported(true); + } + fsm_sendSuccess(_("Device recovered")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to store mnemonic")); + } + memzero(new_mnemonic, sizeof(new_mnemonic)); + } else { + // Inform the user about new mnemonic correctness (as well as whether it + // is the same as the current one). + bool match = + (config_isInitialized() && config_containsMnemonic(new_mnemonic)); + memzero(new_mnemonic, sizeof(new_mnemonic)); + if (match) { + layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, + _("The seed is valid"), _("and MATCHES"), + _("the one in the device."), NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendSuccess( + _("The seed is valid and matches the one in the device")); + } else { + layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, + _("The seed is valid"), _("but does NOT MATCH"), + _("the one in the device."), NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + fsm_sendFailure( + FailureType_Failure_DataError, + _("The seed is valid but does not match the one in the device")); + } + } + } else { + // New mnemonic is invalid. + memzero(new_mnemonic, sizeof(new_mnemonic)); + if (!dry_run) { + session_clear(true); + } else { + layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"), + _("INVALID!"), NULL, NULL, NULL, NULL); + protectButton(ButtonRequestType_ButtonRequest_Other, true); + } + fsm_sendFailure(FailureType_Failure_DataError, + _("Invalid seed, are words in correct order?")); + } + awaiting_word = 0; + layoutHome(); } /* Helper function for matrix recovery: @@ -222,36 +231,37 @@ static void recovery_done(void) { * memcmp(last, "last + 1", prefixlen) != 0 * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. */ -static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { - // assert 1 <= prefixlen <= 4 - char *dest = choice; - for (int i = 0; i < prefixlen; i++) { - *dest++ = toupper((int) first[i]); - } - if (first[0] != last[0]) { - /* special case WI-Z; also used for T-Z, etc. */ - *dest++ = '-'; - *dest++ = toupper((int) last[0]); - } else if (last[prefixlen-1] == first[prefixlen-1]) { - /* single prefix */ - } else if (prefixlen < 3) { - /* AB-AC, etc. */ - *dest++ = '-'; - for (int i = 0; i < prefixlen; i++) { - *dest++ = toupper((int) last[i]); - } - } else { - /* RE[A-M] etc. */ - /* remove last and replace with space */ - dest[-1] = ' '; - if (first[prefixlen - 1]) { - /* handle special case: CAN[-D] */ - *dest++ = toupper((int)first[prefixlen - 1]); - } - *dest++ = '-'; - *dest++ = toupper((int) last[prefixlen - 1]); - } - *dest++ = 0; +static void add_choice(char choice[12], int prefixlen, const char *first, + const char *last) { + // assert 1 <= prefixlen <= 4 + char *dest = choice; + for (int i = 0; i < prefixlen; i++) { + *dest++ = toupper((int)first[i]); + } + if (first[0] != last[0]) { + /* special case WI-Z; also used for T-Z, etc. */ + *dest++ = '-'; + *dest++ = toupper((int)last[0]); + } else if (last[prefixlen - 1] == first[prefixlen - 1]) { + /* single prefix */ + } else if (prefixlen < 3) { + /* AB-AC, etc. */ + *dest++ = '-'; + for (int i = 0; i < prefixlen; i++) { + *dest++ = toupper((int)last[i]); + } + } else { + /* RE[A-M] etc. */ + /* remove last and replace with space */ + dest[-1] = ' '; + if (first[prefixlen - 1]) { + /* handle special case: CAN[-D] */ + *dest++ = toupper((int)first[prefixlen - 1]); + } + *dest++ = '-'; + *dest++ = toupper((int)last[prefixlen - 1]); + } + *dest++ = 0; } /* Helper function for matrix recovery: @@ -259,122 +269,121 @@ static void add_choice(char choice[12], int prefixlen, const char *first, const * use 2x3 layout, otherwise 3x3 layout. Also generates a random * scrambling and stores it in word_matrix. */ -static void display_choices(bool twoColumn, char choices[9][12], int num) -{ - const int nColumns = twoColumn ? 2 : 3; - const int displayedChoices = nColumns * 3; - for (int i = 0; i < displayedChoices; i++) { - word_matrix[i] = i; - } - /* scramble matrix */ - random_permute((char*)word_matrix, displayedChoices); +static void display_choices(bool twoColumn, char choices[9][12], int num) { + const int nColumns = twoColumn ? 2 : 3; + const int displayedChoices = nColumns * 3; + for (int i = 0; i < displayedChoices; i++) { + word_matrix[i] = i; + } + /* scramble matrix */ + random_permute((char *)word_matrix, displayedChoices); - if (word_index % 4 == 0) { - char desc[] = "##th word"; - int nr = (word_index / 4) + 1; - format_number(desc, nr); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL, NULL, NULL); - } else { - oledBox(0, 27, 127, 63, false); - } + if (word_index % 4 == 0) { + char desc[] = "##th word"; + int nr = (word_index / 4) + 1; + format_number(desc, nr); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), + (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL, + NULL, NULL); + } else { + oledBox(0, 27, 127, 63, false); + } - for (int row = 0; row < 3; row ++) { - int y = 55 - row * 11; - for (int col = 0; col < nColumns; col++) { - int x = twoColumn ? 64 * col + 32 : 42 * col + 22; - int choice = word_matrix[nColumns*row + col]; - const char *text = choice < num ? choices[choice] : "-"; - oledDrawString(x - oledStringWidth(text, FONT_STANDARD)/2, y, text, FONT_STANDARD); - if (twoColumn) { - oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); - } else { - oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8); - } - } - } - oledRefresh(); + for (int row = 0; row < 3; row++) { + int y = 55 - row * 11; + for (int col = 0; col < nColumns; col++) { + int x = twoColumn ? 64 * col + 32 : 42 * col + 22; + int choice = word_matrix[nColumns * row + col]; + const char *text = choice < num ? choices[choice] : "-"; + oledDrawString(x - oledStringWidth(text, FONT_STANDARD) / 2, y, text, + FONT_STANDARD); + if (twoColumn) { + oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); + } else { + oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8); + } + } + } + oledRefresh(); - /* avoid picking out of range numbers */ - for (int i = 0; i < displayedChoices; i++) { - if (word_matrix[i] >= num) - word_matrix[i] = 0; - } - /* two column layout: middle column = right column */ - if (twoColumn) { - static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 }; - for (int i = 8; i >= 2; i--) { - word_matrix[i] = word_matrix[twolayout[i]]; - } - } + /* avoid picking out of range numbers */ + for (int i = 0; i < displayedChoices; i++) { + if (word_matrix[i] >= num) word_matrix[i] = 0; + } + /* two column layout: middle column = right column */ + if (twoColumn) { + static const uint8_t twolayout[9] = {0, 1, 1, 2, 3, 3, 4, 5, 5}; + for (int i = 8; i >= 2; i--) { + word_matrix[i] = word_matrix[twolayout[i]]; + } + } } /* Helper function for matrix recovery: * Generates a new matrix and requests the next pin. */ static void next_matrix(void) { - const char * const *wl = mnemonic_wordlist(); - char word_choices[9][12]; - uint32_t idx, num; - bool last = (word_index % 4) == 3; + const char *const *wl = mnemonic_wordlist(); + char word_choices[9][12]; + uint32_t idx, num; + bool last = (word_index % 4) == 3; - /* Build the matrix: - * num: number of choices - * word_choices[][]: the strings containing the choices - */ - switch (word_index % 4) { - case 3: - /* last level: show up to six words */ - /* idx: index in table2 for the entered choice. */ - /* first: the first word. */ - /* num: the number of words to choose from. */ - idx = TABLE1(word_pincode / 9) + word_pincode % 9; - const uint32_t first = TABLE2(idx); - num = TABLE2(idx + 1) - first; - for (uint32_t i = 0; i < num; i++) { - strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); - } - break; + /* Build the matrix: + * num: number of choices + * word_choices[][]: the strings containing the choices + */ + switch (word_index % 4) { + case 3: + /* last level: show up to six words */ + /* idx: index in table2 for the entered choice. */ + /* first: the first word. */ + /* num: the number of words to choose from. */ + idx = TABLE1(word_pincode / 9) + word_pincode % 9; + const uint32_t first = TABLE2(idx); + num = TABLE2(idx + 1) - first; + for (uint32_t i = 0; i < num; i++) { + strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); + } + break; - case 2: - /* third level: show up to nine ranges (using table2) */ - /* idx: first index in table2 corresponding to pin code. */ - /* num: the number of choices. */ - idx = TABLE1(word_pincode); - num = TABLE1(word_pincode + 1) - idx; - for (uint32_t i = 0; i < num; i++) { - add_choice(word_choices[i], (word_table2[idx + i] >> 12), - wl[TABLE2(idx + i)], - wl[TABLE2(idx + i + 1) - 1]); - } - break; + case 2: + /* third level: show up to nine ranges (using table2) */ + /* idx: first index in table2 corresponding to pin code. */ + /* num: the number of choices. */ + idx = TABLE1(word_pincode); + num = TABLE1(word_pincode + 1) - idx; + for (uint32_t i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table2[idx + i] >> 12), + wl[TABLE2(idx + i)], wl[TABLE2(idx + i + 1) - 1]); + } + break; - case 1: - /* second level: exactly nine ranges (using table1) */ - /* idx: first index in table1 corresponding to pin code. */ - /* num: the number of choices. */ - idx = word_pincode * 9; - num = 9; - for (uint32_t i = 0; i < num; i++) { - add_choice(word_choices[i], (word_table1[idx + i] >> 12), - wl[TABLE2(TABLE1(idx + i))], - wl[TABLE2(TABLE1(idx + i + 1)) - 1]); - } - break; + case 1: + /* second level: exactly nine ranges (using table1) */ + /* idx: first index in table1 corresponding to pin code. */ + /* num: the number of choices. */ + idx = word_pincode * 9; + num = 9; + for (uint32_t i = 0; i < num; i++) { + add_choice(word_choices[i], (word_table1[idx + i] >> 12), + wl[TABLE2(TABLE1(idx + i))], + wl[TABLE2(TABLE1(idx + i + 1)) - 1]); + } + break; - case 0: - /* first level: exactly nine ranges */ - /* num: the number of choices. */ - num = 9; - for (uint32_t i = 0; i < num; i++) { - add_choice(word_choices[i], 1, - wl[TABLE2(TABLE1(9*i))], - wl[TABLE2(TABLE1(9*(i+1)))-1]); - } - break; - } - display_choices(last, word_choices, num); + case 0: + /* first level: exactly nine ranges */ + /* num: the number of choices. */ + num = 9; + for (uint32_t i = 0; i < num; i++) { + add_choice(word_choices[i], 1, wl[TABLE2(TABLE1(9 * i))], + wl[TABLE2(TABLE1(9 * (i + 1))) - 1]); + } + break; + } + display_choices(last, word_choices, num); - recovery_request(); + recovery_request(); } /* Function called when a digit was entered by user. @@ -382,202 +391,203 @@ static void next_matrix(void) { * '\x08' for backspace. */ static void recovery_digit(const char digit) { - if (digit == 8) { - /* backspace: undo */ - if ((word_index % 4) == 0) { - /* undo complete word */ - if (word_index > 0) - word_index -= 4; - } else { - word_index--; - word_pincode /= 9; - } - next_matrix(); - return; - } + if (digit == 8) { + /* backspace: undo */ + if ((word_index % 4) == 0) { + /* undo complete word */ + if (word_index > 0) word_index -= 4; + } else { + word_index--; + word_pincode /= 9; + } + next_matrix(); + return; + } - if (digit < '1' || digit > '9') { - recovery_request(); - return; - } + if (digit < '1' || digit > '9') { + recovery_request(); + return; + } - int choice = word_matrix[digit - '1']; - if ((word_index % 4) == 3) { - /* received final word */ + int choice = word_matrix[digit - '1']; + if ((word_index % 4) == 3) { + /* received final word */ - /* Mark the chosen word for 250 ms */ - int y = 54 - ((digit - '1') / 3) * 11; - int x = 64 * (((digit - '1') % 3) > 0); - oledInvert(x + 1, y, x + 62, y + 9); - oledRefresh(); - usbTiny(1); - usbSleep(250); - usbTiny(0); + /* Mark the chosen word for 250 ms */ + int y = 54 - ((digit - '1') / 3) * 11; + int x = 64 * (((digit - '1') % 3) > 0); + oledInvert(x + 1, y, x + 62, y + 9); + oledRefresh(); + usbTiny(1); + usbSleep(250); + usbTiny(0); - /* index of the chosen word */ - int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; - uint32_t widx = word_index / 4; + /* index of the chosen word */ + int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; + uint32_t widx = word_index / 4; - word_pincode = 0; - strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx])); - if (widx + 1 == word_count) { - recovery_done(); - return; - } - /* next word */ - } else { - word_pincode = word_pincode * 9 + choice; - } - word_index++; - next_matrix(); + word_pincode = 0; + strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx])); + if (widx + 1 == word_count) { + recovery_done(); + return; + } + /* next word */ + } else { + word_pincode = word_pincode * 9 + choice; + } + word_index++; + next_matrix(); } /* Helper function for scrambled recovery: * Ask the user for the next word. */ void next_word(void) { - word_pos = word_order[word_index]; - if (word_pos == 0) { - const char * const *wl = mnemonic_wordlist(); - strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the word"), NULL, fake_word, NULL, _("on your computer"), NULL); - } else { - fake_word[0] = 0; - char desc[] = "##th word"; - format_number(desc, word_pos); - layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), NULL, (word_pos < 10 ? desc + 1 : desc), NULL, _("of your mnemonic"), NULL); - } - recovery_request(); + word_pos = word_order[word_index]; + if (word_pos == 0) { + const char *const *wl = mnemonic_wordlist(); + strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, + _("Please enter the word"), NULL, fake_word, NULL, + _("on your computer"), NULL); + } else { + fake_word[0] = 0; + char desc[] = "##th word"; + format_number(desc, word_pos); + layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), + NULL, (word_pos < 10 ? desc + 1 : desc), NULL, + _("of your mnemonic"), NULL); + } + recovery_request(); } -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run) -{ - if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; +void recovery_init(uint32_t _word_count, bool passphrase_protection, + bool pin_protection, const char *language, const char *label, + bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, + bool _dry_run) { + if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; - word_count = _word_count; - enforce_wordlist = _enforce_wordlist; - dry_run = _dry_run; + word_count = _word_count; + enforce_wordlist = _enforce_wordlist; + dry_run = _dry_run; - if (!dry_run) { - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (!dry_run) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("recover the device?"), + NULL, NULL, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (!dry_run) { - if (pin_protection && !protectChangePin(false)) { - layoutHome(); - return; - } + if (!dry_run) { + if (pin_protection && !protectChangePin(false)) { + layoutHome(); + return; + } - config_setPassphraseProtection(passphrase_protection); - config_setLanguage(language); - config_setLabel(label); - config_setU2FCounter(u2f_counter); - } + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); + } - if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { - awaiting_word = 2; - word_index = 0; - word_pincode = 0; - next_matrix(); - } else { - for (uint32_t i = 0; i < word_count; i++) { - word_order[i] = i + 1; - } - for (uint32_t i = word_count; i < 24; i++) { - word_order[i] = 0; - } - random_permute(word_order, 24); - awaiting_word = 1; - word_index = 0; - next_word(); - } + if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { + awaiting_word = 2; + word_index = 0; + word_pincode = 0; + next_matrix(); + } else { + for (uint32_t i = 0; i < word_count; i++) { + word_order[i] = i + 1; + } + for (uint32_t i = word_count; i < 24; i++) { + word_order[i] = 0; + } + random_permute(word_order, 24); + awaiting_word = 1; + word_index = 0; + next_word(); + } } -static void recovery_scrambledword(const char *word) -{ - if (word_pos == 0) { // fake word - if (strcmp(word, fake_word) != 0) { - if (!dry_run) { - session_clear(true); - } - fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); - layoutHome(); - return; - } - } else { // real word - if (enforce_wordlist) { // check if word is valid - const char * const *wl = mnemonic_wordlist(); - bool found = false; - while (*wl) { - if (strcmp(word, *wl) == 0) { - found = true; - break; - } - wl++; - } - if (!found) { - if (!dry_run) { - session_clear(true); - } - fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); - layoutHome(); - return; - } - } - strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); - } +static void recovery_scrambledword(const char *word) { + if (word_pos == 0) { // fake word + if (strcmp(word, fake_word) != 0) { + if (!dry_run) { + session_clear(true); + } + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Wrong word retyped")); + layoutHome(); + return; + } + } else { // real word + if (enforce_wordlist) { // check if word is valid + const char *const *wl = mnemonic_wordlist(); + bool found = false; + while (*wl) { + if (strcmp(word, *wl) == 0) { + found = true; + break; + } + wl++; + } + if (!found) { + if (!dry_run) { + session_clear(true); + } + fsm_sendFailure(FailureType_Failure_DataError, + _("Word not found in a wordlist")); + layoutHome(); + return; + } + } + strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); + } - if (word_index + 1 == 24) { // last one - recovery_done(); - } else { - word_index++; - next_word(); - } + if (word_index + 1 == 24) { // last one + recovery_done(); + } else { + word_index++; + next_word(); + } } /* Function called when a word was entered by user. Used * for scrambled recovery. */ -void recovery_word(const char *word) -{ - switch (awaiting_word) { - case 2: - recovery_digit(word[0]); - break; - case 1: - recovery_scrambledword(word); - break; - default: - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); - break; - } +void recovery_word(const char *word) { + switch (awaiting_word) { + case 2: + recovery_digit(word[0]); + break; + case 1: + recovery_scrambledword(word); + break; + default: + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Recovery mode")); + break; + } } /* Abort recovery. */ -void recovery_abort(void) -{ - if (awaiting_word) { - layoutHome(); - awaiting_word = 0; - } +void recovery_abort(void) { + if (awaiting_word) { + layoutHome(); + awaiting_word = 0; + } } #if DEBUG_LINK -const char *recovery_get_fake_word(void) -{ - return fake_word; -} +const char *recovery_get_fake_word(void) { return fake_word; } -uint32_t recovery_get_word_pos(void) -{ - return word_pos; -} +uint32_t recovery_get_word_pos(void) { return word_pos; } #endif diff --git a/firmware/recovery.h b/firmware/recovery.h index d0a63508ea..84a261aa05 100644 --- a/firmware/recovery.h +++ b/firmware/recovery.h @@ -20,10 +20,13 @@ #ifndef __RECOVERY_H__ #define __RECOVERY_H__ -#include #include +#include -void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run); +void recovery_init(uint32_t _word_count, bool passphrase_protection, + bool pin_protection, const char *language, const char *label, + bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, + bool _dry_run); void recovery_word(const char *word); void recovery_abort(void); const char *recovery_get_fake_word(void); diff --git a/firmware/reset.c b/firmware/reset.c index 82bf7191d6..1faef79ee9 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -18,180 +18,189 @@ */ #include "reset.h" +#include "bip39.h" #include "config.h" +#include "fsm.h" +#include "gettext.h" +#include "layout2.h" +#include "memzero.h" +#include "messages.h" +#include "messages.pb.h" +#include "protect.h" #include "rng.h" #include "sha2.h" -#include "messages.h" -#include "fsm.h" -#include "layout2.h" -#include "protect.h" -#include "bip39.h" #include "util.h" -#include "gettext.h" -#include "messages.pb.h" -#include "memzero.h" static uint32_t strength; -static uint8_t int_entropy[32]; -static bool awaiting_entropy = false; -static bool skip_backup = false; -static bool no_backup = false; +static uint8_t int_entropy[32]; +static bool awaiting_entropy = false; +static bool skip_backup = false; +static bool no_backup = false; -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup) -{ - if (_strength != 128 && _strength != 192 && _strength != 256) return; +void reset_init(bool display_random, uint32_t _strength, + bool passphrase_protection, bool pin_protection, + const char *language, const char *label, uint32_t u2f_counter, + bool _skip_backup, bool _no_backup) { + if (_strength != 128 && _strength != 192 && _strength != 256) return; - strength = _strength; - skip_backup = _skip_backup; - no_backup = _no_backup; + strength = _strength; + skip_backup = _skip_backup; + no_backup = _no_backup; - if (display_random && (skip_backup || no_backup)) { - fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when backup is skipped"); - layoutHome(); - return; - } + if (display_random && (skip_backup || no_backup)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + "Can't show internal entropy when backup is skipped"); + layoutHome(); + return; + } - layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, _("By continuing you"), _("agree to trezor.io/tos"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("create a new wallet?"), NULL, + _("By continuing you"), _("agree to trezor.io/tos"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - random_buffer(int_entropy, 32); + random_buffer(int_entropy, 32); - char ent_str[4][17]; - data2hex(int_entropy , 8, ent_str[0]); - data2hex(int_entropy + 8, 8, ent_str[1]); - data2hex(int_entropy + 16, 8, ent_str[2]); - data2hex(int_entropy + 24, 8, ent_str[3]); + char ent_str[4][17]; + data2hex(int_entropy, 8, ent_str[0]); + data2hex(int_entropy + 8, 8, ent_str[1]); + data2hex(int_entropy + 16, 8, ent_str[2]); + data2hex(int_entropy + 24, 8, ent_str[3]); - if (display_random) { - layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - layoutHome(); - return; - } - } + if (display_random) { + layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, + _("Internal entropy:"), ent_str[0], ent_str[1], + ent_str[2], ent_str[3], NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (pin_protection && !protectChangePin(false)) { - layoutHome(); - return; - } + if (pin_protection && !protectChangePin(false)) { + layoutHome(); + return; + } - config_setPassphraseProtection(passphrase_protection); - config_setLanguage(language); - config_setLabel(label); - config_setU2FCounter(u2f_counter); + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); - EntropyRequest resp; - memzero(&resp, sizeof(EntropyRequest)); - msg_write(MessageType_MessageType_EntropyRequest, &resp); - awaiting_entropy = true; + EntropyRequest resp; + memzero(&resp, sizeof(EntropyRequest)); + msg_write(MessageType_MessageType_EntropyRequest, &resp); + awaiting_entropy = true; } -void reset_entropy(const uint8_t *ext_entropy, uint32_t len) -{ - if (!awaiting_entropy) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); - return; - } - awaiting_entropy = false; +void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { + if (!awaiting_entropy) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Reset mode")); + return; + } + awaiting_entropy = false; - SHA256_CTX ctx; - sha256_Init(&ctx); - sha256_Update(&ctx, int_entropy, 32); - sha256_Update(&ctx, ext_entropy, len); - sha256_Final(&ctx, int_entropy); - const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); - memzero(int_entropy, 32); + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, int_entropy, 32); + sha256_Update(&ctx, ext_entropy, len); + sha256_Final(&ctx, int_entropy); + const char *mnemonic = mnemonic_from_data(int_entropy, strength / 8); + memzero(int_entropy, 32); - if (skip_backup || no_backup) { - if (no_backup) { - config_setNoBackup(); - } else { - config_setNeedsBackup(true); - } - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } - layoutHome(); - } else { - reset_backup(false, mnemonic); - } - mnemonic_clear(); + if (skip_backup || no_backup) { + if (no_backup) { + config_setNoBackup(); + } else { + config_setNeedsBackup(true); + } + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to store mnemonic")); + } + layoutHome(); + } else { + reset_backup(false, mnemonic); + } + mnemonic_clear(); } static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage -void reset_backup(bool separated, const char* mnemonic) -{ - if (separated) { - bool needs_backup = false; - config_getNeedsBackup(&needs_backup); - if (!needs_backup) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); - return; - } +void reset_backup(bool separated, const char *mnemonic) { + if (separated) { + bool needs_backup = false; + config_getNeedsBackup(&needs_backup); + if (!needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Seed already backed up")); + return; + } - config_setUnfinishedBackup(true); - config_setNeedsBackup(false); - } + config_setUnfinishedBackup(true); + config_setNeedsBackup(false); + } - for (int pass = 0; pass < 2; pass++) { - int i = 0, word_pos = 1; - while (mnemonic[i] != 0) { - // copy current_word - int j = 0; - while (mnemonic[i] != ' ' && mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { - current_word[j] = mnemonic[i]; - i++; j++; - } - current_word[j] = 0; - if (mnemonic[i] != 0) { - i++; - } - layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { - if (!separated) { - session_clear(true); - } - layoutHome(); - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - return; - } - word_pos++; - } - } + for (int pass = 0; pass < 2; pass++) { + int i = 0, word_pos = 1; + while (mnemonic[i] != 0) { + // copy current_word + int j = 0; + while (mnemonic[i] != ' ' && mnemonic[i] != 0 && + j + 1 < (int)sizeof(current_word)) { + current_word[j] = mnemonic[i]; + i++; + j++; + } + current_word[j] = 0; + if (mnemonic[i] != 0) { + i++; + } + layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { + if (!separated) { + session_clear(true); + } + layoutHome(); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return; + } + word_pos++; + } + } - config_setUnfinishedBackup(false); + config_setUnfinishedBackup(false); - if (separated) { - fsm_sendSuccess(_("Seed successfully backed up")); - } else { - config_setNeedsBackup(false); - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } - } - layoutHome(); + if (separated) { + fsm_sendSuccess(_("Seed successfully backed up")); + } else { + config_setNeedsBackup(false); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to store mnemonic")); + } + } + layoutHome(); } #if DEBUG_LINK uint32_t reset_get_int_entropy(uint8_t *entropy) { - memcpy(entropy, int_entropy, 32); - return 32; + memcpy(entropy, int_entropy, 32); + return 32; } -const char *reset_get_word(void) { - return current_word; -} +const char *reset_get_word(void) { return current_word; } #endif diff --git a/firmware/reset.h b/firmware/reset.h index 3ceea7533b..e9aba0b6d9 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -20,12 +20,15 @@ #ifndef __RESET_H__ #define __RESET_H__ -#include #include +#include -void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup); +void reset_init(bool display_random, uint32_t _strength, + bool passphrase_protection, bool pin_protection, + const char *language, const char *label, uint32_t u2f_counter, + bool _skip_backup, bool _no_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); -void reset_backup(bool separated, const char* mnemonic); +void reset_backup(bool separated, const char *mnemonic); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); diff --git a/firmware/signing.c b/firmware/signing.c index 035ab05c72..c69cccef53 100644 --- a/firmware/signing.c +++ b/firmware/signing.c @@ -18,17 +18,17 @@ */ #include "signing.h" -#include "fsm.h" -#include "layout2.h" -#include "messages.h" -#include "transaction.h" -#include "ecdsa.h" -#include "protect.h" #include "crypto.h" -#include "secp256k1.h" +#include "ecdsa.h" +#include "fsm.h" #include "gettext.h" -#include "messages.pb.h" +#include "layout2.h" #include "memzero.h" +#include "messages.h" +#include "messages.pb.h" +#include "protect.h" +#include "secp256k1.h" +#include "transaction.h" static uint32_t inputs_count; static uint32_t outputs_count; @@ -37,18 +37,18 @@ static CONFIDENTIAL HDNode root; static CONFIDENTIAL HDNode node; static bool signing = false; enum { - STAGE_REQUEST_1_INPUT, - STAGE_REQUEST_2_PREV_META, - STAGE_REQUEST_2_PREV_INPUT, - STAGE_REQUEST_2_PREV_OUTPUT, - STAGE_REQUEST_2_PREV_EXTRADATA, - STAGE_REQUEST_3_OUTPUT, - STAGE_REQUEST_4_INPUT, - STAGE_REQUEST_4_OUTPUT, - STAGE_REQUEST_SEGWIT_INPUT, - STAGE_REQUEST_5_OUTPUT, - STAGE_REQUEST_SEGWIT_WITNESS, - STAGE_REQUEST_DECRED_WITNESS + STAGE_REQUEST_1_INPUT, + STAGE_REQUEST_2_PREV_META, + STAGE_REQUEST_2_PREV_INPUT, + STAGE_REQUEST_2_PREV_OUTPUT, + STAGE_REQUEST_2_PREV_EXTRADATA, + STAGE_REQUEST_3_OUTPUT, + STAGE_REQUEST_4_INPUT, + STAGE_REQUEST_4_OUTPUT, + STAGE_REQUEST_SEGWIT_INPUT, + STAGE_REQUEST_5_OUTPUT, + STAGE_REQUEST_SEGWIT_WITNESS, + STAGE_REQUEST_DECRED_WITNESS } signing_stage; static uint32_t idx1, idx2; static uint32_t signatures; @@ -59,7 +59,7 @@ static TxStruct to, tp, ti; static Hasher hasher_prevouts, hasher_sequence, hasher_outputs, hasher_check; static uint8_t CONFIDENTIAL privkey[32]; static uint8_t pubkey[33], sig[64]; -static uint8_t hash_prevouts[32], hash_sequence[32],hash_outputs[32]; +static uint8_t hash_prevouts[32], hash_sequence[32], hash_outputs[32]; static uint8_t hash_prefix[32]; static uint8_t hash_check[32]; static uint64_t to_spend, authorized_amount, spending, change_spend; @@ -81,9 +81,9 @@ static uint32_t tx_weight; input */ #define BIP32_NOCHANGEALLOWED 1 /* The number of bip32 levels used in a wallet (chain and address) */ -#define BIP32_WALLET_DEPTH 2 +#define BIP32_WALLET_DEPTH 2 /* The chain id used for change */ -#define BIP32_CHANGE_CHAIN 1 +#define BIP32_CHANGE_CHAIN 1 /* The maximum allowed change address. This should be large enough for normal use and still allow to quickly brute-force the correct bip32 path. */ #define BIP32_MAX_LAST_ELEMENT 1000000 @@ -96,17 +96,16 @@ static uint32_t tx_weight; #define TXSIZE_SEGWIT_OVERHEAD 2 enum { - SIGHASH_ALL = 1, - SIGHASH_FORKID = 0x40, + SIGHASH_ALL = 1, + SIGHASH_FORKID = 0x40, }; enum { - DECRED_SERIALIZE_FULL = 0, - DECRED_SERIALIZE_NO_WITNESS = 1, - DECRED_SERIALIZE_WITNESS_SIGNING = 3, + DECRED_SERIALIZE_FULL = 0, + DECRED_SERIALIZE_NO_WITNESS = 1, + DECRED_SERIALIZE_WITNESS_SIGNING = 3, }; - /* progress_step/meta_step are fixed point numbers, giving the * progress per input in permille with these many additional bits. */ @@ -126,29 +125,20 @@ Phase1 - check inputs, previous transactions, and outputs ========================================================= foreach I (idx1): - Request I STAGE_REQUEST_1_INPUT - Add I to segwit hash_prevouts, hash_sequence + Request I STAGE_REQUEST_1_INPUT Add I to segwit hash_prevouts, hash_sequence Add I to Decred hash_prefix Add I to TransactionChecksum (prevout and type) if (Decred) Return I If not segwit, Calculate amount of I: - Request prevhash I, META STAGE_REQUEST_2_PREV_META - foreach prevhash I (idx2): - Request prevhash I STAGE_REQUEST_2_PREV_INPUT - foreach prevhash O (idx2): - Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT - Add amount of prevhash O (which is amount of I) - Request prevhash extra data (if applicable) STAGE_REQUEST_2_PREV_EXTRADATA - Calculate hash of streamed tx, compare to prevhash I -foreach O (idx1): - Request O STAGE_REQUEST_3_OUTPUT - Add O to Decred hash_prefix - Add O to TransactionChecksum - if (Decred) - Return O - Display output - Ask for confirmation + Request prevhash I, META STAGE_REQUEST_2_PREV_META foreach prevhash I +(idx2): Request prevhash I STAGE_REQUEST_2_PREV_INPUT foreach prevhash O (idx2): + Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT Add amount of +prevhash O (which is amount of I) Request prevhash extra data (if applicable) +STAGE_REQUEST_2_PREV_EXTRADATA Calculate hash of streamed tx, compare to +prevhash I foreach O (idx1): Request O STAGE_REQUEST_3_OUTPUT Add O to Decred +hash_prefix Add O to TransactionChecksum if (Decred) Return O Display output Ask +for confirmation Check tx fee Ask for confirmation @@ -161,21 +151,17 @@ if (Decred) foreach I (idx1): // input to sign if (idx1 is segwit) - Request I STAGE_REQUEST_SEGWIT_INPUT - Return serialized input chunk + Request I STAGE_REQUEST_SEGWIT_INPUT Return serialized input chunk else foreach I (idx2): - Request I STAGE_REQUEST_4_INPUT - If idx1 == idx2 - Fill scriptsig + Request I STAGE_REQUEST_4_INPUT If idx1 == idx2 Fill scriptsig Remember key for signing Add I to StreamTransactionSign Add I to TransactionChecksum foreach O (idx2): - Request O STAGE_REQUEST_4_OUTPUT - Add O to StreamTransactionSign - Add O to TransactionChecksum + Request O STAGE_REQUEST_4_OUTPUT Add O to StreamTransactionSign Add +O to TransactionChecksum Compare TransactionChecksum with checksum computed in Phase 1 If different: @@ -184,1270 +170,1369 @@ foreach I (idx1): // input to sign Return signed chunk foreach O (idx1): - Request O STAGE_REQUEST_5_OUTPUT - Rewrite change address - Return O + Request O STAGE_REQUEST_5_OUTPUT Rewrite change address Return O Phase3: sign segwit inputs, check that nothing changed =============================================== foreach I (idx1): // input to sign - Request I STAGE_REQUEST_SEGWIT_WITNESS - Check amount - Sign segwit prevhash, sequence, amount, outputs - Return witness + Request I STAGE_REQUEST_SEGWIT_WITNESS Check amount Sign segwit prevhash, +sequence, amount, outputs Return witness Phase3: sign Decred inputs ========================== -foreach I (idx1): // input to sign STAGE_REQUEST_DECRED_WITNESS - Request I - Fill scriptSig - Compute hash_witness +foreach I (idx1): // input to sign STAGE_REQUEST_DECRED_WITNESS Request I Fill +scriptSig Compute hash_witness Sign (hash_type || hash_prefix || hash_witness) Return witness */ -void send_req_1_input(void) -{ - signing_stage = STAGE_REQUEST_1_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_1_input(void) { + signing_stage = STAGE_REQUEST_1_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_meta(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_META; - resp.has_request_type = true; - resp.request_type = RequestType_TXMETA; - resp.has_details = true; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, input.prev_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_meta(void) { + signing_stage = STAGE_REQUEST_2_PREV_META; + resp.has_request_type = true; + resp.request_type = RequestType_TXMETA; + resp.has_details = true; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + input.prev_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_input(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_input(void) { + signing_stage = STAGE_REQUEST_2_PREV_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_output(void) -{ - signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_output(void) { + signing_stage = STAGE_REQUEST_2_PREV_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) -{ - signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; - resp.has_request_type = true; - resp.request_type = RequestType_TXEXTRADATA; - resp.has_details = true; - resp.details.has_extra_data_offset = true; - resp.details.extra_data_offset = chunk_offset; - resp.details.has_extra_data_len = true; - resp.details.extra_data_len = chunk_len; - resp.details.has_tx_hash = true; - resp.details.tx_hash.size = input.prev_hash.size; - memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size); - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len) { + signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA; + resp.has_request_type = true; + resp.request_type = RequestType_TXEXTRADATA; + resp.has_details = true; + resp.details.has_extra_data_offset = true; + resp.details.extra_data_offset = chunk_offset; + resp.details.has_extra_data_len = true; + resp.details.extra_data_len = chunk_len; + resp.details.has_tx_hash = true; + resp.details.tx_hash.size = input.prev_hash.size; + memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, + resp.details.tx_hash.size); + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_3_output(void) -{ - signing_stage = STAGE_REQUEST_3_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_3_output(void) { + signing_stage = STAGE_REQUEST_3_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_4_input(void) -{ - signing_stage = STAGE_REQUEST_4_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_4_input(void) { + signing_stage = STAGE_REQUEST_4_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_4_output(void) -{ - signing_stage = STAGE_REQUEST_4_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx2; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_4_output(void) { + signing_stage = STAGE_REQUEST_4_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx2; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_segwit_input(void) -{ - signing_stage = STAGE_REQUEST_SEGWIT_INPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_segwit_input(void) { + signing_stage = STAGE_REQUEST_SEGWIT_INPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_segwit_witness(void) -{ - signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_segwit_witness(void) { + signing_stage = STAGE_REQUEST_SEGWIT_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_decred_witness(void) -{ - signing_stage = STAGE_REQUEST_DECRED_WITNESS; - resp.has_request_type = true; - resp.request_type = RequestType_TXINPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_decred_witness(void) { + signing_stage = STAGE_REQUEST_DECRED_WITNESS; + resp.has_request_type = true; + resp.request_type = RequestType_TXINPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_5_output(void) -{ - signing_stage = STAGE_REQUEST_5_OUTPUT; - resp.has_request_type = true; - resp.request_type = RequestType_TXOUTPUT; - resp.has_details = true; - resp.details.has_request_index = true; - resp.details.request_index = idx1; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_5_output(void) { + signing_stage = STAGE_REQUEST_5_OUTPUT; + resp.has_request_type = true; + resp.request_type = RequestType_TXOUTPUT; + resp.has_details = true; + resp.details.has_request_index = true; + resp.details.request_index = idx1; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void send_req_finished(void) -{ - resp.has_request_type = true; - resp.request_type = RequestType_TXFINISHED; - msg_write(MessageType_MessageType_TxRequest, &resp); +void send_req_finished(void) { + resp.has_request_type = true; + resp.request_type = RequestType_TXFINISHED; + msg_write(MessageType_MessageType_TxRequest, &resp); } -void phase1_request_next_input(void) -{ - if (idx1 < inputs_count - 1) { - idx1++; - send_req_1_input(); - } else { - // compute segwit hashPrevouts & hashSequence - hasher_Final(&hasher_prevouts, hash_prevouts); - hasher_Final(&hasher_sequence, hash_sequence); - hasher_Final(&hasher_check, hash_check); - // init hashOutputs - hasher_Reset(&hasher_outputs); - idx1 = 0; - send_req_3_output(); - } +void phase1_request_next_input(void) { + if (idx1 < inputs_count - 1) { + idx1++; + send_req_1_input(); + } else { + // compute segwit hashPrevouts & hashSequence + hasher_Final(&hasher_prevouts, hash_prevouts); + hasher_Final(&hasher_sequence, hash_sequence); + hasher_Final(&hasher_check, hash_check); + // init hashOutputs + hasher_Reset(&hasher_outputs); + idx1 = 0; + send_req_3_output(); + } } -void phase2_request_next_input(void) -{ - if (idx1 == next_nonsegwit_input) { - idx2 = 0; - send_req_4_input(); - } else { - send_req_segwit_input(); - } +void phase2_request_next_input(void) { + if (idx1 == next_nonsegwit_input) { + idx2 = 0; + send_req_4_input(); + } else { + send_req_segwit_input(); + } } -void extract_input_bip32_path(const TxInputType *tinput) -{ - if (in_address_n_count == BIP32_NOCHANGEALLOWED) { - return; - } - size_t count = tinput->address_n_count; - if (count < BIP32_WALLET_DEPTH) { - // no change address allowed - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } - if (in_address_n_count == 0) { - // initialize in_address_n on first input seen - in_address_n_count = count; - // store the bip32 path up to the account - memcpy(in_address_n, tinput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)); - return; - } - // check that all addresses use a path of same length - if (in_address_n_count != count) { - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } - // check that the bip32 path up to the account matches - if (memcmp(in_address_n, tinput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) != 0) { - // mismatch -> no change address allowed - in_address_n_count = BIP32_NOCHANGEALLOWED; - return; - } +void extract_input_bip32_path(const TxInputType *tinput) { + if (in_address_n_count == BIP32_NOCHANGEALLOWED) { + return; + } + size_t count = tinput->address_n_count; + if (count < BIP32_WALLET_DEPTH) { + // no change address allowed + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } + if (in_address_n_count == 0) { + // initialize in_address_n on first input seen + in_address_n_count = count; + // store the bip32 path up to the account + memcpy(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)); + return; + } + // check that all addresses use a path of same length + if (in_address_n_count != count) { + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } + // check that the bip32 path up to the account matches + if (memcmp(in_address_n, tinput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) != 0) { + // mismatch -> no change address allowed + in_address_n_count = BIP32_NOCHANGEALLOWED; + return; + } } -bool check_change_bip32_path(const TxOutputType *toutput) -{ - size_t count = toutput->address_n_count; +bool check_change_bip32_path(const TxOutputType *toutput) { + size_t count = toutput->address_n_count; - // Check that the change path has the same bip32 path length, - // the same path up to the account, and that the wallet components - // (chain id and address) are as expected. - // Note: count >= BIP32_WALLET_DEPTH and count == in_address_n_count - // imply that in_address_n_count != BIP32_NOCHANGEALLOWED - return (count >= BIP32_WALLET_DEPTH - && count == in_address_n_count - && 0 == memcmp(in_address_n, toutput->address_n, - (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) - && toutput->address_n[count - 2] <= BIP32_CHANGE_CHAIN - && toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); + // Check that the change path has the same bip32 path length, + // the same path up to the account, and that the wallet components + // (chain id and address) are as expected. + // Note: count >= BIP32_WALLET_DEPTH and count == in_address_n_count + // imply that in_address_n_count != BIP32_NOCHANGEALLOWED + return (count >= BIP32_WALLET_DEPTH && count == in_address_n_count && + 0 == memcmp(in_address_n, toutput->address_n, + (count - BIP32_WALLET_DEPTH) * sizeof(uint32_t)) && + toutput->address_n[count - 2] <= BIP32_CHANGE_CHAIN && + toutput->address_n[count - 1] <= BIP32_MAX_LAST_ELEMENT); } -bool compile_input_script_sig(TxInputType *tinput) -{ - if (!multisig_fp_mismatch) { - // check that this is still multisig - uint8_t h[32]; - if (!tinput->has_multisig - || cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 - || memcmp(multisig_fp, h, 32) != 0) { - // Transaction has changed during signing - return false; - } - } - if (in_address_n_count != BIP32_NOCHANGEALLOWED) { - // check that input address didn't change - size_t count = tinput->address_n_count; - if (count < 2 - || count != in_address_n_count - || 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) { - return false; - } - } - memcpy(&node, &root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, tinput->address_n, tinput->address_n_count, NULL) == 0) { - // Failed to derive private key - return false; - } - hdnode_fill_public_key(&node); - if (tinput->has_multisig) { - tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), tinput->script_sig.bytes); - } else { // SPENDADDRESS - uint8_t hash[20]; - ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_pubkey, hash); - tinput->script_sig.size = compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); - } - return tinput->script_sig.size > 0; +bool compile_input_script_sig(TxInputType *tinput) { + if (!multisig_fp_mismatch) { + // check that this is still multisig + uint8_t h[32]; + if (!tinput->has_multisig || + cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 || + memcmp(multisig_fp, h, 32) != 0) { + // Transaction has changed during signing + return false; + } + } + if (in_address_n_count != BIP32_NOCHANGEALLOWED) { + // check that input address didn't change + size_t count = tinput->address_n_count; + if (count < 2 || count != in_address_n_count || + 0 != memcmp(in_address_n, tinput->address_n, + (count - 2) * sizeof(uint32_t))) { + return false; + } + } + memcpy(&node, &root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, tinput->address_n, + tinput->address_n_count, NULL) == 0) { + // Failed to derive private key + return false; + } + hdnode_fill_public_key(&node); + if (tinput->has_multisig) { + tinput->script_sig.size = compile_script_multisig(coin, &(tinput->multisig), + tinput->script_sig.bytes); + } else { // SPENDADDRESS + uint8_t hash[20]; + ecdsa_get_pubkeyhash(node.public_key, coin->curve->hasher_pubkey, hash); + tinput->script_sig.size = + compile_script_sig(coin->address_type, hash, tinput->script_sig.bytes); + } + return tinput->script_sig.size > 0; } -void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root) -{ - inputs_count = msg->inputs_count; - outputs_count = msg->outputs_count; - coin = _coin; - memcpy(&root, _root, sizeof(HDNode)); - version = msg->version; - lock_time = msg->lock_time; - expiry = msg->expiry; - overwintered = msg->has_overwintered && msg->overwintered; - version_group_id = msg->version_group_id; - branch_id = msg->branch_id; - // set default values for Zcash if branch_id is unset - if (overwintered && (branch_id == 0)) { - switch (version) { - case 3: - branch_id = 0x5BA81B19; // Overwinter - break; - case 4: - branch_id = 0x76B809BB; // Sapling - break; - } - } +void signing_init(const SignTx *msg, const CoinInfo *_coin, + const HDNode *_root) { + inputs_count = msg->inputs_count; + outputs_count = msg->outputs_count; + coin = _coin; + memcpy(&root, _root, sizeof(HDNode)); + version = msg->version; + lock_time = msg->lock_time; + expiry = msg->expiry; + overwintered = msg->has_overwintered && msg->overwintered; + version_group_id = msg->version_group_id; + branch_id = msg->branch_id; + // set default values for Zcash if branch_id is unset + if (overwintered && (branch_id == 0)) { + switch (version) { + case 3: + branch_id = 0x5BA81B19; // Overwinter + break; + case 4: + branch_id = 0x76B809BB; // Sapling + break; + } + } - uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + ser_length_size(inputs_count) + ser_length_size(outputs_count); - if (coin->decred) { - size += 4; // Decred expiry - size += ser_length_size(inputs_count); // Witness inputs count - } + uint32_t size = TXSIZE_HEADER + TXSIZE_FOOTER + + ser_length_size(inputs_count) + + ser_length_size(outputs_count); + if (coin->decred) { + size += 4; // Decred expiry + size += ser_length_size(inputs_count); // Witness inputs count + } - tx_weight = 4 * size; + tx_weight = 4 * size; - signatures = 0; - idx1 = 0; - to_spend = 0; - spending = 0; - change_spend = 0; - authorized_amount = 0; - memzero(&input, sizeof(TxInputType)); - memzero(&resp, sizeof(TxRequest)); + signatures = 0; + idx1 = 0; + to_spend = 0; + spending = 0; + change_spend = 0; + authorized_amount = 0; + memzero(&input, sizeof(TxInputType)); + memzero(&resp, sizeof(TxRequest)); - signing = true; - progress = 0; - // we step by 500/inputs_count per input in phase1 and phase2 - // this means 50 % per phase. - progress_step = (500 << PROGRESS_PRECISION) / inputs_count; + signing = true; + progress = 0; + // we step by 500/inputs_count per input in phase1 and phase2 + // this means 50 % per phase. + progress_step = (500 << PROGRESS_PRECISION) / inputs_count; - in_address_n_count = 0; - multisig_fp_set = false; - multisig_fp_mismatch = false; - next_nonsegwit_input = 0xffffffff; + in_address_n_count = 0; + multisig_fp_set = false; + multisig_fp_mismatch = false; + next_nonsegwit_input = 0xffffffff; - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, + coin->curve->hasher_sign, overwintered, version_group_id); - if (coin->decred) { - to.version |= (DECRED_SERIALIZE_FULL << 16); - to.is_decred = true; + if (coin->decred) { + to.version |= (DECRED_SERIALIZE_FULL << 16); + to.is_decred = true; - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); - ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); - ti.is_decred = true; - } + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + coin->curve->hasher_sign, overwintered, version_group_id); + ti.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + ti.is_decred = true; + } - // segwit hashes for hashPrevouts and hashSequence - if (overwintered) { - hasher_InitParam(&hasher_prevouts, HASHER_BLAKE2B_PERSONAL, "ZcashPrevoutHash", 16); - hasher_InitParam(&hasher_sequence, HASHER_BLAKE2B_PERSONAL, "ZcashSequencHash", 16); - hasher_InitParam(&hasher_outputs, HASHER_BLAKE2B_PERSONAL, "ZcashOutputsHash", 16); - hasher_Init(&hasher_check, coin->curve->hasher_sign); - } else { - hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); - hasher_Init(&hasher_sequence, coin->curve->hasher_sign); - hasher_Init(&hasher_outputs, coin->curve->hasher_sign); - hasher_Init(&hasher_check, coin->curve->hasher_sign); - } + // segwit hashes for hashPrevouts and hashSequence + if (overwintered) { + hasher_InitParam(&hasher_prevouts, HASHER_BLAKE2B_PERSONAL, + "ZcashPrevoutHash", 16); + hasher_InitParam(&hasher_sequence, HASHER_BLAKE2B_PERSONAL, + "ZcashSequencHash", 16); + hasher_InitParam(&hasher_outputs, HASHER_BLAKE2B_PERSONAL, + "ZcashOutputsHash", 16); + hasher_Init(&hasher_check, coin->curve->hasher_sign); + } else { + hasher_Init(&hasher_prevouts, coin->curve->hasher_sign); + hasher_Init(&hasher_sequence, coin->curve->hasher_sign); + hasher_Init(&hasher_outputs, coin->curve->hasher_sign); + hasher_Init(&hasher_check, coin->curve->hasher_sign); + } - layoutProgressSwipe(_("Signing transaction"), 0); + layoutProgressSwipe(_("Signing transaction"), 0); - send_req_1_input(); + send_req_1_input(); } -#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) static bool signing_check_input(const TxInputType *txinput) { - /* compute multisig fingerprint */ - /* (if all input share the same fingerprint, outputs having the same fingerprint will be considered as change outputs) */ - if (txinput->has_multisig && !multisig_fp_mismatch) { - uint8_t h[32]; - if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing multisig fingerprint")); - signing_abort(); - return false; - } - if (multisig_fp_set) { - if (memcmp(multisig_fp, h, 32) != 0) { - multisig_fp_mismatch = true; - } - } else { - memcpy(multisig_fp, h, 32); - multisig_fp_set = true; - } - } else { // single signature - multisig_fp_mismatch = true; - } - // remember the input bip32 path - // change addresses must use the same bip32 path as all inputs - extract_input_bip32_path(txinput); - // compute segwit hashPrevouts & hashSequence - tx_prevout_hash(&hasher_prevouts, txinput); - tx_sequence_hash(&hasher_sequence, txinput); - if (coin->decred) { - if (txinput->decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred v1+ scripts are not supported")); - signing_abort(); - return false; - } + /* compute multisig fingerprint */ + /* (if all input share the same fingerprint, outputs having the same + * fingerprint will be considered as change outputs) */ + if (txinput->has_multisig && !multisig_fp_mismatch) { + uint8_t h[32]; + if (cryptoMultisigFingerprint(&txinput->multisig, h) == 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Error computing multisig fingerprint")); + signing_abort(); + return false; + } + if (multisig_fp_set) { + if (memcmp(multisig_fp, h, 32) != 0) { + multisig_fp_mismatch = true; + } + } else { + memcpy(multisig_fp, h, 32); + multisig_fp_set = true; + } + } else { // single signature + multisig_fp_mismatch = true; + } + // remember the input bip32 path + // change addresses must use the same bip32 path as all inputs + extract_input_bip32_path(txinput); + // compute segwit hashPrevouts & hashSequence + tx_prevout_hash(&hasher_prevouts, txinput); + tx_sequence_hash(&hasher_sequence, txinput); + if (coin->decred) { + if (txinput->decred_script_version > 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Decred v1+ scripts are not supported")); + signing_abort(); + return false; + } - // serialize Decred prefix in Phase 1 - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_input(&to, txinput, resp.serialized.serialized_tx.bytes); + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = + tx_serialize_input(&to, txinput, resp.serialized.serialized_tx.bytes); - // compute Decred hashPrefix - tx_serialize_input_hash(&ti, txinput); - } - // hash prevout and script type to check it later (relevant for fee computation) - tx_prevout_hash(&hasher_check, txinput); - hasher_Update(&hasher_check, (const uint8_t *)&txinput->script_type, sizeof(&txinput->script_type)); - return true; + // compute Decred hashPrefix + tx_serialize_input_hash(&ti, txinput); + } + // hash prevout and script type to check it later (relevant for fee + // computation) + tx_prevout_hash(&hasher_check, txinput); + hasher_Update(&hasher_check, (const uint8_t *)&txinput->script_type, + sizeof(&txinput->script_type)); + return true; } // check if the hash of the prevtx matches static bool signing_check_prevtx_hash(void) { - uint8_t hash[32]; - tx_hash_final(&tp, hash, true); - if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Encountered invalid prevhash")); - signing_abort(); - return false; - } - phase1_request_next_input(); - return true; + uint8_t hash[32]; + tx_hash_final(&tp, hash, true); + if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Encountered invalid prevhash")); + signing_abort(); + return false; + } + phase1_request_next_input(); + return true; } static bool signing_check_output(TxOutputType *txoutput) { - // Phase1: Check outputs - // add it to hash_outputs - // ask user for permission + // Phase1: Check outputs + // add it to hash_outputs + // ask user for permission - // check for change address - bool is_change = false; - if (txoutput->address_n_count > 0) { - if (txoutput->has_address) { - fsm_sendFailure(FailureType_Failure_DataError, _("Address in change output")); - signing_abort(); - return false; - } - /* - * For multisig check that all inputs are multisig - */ - if (txoutput->has_multisig) { - uint8_t h[32]; - if (multisig_fp_set && !multisig_fp_mismatch - && cryptoMultisigFingerprint(&(txoutput->multisig), h) - && memcmp(multisig_fp, h, 32) == 0) { - is_change = check_change_bip32_path(txoutput); - } - } else { - is_change = check_change_bip32_path(txoutput); - } - /* - * only allow segwit change if amount is smaller than what segwit inputs paid. - * this was added during the times segwit was not yet fully activated - * to make sure the user is not tricked to use witness change output - * instead of regular one therefore creating ANYONECANSPEND output - */ - if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS - || txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) - && txoutput->amount > authorized_amount) { - is_change = false; - } - } + // check for change address + bool is_change = false; + if (txoutput->address_n_count > 0) { + if (txoutput->has_address) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Address in change output")); + signing_abort(); + return false; + } + /* + * For multisig check that all inputs are multisig + */ + if (txoutput->has_multisig) { + uint8_t h[32]; + if (multisig_fp_set && !multisig_fp_mismatch && + cryptoMultisigFingerprint(&(txoutput->multisig), h) && + memcmp(multisig_fp, h, 32) == 0) { + is_change = check_change_bip32_path(txoutput); + } + } else { + is_change = check_change_bip32_path(txoutput); + } + /* + * only allow segwit change if amount is smaller than what segwit inputs + * paid. this was added during the times segwit was not yet fully activated + * to make sure the user is not tricked to use witness change output + * instead of regular one therefore creating ANYONECANSPEND output + */ + if ((txoutput->script_type == OutputScriptType_PAYTOWITNESS || + txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) && + txoutput->amount > authorized_amount) { + is_change = false; + } + } - if (is_change) { - if (change_spend == 0) { // not set - change_spend = txoutput->amount; - } else { - /* We only skip confirmation for the first change output */ - is_change = false; - } - } + if (is_change) { + if (change_spend == 0) { // not set + change_spend = txoutput->amount; + } else { + /* We only skip confirmation for the first change output */ + is_change = false; + } + } - if (spending + txoutput->amount < spending) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); - signing_abort(); - return false; - } - spending += txoutput->amount; - int co = compile_output(coin, &root, txoutput, &bin_output, !is_change); - if (!is_change) { - layoutProgress(_("Signing transaction"), progress); - } - if (co < 0) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - signing_abort(); - return false; - } else if (co == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); - signing_abort(); - return false; - } - if (coin->decred) { - // serialize Decred prefix in Phase 1 - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); + if (spending + txoutput->amount < spending) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return false; + } + spending += txoutput->amount; + int co = compile_output(coin, &root, txoutput, &bin_output, !is_change); + if (!is_change) { + layoutProgress(_("Signing transaction"), progress); + } + if (co < 0) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + signing_abort(); + return false; + } else if (co == 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile output")); + signing_abort(); + return false; + } + if (coin->decred) { + // serialize Decred prefix in Phase 1 + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output( + &to, &bin_output, resp.serialized.serialized_tx.bytes); - // compute Decred hashPrefix - tx_serialize_output_hash(&ti, &bin_output); - } - // compute segwit hashOuts - tx_output_hash(&hasher_outputs, &bin_output, coin->decred); - return true; + // compute Decred hashPrefix + tx_serialize_output_hash(&ti, &bin_output); + } + // compute segwit hashOuts + tx_output_hash(&hasher_outputs, &bin_output, coin->decred); + return true; } static bool signing_check_fee(void) { - // check fees - if (spending > to_spend) { - fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); - signing_abort(); - return false; - } - uint64_t fee = to_spend - spending; - if (fee > ((uint64_t) tx_weight * coin->maxfee_kb)/4000) { - layoutFeeOverThreshold(coin, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - signing_abort(); - return false; - } - } - // last confirmation - layoutConfirmTx(coin, to_spend - change_spend, fee); - if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - signing_abort(); - return false; - } - return true; + // check fees + if (spending > to_spend) { + fsm_sendFailure(FailureType_Failure_NotEnoughFunds, _("Not enough funds")); + signing_abort(); + return false; + } + uint64_t fee = to_spend - spending; + if (fee > ((uint64_t)tx_weight * coin->maxfee_kb) / 4000) { + layoutFeeOverThreshold(coin, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_FeeOverThreshold, + false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + signing_abort(); + return false; + } + } + // last confirmation + layoutConfirmTx(coin, to_spend - change_spend, fee); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + signing_abort(); + return false; + } + return true; } static uint32_t signing_hash_type(void) { - uint32_t hash_type = SIGHASH_ALL; + uint32_t hash_type = SIGHASH_ALL; - if (coin->has_fork_id) { - hash_type |= (coin->fork_id << 8) | SIGHASH_FORKID; - } + if (coin->has_fork_id) { + hash_type |= (coin->fork_id << 8) | SIGHASH_FORKID; + } - return hash_type; + return hash_type; } static void phase1_request_next_output(void) { - if (idx1 < outputs_count - 1) { - idx1++; - send_req_3_output(); - } else { - if (coin->decred) { - // compute Decred hashPrefix - tx_hash_final(&ti, hash_prefix, false); - } - hasher_Final(&hasher_outputs, hash_outputs); - if (!signing_check_fee()) { - return; - } - // Everything was checked, now phase 2 begins and the transaction is signed. - progress_meta_step = progress_step / (inputs_count + outputs_count); - layoutProgress(_("Signing transaction"), progress); - idx1 = 0; - if (coin->decred) { - // Decred prefix serialized in Phase 1, skip Phase 2 - send_req_decred_witness(); - } else { - phase2_request_next_input(); - } - } + if (idx1 < outputs_count - 1) { + idx1++; + send_req_3_output(); + } else { + if (coin->decred) { + // compute Decred hashPrefix + tx_hash_final(&ti, hash_prefix, false); + } + hasher_Final(&hasher_outputs, hash_outputs); + if (!signing_check_fee()) { + return; + } + // Everything was checked, now phase 2 begins and the transaction is signed. + progress_meta_step = progress_step / (inputs_count + outputs_count); + layoutProgress(_("Signing transaction"), progress); + idx1 = 0; + if (coin->decred) { + // Decred prefix serialized in Phase 1, skip Phase 2 + send_req_decred_witness(); + } else { + phase2_request_next_input(); + } + } } static void signing_hash_bip143(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - Hasher hasher_preimage; - hasher_Init(&hasher_preimage, coin->curve->hasher_sign); - hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion - hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence - tx_prevout_hash(&hasher_preimage, txinput); // outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // scriptCode - hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // amount - tx_sequence_hash(&hasher_preimage, txinput); // nSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs - hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // nLockTime - hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // nHashType - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); + hasher_Update(&hasher_preimage, (const uint8_t *)&version, 4); // nVersion + hasher_Update(&hasher_preimage, hash_prevouts, 32); // hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // hashSequence + tx_prevout_hash(&hasher_preimage, txinput); // outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // amount + tx_sequence_hash(&hasher_preimage, txinput); // nSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // hashOutputs + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // nHashType + hasher_Final(&hasher_preimage, hash); } static void signing_hash_zip143(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - uint8_t personal[16]; - memcpy(personal, "ZcashSigHash", 12); - memcpy(personal + 12, &branch_id, 4); - Hasher hasher_preimage; - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); - uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered - hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); - hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId - hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs - // 6. hashJoinSplits - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // 7. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, 4); // 8. expiryHeight - hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // 9. nHashType + uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); + Hasher hasher_preimage; + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, + sizeof(personal)); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, + 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, + 4); // 7. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, + 4); // 8. expiryHeight + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, + 4); // 9. nHashType - tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 10b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // 10c. value - tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence + tx_prevout_hash(&hasher_preimage, txinput); // 10a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // 10b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // 10c. value + tx_sequence_hash(&hasher_preimage, txinput); // 10d. nSequence - hasher_Final(&hasher_preimage, hash); + hasher_Final(&hasher_preimage, hash); } static void signing_hash_zip243(const TxInputType *txinput, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - uint8_t personal[16]; - memcpy(personal, "ZcashSigHash", 12); - memcpy(personal + 12, &branch_id, 4); - Hasher hasher_preimage; - hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, sizeof(personal)); - uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered - hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); - hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, 4); // 2. nVersionGroupId - hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts - hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence - hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs - // 6. hashJoinSplits - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - // 7. hashShieldedSpends - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - // 8. hashShieldedOutputs - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); - hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, 4); // 9. nLockTime - hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, 4); // 10. expiryHeight - hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", 8); // 11. valueBalance - hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); // 12. nHashType + uint32_t hash_type = signing_hash_type(); + uint8_t personal[16]; + memcpy(personal, "ZcashSigHash", 12); + memcpy(personal + 12, &branch_id, 4); + Hasher hasher_preimage; + hasher_InitParam(&hasher_preimage, HASHER_BLAKE2B_PERSONAL, personal, + sizeof(personal)); + uint32_t ver = version | TX_OVERWINTERED; // 1. nVersion | fOverwintered + hasher_Update(&hasher_preimage, (const uint8_t *)&ver, 4); + hasher_Update(&hasher_preimage, (const uint8_t *)&version_group_id, + 4); // 2. nVersionGroupId + hasher_Update(&hasher_preimage, hash_prevouts, 32); // 3. hashPrevouts + hasher_Update(&hasher_preimage, hash_sequence, 32); // 4. hashSequence + hasher_Update(&hasher_preimage, hash_outputs, 32); // 5. hashOutputs + // 6. hashJoinSplits + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 7. hashShieldedSpends + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + // 8. hashShieldedOutputs + hasher_Update(&hasher_preimage, (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32); + hasher_Update(&hasher_preimage, (const uint8_t *)&lock_time, + 4); // 9. nLockTime + hasher_Update(&hasher_preimage, (const uint8_t *)&expiry, + 4); // 10. expiryHeight + hasher_Update(&hasher_preimage, + (const uint8_t *)"\x00\x00\x00\x00\x00\x00\x00\x00", + 8); // 11. valueBalance + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, + 4); // 12. nHashType - tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint - tx_script_hash(&hasher_preimage, txinput->script_sig.size, txinput->script_sig.bytes); // 13b. scriptCode - hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, 8); // 13c. value - tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence + tx_prevout_hash(&hasher_preimage, txinput); // 13a. outpoint + tx_script_hash(&hasher_preimage, txinput->script_sig.size, + txinput->script_sig.bytes); // 13b. scriptCode + hasher_Update(&hasher_preimage, (const uint8_t *)&txinput->amount, + 8); // 13c. value + tx_sequence_hash(&hasher_preimage, txinput); // 13d. nSequence - hasher_Final(&hasher_preimage, hash); + hasher_Final(&hasher_preimage, hash); } static void signing_hash_decred(const uint8_t *hash_witness, uint8_t *hash) { - uint32_t hash_type = signing_hash_type(); - Hasher hasher_preimage; - hasher_Init(&hasher_preimage, coin->curve->hasher_sign); - hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); - hasher_Update(&hasher_preimage, hash_prefix, 32); - hasher_Update(&hasher_preimage, hash_witness, 32); - hasher_Final(&hasher_preimage, hash); + uint32_t hash_type = signing_hash_type(); + Hasher hasher_preimage; + hasher_Init(&hasher_preimage, coin->curve->hasher_sign); + hasher_Update(&hasher_preimage, (const uint8_t *)&hash_type, 4); + hasher_Update(&hasher_preimage, hash_prefix, 32); + hasher_Update(&hasher_preimage, hash_witness, 32); + hasher_Final(&hasher_preimage, hash); } -static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key, const uint8_t *public_key, const uint8_t *hash) { - resp.serialized.has_signature_index = true; - resp.serialized.signature_index = idx1; - resp.serialized.has_signature = true; - resp.serialized.has_serialized_tx = true; - if (ecdsa_sign_digest(coin->curve->params, private_key, hash, sig, NULL, NULL) != 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); - signing_abort(); - return false; - } - resp.serialized.signature.size = ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); +static bool signing_sign_hash(TxInputType *txinput, const uint8_t *private_key, + const uint8_t *public_key, const uint8_t *hash) { + resp.serialized.has_signature_index = true; + resp.serialized.signature_index = idx1; + resp.serialized.has_signature = true; + resp.serialized.has_serialized_tx = true; + if (ecdsa_sign_digest(coin->curve->params, private_key, hash, sig, NULL, + NULL) != 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); + signing_abort(); + return false; + } + resp.serialized.signature.size = + ecdsa_sig_to_der(sig, resp.serialized.signature.bytes); - uint8_t sighash = signing_hash_type() & 0xff; - if (txinput->has_multisig) { - // fill in the signature - int pubkey_idx = cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); - if (pubkey_idx < 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Pubkey not found in multisig script")); - signing_abort(); - return false; - } - memcpy(txinput->multisig.signatures[pubkey_idx].bytes, resp.serialized.signature.bytes, resp.serialized.signature.size); - txinput->multisig.signatures[pubkey_idx].size = resp.serialized.signature.size; - txinput->script_sig.size = serialize_script_multisig(coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); - if (txinput->script_sig.size == 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize multisig script")); - signing_abort(); - return false; - } - } else { // SPENDADDRESS - txinput->script_sig.size = serialize_script_sig(resp.serialized.signature.bytes, resp.serialized.signature.size, public_key, 33, sighash, txinput->script_sig.bytes); - } - return true; + uint8_t sighash = signing_hash_type() & 0xff; + if (txinput->has_multisig) { + // fill in the signature + int pubkey_idx = + cryptoMultisigPubkeyIndex(coin, &(txinput->multisig), public_key); + if (pubkey_idx < 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Pubkey not found in multisig script")); + signing_abort(); + return false; + } + memcpy(txinput->multisig.signatures[pubkey_idx].bytes, + resp.serialized.signature.bytes, resp.serialized.signature.size); + txinput->multisig.signatures[pubkey_idx].size = + resp.serialized.signature.size; + txinput->script_sig.size = serialize_script_multisig( + coin, &(txinput->multisig), sighash, txinput->script_sig.bytes); + if (txinput->script_sig.size == 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize multisig script")); + signing_abort(); + return false; + } + } else { // SPENDADDRESS + txinput->script_sig.size = serialize_script_sig( + resp.serialized.signature.bytes, resp.serialized.signature.size, + public_key, 33, sighash, txinput->script_sig.bytes); + } + return true; } static bool signing_sign_input(void) { - uint8_t hash[32]; - hasher_Final(&hasher_check, hash); - if (memcmp(hash, hash_outputs, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return false; - } + uint8_t hash[32]; + hasher_Final(&hasher_check, hash); + if (memcmp(hash, hash_outputs, 32) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Transaction has changed during signing")); + signing_abort(); + return false; + } - uint32_t hash_type = signing_hash_type(); - hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); - tx_hash_final(&ti, hash, false); - resp.has_serialized = true; - if (!signing_sign_hash(&input, privkey, pubkey, hash)) - return false; - resp.serialized.serialized_tx.size = tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); - return true; + uint32_t hash_type = signing_hash_type(); + hasher_Update(&ti.hasher, (const uint8_t *)&hash_type, 4); + tx_hash_final(&ti, hash, false); + resp.has_serialized = true; + if (!signing_sign_hash(&input, privkey, pubkey, hash)) return false; + resp.serialized.serialized_tx.size = + tx_serialize_input(&to, &input, resp.serialized.serialized_tx.bytes); + return true; } static bool signing_sign_segwit_input(TxInputType *txinput) { - // idx1: index to sign - uint8_t hash[32]; + // idx1: index to sign + uint8_t hash[32]; - if (txinput->script_type == InputScriptType_SPENDWITNESS - || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - if (!compile_input_script_sig(txinput)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return false; - } - if (txinput->amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return false; - } - authorized_amount -= txinput->amount; + if (txinput->script_type == InputScriptType_SPENDWITNESS || + txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + if (!compile_input_script_sig(txinput)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return false; + } + if (txinput->amount > authorized_amount) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Transaction has changed during signing")); + signing_abort(); + return false; + } + authorized_amount -= txinput->amount; - signing_hash_bip143(txinput, hash); + signing_hash_bip143(txinput, hash); - resp.has_serialized = true; - if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) - return false; + resp.has_serialized = true; + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) + return false; - uint8_t sighash = signing_hash_type() & 0xff; - if (txinput->has_multisig) { - uint32_t r = 1; // skip number of items (filled in later) - resp.serialized.serialized_tx.bytes[r] = 0; r++; - int nwitnesses = 2; - for (uint32_t i = 0; i < txinput->multisig.signatures_count; i++) { - if (txinput->multisig.signatures[i].size == 0) { - continue; - } - nwitnesses++; - txinput->multisig.signatures[i].bytes[txinput->multisig.signatures[i].size] = sighash; - r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, txinput->multisig.signatures[i].bytes, resp.serialized.serialized_tx.bytes + r); - } - uint32_t script_len = compile_script_multisig(coin, &txinput->multisig, 0); - r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); - r += compile_script_multisig(coin, &txinput->multisig, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.bytes[0] = nwitnesses; - resp.serialized.serialized_tx.size = r; - } else { // single signature - uint32_t r = 0; - r += ser_length(2, resp.serialized.serialized_tx.bytes + r); - resp.serialized.signature.bytes[resp.serialized.signature.size] = sighash; - r += tx_serialize_script(resp.serialized.signature.size + 1, resp.serialized.signature.bytes, resp.serialized.serialized_tx.bytes + r); - r += tx_serialize_script(33, node.public_key, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - } else { - // empty witness - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.bytes[0] = 0; - resp.serialized.serialized_tx.size = 1; - } - // if last witness add tx footer - if (idx1 == inputs_count - 1) { - uint32_t r = resp.serialized.serialized_tx.size; - r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); - resp.serialized.serialized_tx.size = r; - } - return true; + uint8_t sighash = signing_hash_type() & 0xff; + if (txinput->has_multisig) { + uint32_t r = 1; // skip number of items (filled in later) + resp.serialized.serialized_tx.bytes[r] = 0; + r++; + int nwitnesses = 2; + for (uint32_t i = 0; i < txinput->multisig.signatures_count; i++) { + if (txinput->multisig.signatures[i].size == 0) { + continue; + } + nwitnesses++; + txinput->multisig.signatures[i] + .bytes[txinput->multisig.signatures[i].size] = sighash; + r += tx_serialize_script(txinput->multisig.signatures[i].size + 1, + txinput->multisig.signatures[i].bytes, + resp.serialized.serialized_tx.bytes + r); + } + uint32_t script_len = + compile_script_multisig(coin, &txinput->multisig, 0); + r += ser_length(script_len, resp.serialized.serialized_tx.bytes + r); + r += compile_script_multisig(coin, &txinput->multisig, + resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.bytes[0] = nwitnesses; + resp.serialized.serialized_tx.size = r; + } else { // single signature + uint32_t r = 0; + r += ser_length(2, resp.serialized.serialized_tx.bytes + r); + resp.serialized.signature.bytes[resp.serialized.signature.size] = sighash; + r += tx_serialize_script(resp.serialized.signature.size + 1, + resp.serialized.signature.bytes, + resp.serialized.serialized_tx.bytes + r); + r += tx_serialize_script(33, node.public_key, + resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + } else { + // empty witness + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.bytes[0] = 0; + resp.serialized.serialized_tx.size = 1; + } + // if last witness add tx footer + if (idx1 == inputs_count - 1) { + uint32_t r = resp.serialized.serialized_tx.size; + r += tx_serialize_footer(&to, resp.serialized.serialized_tx.bytes + r); + resp.serialized.serialized_tx.size = r; + } + return true; } static bool signing_sign_decred_input(TxInputType *txinput) { - uint8_t hash[32], hash_witness[32]; - tx_hash_final(&ti, hash_witness, false); - signing_hash_decred(hash_witness, hash); - resp.has_serialized = true; - if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) - return false; - resp.serialized.serialized_tx.size = tx_serialize_decred_witness(&to, txinput, resp.serialized.serialized_tx.bytes); - return true; + uint8_t hash[32], hash_witness[32]; + tx_hash_final(&ti, hash_witness, false); + signing_hash_decred(hash_witness, hash); + resp.has_serialized = true; + if (!signing_sign_hash(txinput, node.private_key, node.public_key, hash)) + return false; + resp.serialized.serialized_tx.size = tx_serialize_decred_witness( + &to, txinput, resp.serialized.serialized_tx.bytes); + return true; } -#define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 +#define ENABLE_SEGWIT_NONSEGWIT_MIXING 1 -void signing_txack(TransactionType *tx) -{ - if (!signing) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Signing mode")); - layoutHome(); - return; - } +void signing_txack(TransactionType *tx) { + if (!signing) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Not in Signing mode")); + layoutHome(); + return; + } - static int update_ctr = 0; - if (update_ctr++ == 20) { - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - } + static int update_ctr = 0; + if (update_ctr++ == 20) { + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + } - memzero(&resp, sizeof(TxRequest)); + memzero(&resp, sizeof(TxRequest)); - switch (signing_stage) { - case STAGE_REQUEST_1_INPUT: - signing_check_input(&tx->inputs[0]); + switch (signing_stage) { + case STAGE_REQUEST_1_INPUT: + signing_check_input(&tx->inputs[0]); - tx_weight += tx_input_weight(coin, &tx->inputs[0]); - if (coin->decred) { - tx_weight += tx_decred_witness_weight(&tx->inputs[0]); - } + tx_weight += tx_input_weight(coin, &tx->inputs[0]); + if (coin->decred) { + tx_weight += tx_decred_witness_weight(&tx->inputs[0]); + } - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - memcpy(&input, tx->inputs, sizeof(TxInputType)); + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || + tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + memcpy(&input, tx->inputs, sizeof(TxInputType)); #if !ENABLE_SEGWIT_NONSEGWIT_MIXING - // don't mix segwit and non-segwit inputs - if (idx1 > 0 && to.is_segwit == true) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); - signing_abort(); - return; - } + // don't mix segwit and non-segwit inputs + if (idx1 > 0 && to.is_segwit == true) { + fsm_sendFailure( + FailureType_Failure_DataError, + _("Mixing segwit and non-segwit inputs is not allowed")); + signing_abort(); + return; + } #endif - if (coin->force_bip143 || overwintered) { - if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Expected input with amount")); - signing_abort(); - return; - } - if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); - signing_abort(); - return; - } - to_spend += tx->inputs[0].amount; - authorized_amount += tx->inputs[0].amount; - phase1_request_next_input(); - } else { - // remember the first non-segwit input -- this is the first input - // we need to sign during phase2 - if (next_nonsegwit_input == 0xffffffff) - next_nonsegwit_input = idx1; - send_req_2_prev_meta(); - } - } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS - || tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - if (coin->decred) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred does not support Segwit")); - signing_abort(); - return; - } - if (!coin->has_segwit) { - fsm_sendFailure(FailureType_Failure_DataError, _("Segwit not enabled on this coin")); - signing_abort(); - return; - } - if (!tx->inputs[0].has_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Segwit input without amount")); - signing_abort(); - return; - } - if (to_spend + tx->inputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); - signing_abort(); - return; - } - if (!to.is_segwit) { - tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; - } + if (coin->force_bip143 || overwintered) { + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Expected input with amount")); + signing_abort(); + return; + } + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } + to_spend += tx->inputs[0].amount; + authorized_amount += tx->inputs[0].amount; + phase1_request_next_input(); + } else { + // remember the first non-segwit input -- this is the first input + // we need to sign during phase2 + if (next_nonsegwit_input == 0xffffffff) next_nonsegwit_input = idx1; + send_req_2_prev_meta(); + } + } else if (tx->inputs[0].script_type == InputScriptType_SPENDWITNESS || + tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS) { + if (coin->decred) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Decred does not support Segwit")); + signing_abort(); + return; + } + if (!coin->has_segwit) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Segwit not enabled on this coin")); + signing_abort(); + return; + } + if (!tx->inputs[0].has_amount) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Segwit input without amount")); + signing_abort(); + return; + } + if (to_spend + tx->inputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } + if (!to.is_segwit) { + tx_weight += TXSIZE_SEGWIT_OVERHEAD + to.inputs_len; + } #if !ENABLE_SEGWIT_NONSEGWIT_MIXING - // don't mix segwit and non-segwit inputs - if (idx1 == 0) { - to.is_segwit = true; - } else if (to.is_segwit == false) { - fsm_sendFailure(FailureType_Failure_DataError, _("Mixing segwit and non-segwit inputs is not allowed")); - signing_abort(); - return; - } + // don't mix segwit and non-segwit inputs + if (idx1 == 0) { + to.is_segwit = true; + } else if (to.is_segwit == false) { + fsm_sendFailure( + FailureType_Failure_DataError, + _("Mixing segwit and non-segwit inputs is not allowed")); + signing_abort(); + return; + } #else - to.is_segwit = true; + to.is_segwit = true; #endif - to_spend += tx->inputs[0].amount; - authorized_amount += tx->inputs[0].amount; - phase1_request_next_input(); - } else { - fsm_sendFailure(FailureType_Failure_DataError, _("Wrong input script type")); - signing_abort(); - return; - } - return; - case STAGE_REQUEST_2_PREV_META: - if (tx->outputs_cnt <= input.prev_index) { - fsm_sendFailure(FailureType_Failure_DataError, _("Not enough outputs in previous transaction.")); - signing_abort(); - return; - } - if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); - signing_abort(); - return; - } - tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, overwintered, version_group_id); - if (coin->decred) { - tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); - tp.is_decred = true; - } - progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); - idx2 = 0; - if (tp.inputs_len > 0) { - send_req_2_prev_input(); - } else { - tx_serialize_header_hash(&tp); - send_req_2_prev_output(); - } - return; - case STAGE_REQUEST_2_PREV_INPUT: - progress = (idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION; - if (!tx_serialize_input_hash(&tp, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); - signing_abort(); - return; - } - if (idx2 < tp.inputs_len - 1) { - idx2++; - send_req_2_prev_input(); - } else { - idx2 = 0; - send_req_2_prev_output(); - } - return; - case STAGE_REQUEST_2_PREV_OUTPUT: - progress = (idx1 * progress_step + (tp.inputs_len + idx2) * progress_meta_step) >> PROGRESS_PRECISION; - if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); - signing_abort(); - return; - } - if (idx2 == input.prev_index) { - if (to_spend + tx->bin_outputs[0].amount < to_spend) { - fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); - signing_abort(); - return; - } - if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Decred script version does not match previous output")); - signing_abort(); - return; - } - to_spend += tx->bin_outputs[0].amount; - } - if (idx2 < tp.outputs_len - 1) { - /* Check prevtx of next input */ - idx2++; - send_req_2_prev_output(); - } else if (tp.extra_data_len > 0) { // has extra data - send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); - return; - } else { - /* prevtx is done */ - signing_check_prevtx_hash(); - } - return; - case STAGE_REQUEST_2_PREV_EXTRADATA: - if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize extra data")); - signing_abort(); - return; - } - if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining - send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received)); - } else { - signing_check_prevtx_hash(); - } - return; - case STAGE_REQUEST_3_OUTPUT: - if (!signing_check_output(&tx->outputs[0])) { - return; - } - tx_weight += tx_output_weight(coin, &tx->outputs[0]); - phase1_request_next_output(); - return; - case STAGE_REQUEST_4_INPUT: - progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); - if (idx2 == 0) { - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); - hasher_Reset(&hasher_check); - } - // check prevouts and script type - tx_prevout_hash(&hasher_check, tx->inputs); - hasher_Update(&hasher_check, (const uint8_t *)&tx->inputs[0].script_type, sizeof(&tx->inputs[0].script_type)); - if (idx2 == idx1) { - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return; - } - memcpy(&input, &tx->inputs[0], sizeof(input)); - memcpy(privkey, node.private_key, 32); - memcpy(pubkey, node.public_key, 33); - } else { - if (next_nonsegwit_input == idx1 && idx2 > idx1 - && (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS - || tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG)) { - next_nonsegwit_input = idx2; - } - tx->inputs[0].script_sig.size = 0; - } - if (!tx_serialize_input_hash(&ti, tx->inputs)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); - signing_abort(); - return; - } - if (idx2 < inputs_count - 1) { - idx2++; - send_req_4_input(); - } else { - uint8_t hash[32]; - hasher_Final(&hasher_check, hash); - if (memcmp(hash, hash_check, 32) != 0) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - hasher_Reset(&hasher_check); - idx2 = 0; - send_req_4_output(); - } - return; - case STAGE_REQUEST_4_OUTPUT: - progress = 500 + ((signatures * progress_step + (inputs_count + idx2) * progress_meta_step) >> PROGRESS_PRECISION); - if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); - signing_abort(); - return; - } - // check hashOutputs - tx_output_hash(&hasher_check, &bin_output, coin->decred); - if (!tx_serialize_output_hash(&ti, &bin_output)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize output")); - signing_abort(); - return; - } - if (idx2 < outputs_count - 1) { - idx2++; - send_req_4_output(); - } else { - if (!signing_sign_input()) { - return; - } - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - phase2_request_next_input(); - } else { - idx1 = 0; - send_req_5_output(); - } - } - return; + to_spend += tx->inputs[0].amount; + authorized_amount += tx->inputs[0].amount; + phase1_request_next_input(); + } else { + fsm_sendFailure(FailureType_Failure_DataError, + _("Wrong input script type")); + signing_abort(); + return; + } + return; + case STAGE_REQUEST_2_PREV_META: + if (tx->outputs_cnt <= input.prev_index) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Not enough outputs in previous transaction.")); + signing_abort(); + return; + } + if (tx->inputs_cnt + tx->outputs_cnt < tx->inputs_cnt) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } + tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, + tx->expiry, tx->extra_data_len, coin->curve->hasher_sign, + overwintered, version_group_id); + if (coin->decred) { + tp.version |= (DECRED_SERIALIZE_NO_WITNESS << 16); + tp.is_decred = true; + } + progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); + idx2 = 0; + if (tp.inputs_len > 0) { + send_req_2_prev_input(); + } else { + tx_serialize_header_hash(&tp); + send_req_2_prev_output(); + } + return; + case STAGE_REQUEST_2_PREV_INPUT: + progress = (idx1 * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION; + if (!tx_serialize_input_hash(&tp, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize input")); + signing_abort(); + return; + } + if (idx2 < tp.inputs_len - 1) { + idx2++; + send_req_2_prev_input(); + } else { + idx2 = 0; + send_req_2_prev_output(); + } + return; + case STAGE_REQUEST_2_PREV_OUTPUT: + progress = (idx1 * progress_step + + (tp.inputs_len + idx2) * progress_meta_step) >> + PROGRESS_PRECISION; + if (!tx_serialize_output_hash(&tp, tx->bin_outputs)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize output")); + signing_abort(); + return; + } + if (idx2 == input.prev_index) { + if (to_spend + tx->bin_outputs[0].amount < to_spend) { + fsm_sendFailure(FailureType_Failure_DataError, _("Value overflow")); + signing_abort(); + return; + } + if (coin->decred && tx->bin_outputs[0].decred_script_version > 0) { + fsm_sendFailure( + FailureType_Failure_DataError, + _("Decred script version does not match previous output")); + signing_abort(); + return; + } + to_spend += tx->bin_outputs[0].amount; + } + if (idx2 < tp.outputs_len - 1) { + /* Check prevtx of next input */ + idx2++; + send_req_2_prev_output(); + } else if (tp.extra_data_len > 0) { // has extra data + send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len)); + return; + } else { + /* prevtx is done */ + signing_check_prevtx_hash(); + } + return; + case STAGE_REQUEST_2_PREV_EXTRADATA: + if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, + tx->extra_data.size)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize extra data")); + signing_abort(); + return; + } + if (tp.extra_data_received < + tp.extra_data_len) { // still some data remanining + send_req_2_prev_extradata( + tp.extra_data_received, + MIN(1024, tp.extra_data_len - tp.extra_data_received)); + } else { + signing_check_prevtx_hash(); + } + return; + case STAGE_REQUEST_3_OUTPUT: + if (!signing_check_output(&tx->outputs[0])) { + return; + } + tx_weight += tx_output_weight(coin, &tx->outputs[0]); + phase1_request_next_output(); + return; + case STAGE_REQUEST_4_INPUT: + progress = + 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION); + if (idx2 == 0) { + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + coin->curve->hasher_sign, overwintered, version_group_id); + hasher_Reset(&hasher_check); + } + // check prevouts and script type + tx_prevout_hash(&hasher_check, tx->inputs); + hasher_Update(&hasher_check, (const uint8_t *)&tx->inputs[0].script_type, + sizeof(&tx->inputs[0].script_type)); + if (idx2 == idx1) { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return; + } + memcpy(&input, &tx->inputs[0], sizeof(input)); + memcpy(privkey, node.private_key, 32); + memcpy(pubkey, node.public_key, 33); + } else { + if (next_nonsegwit_input == idx1 && idx2 > idx1 && + (tx->inputs[0].script_type == InputScriptType_SPENDADDRESS || + tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG)) { + next_nonsegwit_input = idx2; + } + tx->inputs[0].script_sig.size = 0; + } + if (!tx_serialize_input_hash(&ti, tx->inputs)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize input")); + signing_abort(); + return; + } + if (idx2 < inputs_count - 1) { + idx2++; + send_req_4_input(); + } else { + uint8_t hash[32]; + hasher_Final(&hasher_check, hash); + if (memcmp(hash, hash_check, 32) != 0) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + hasher_Reset(&hasher_check); + idx2 = 0; + send_req_4_output(); + } + return; + case STAGE_REQUEST_4_OUTPUT: + progress = 500 + ((signatures * progress_step + + (inputs_count + idx2) * progress_meta_step) >> + PROGRESS_PRECISION); + if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile output")); + signing_abort(); + return; + } + // check hashOutputs + tx_output_hash(&hasher_check, &bin_output, coin->decred); + if (!tx_serialize_output_hash(&ti, &bin_output)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize output")); + signing_abort(); + return; + } + if (idx2 < outputs_count - 1) { + idx2++; + send_req_4_output(); + } else { + if (!signing_sign_input()) { + return; + } + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + phase2_request_next_input(); + } else { + idx1 = 0; + send_req_5_output(); + } + } + return; - case STAGE_REQUEST_SEGWIT_INPUT: - resp.has_serialized = true; - resp.serialized.has_signature_index = false; - resp.serialized.has_signature = false; - resp.serialized.has_serialized_tx = true; - if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG - || tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { - if (!(coin->force_bip143 || overwintered)) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return; - } - if (tx->inputs[0].amount > authorized_amount) { - fsm_sendFailure(FailureType_Failure_DataError, _("Transaction has changed during signing")); - signing_abort(); - return; - } - authorized_amount -= tx->inputs[0].amount; + case STAGE_REQUEST_SEGWIT_INPUT: + resp.has_serialized = true; + resp.serialized.has_signature_index = false; + resp.serialized.has_signature = false; + resp.serialized.has_serialized_tx = true; + if (tx->inputs[0].script_type == InputScriptType_SPENDMULTISIG || + tx->inputs[0].script_type == InputScriptType_SPENDADDRESS) { + if (!(coin->force_bip143 || overwintered)) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return; + } + if (tx->inputs[0].amount > authorized_amount) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Transaction has changed during signing")); + signing_abort(); + return; + } + authorized_amount -= tx->inputs[0].amount; - uint8_t hash[32]; - if (overwintered) { - switch (version) { - case 3: - signing_hash_zip143(&tx->inputs[0], hash); - break; - case 4: - signing_hash_zip243(&tx->inputs[0], hash); - break; - default: - fsm_sendFailure(FailureType_Failure_DataError, _("Unsupported version for overwintered transaction")); - signing_abort(); - return; - } - } else { - signing_hash_bip143(&tx->inputs[0], hash); - } - if (!signing_sign_hash(&tx->inputs[0], node.private_key, node.public_key, hash)) - return; - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS - && !tx->inputs[0].has_multisig) { - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return; - } - // fixup normal p2pkh script into witness 0 p2wpkh script for p2sh - // we convert 76 A9 14 88 AC to 16 00 14 - // P2SH input pushes witness 0 script - tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes. - tx->inputs[0].script_sig.bytes[0] = 0x16; // push 22 bytes; replaces OP_DUP - tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script ; replaces OP_HASH160 - // digest is already in right place. - } else if (tx->inputs[0].script_type == InputScriptType_SPENDP2SHWITNESS) { - // Prepare P2SH witness script. - tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: - tx->inputs[0].script_sig.bytes[0] = 0x22; // push 34 bytes (full witness script) - tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script - tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) - // compute digest of multisig script - if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, tx->inputs[0].script_sig.bytes + 3)) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return; - } - } else { - // direct witness scripts require zero scriptSig - tx->inputs[0].script_sig.size = 0; - } - resp.serialized.serialized_tx.size = tx_serialize_input(&to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); - if (idx1 < inputs_count - 1) { - idx1++; - phase2_request_next_input(); - } else { - idx1 = 0; - send_req_5_output(); - } - return; + uint8_t hash[32]; + if (overwintered) { + switch (version) { + case 3: + signing_hash_zip143(&tx->inputs[0], hash); + break; + case 4: + signing_hash_zip243(&tx->inputs[0], hash); + break; + default: + fsm_sendFailure( + FailureType_Failure_DataError, + _("Unsupported version for overwintered transaction")); + signing_abort(); + return; + } + } else { + signing_hash_bip143(&tx->inputs[0], hash); + } + if (!signing_sign_hash(&tx->inputs[0], node.private_key, + node.public_key, hash)) + return; + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + } else if (tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS && + !tx->inputs[0].has_multisig) { + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return; + } + // fixup normal p2pkh script into witness 0 p2wpkh script for p2sh + // we convert 76 A9 14 88 AC to 16 00 14 + // P2SH input pushes witness 0 script + tx->inputs[0].script_sig.size = 0x17; // drops last 2 bytes. + tx->inputs[0].script_sig.bytes[0] = + 0x16; // push 22 bytes; replaces OP_DUP + tx->inputs[0].script_sig.bytes[1] = + 0x00; // witness 0 script ; replaces OP_HASH160 + // digest is already in right place. + } else if (tx->inputs[0].script_type == + InputScriptType_SPENDP2SHWITNESS) { + // Prepare P2SH witness script. + tx->inputs[0].script_sig.size = 0x23; // 35 bytes long: + tx->inputs[0].script_sig.bytes[0] = + 0x22; // push 34 bytes (full witness script) + tx->inputs[0].script_sig.bytes[1] = 0x00; // witness 0 script + tx->inputs[0].script_sig.bytes[2] = 0x20; // push 32 bytes (digest) + // compute digest of multisig script + if (!compile_script_multisig_hash(coin, &tx->inputs[0].multisig, + tx->inputs[0].script_sig.bytes + 3)) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return; + } + } else { + // direct witness scripts require zero scriptSig + tx->inputs[0].script_sig.size = 0; + } + resp.serialized.serialized_tx.size = tx_serialize_input( + &to, &tx->inputs[0], resp.serialized.serialized_tx.bytes); + if (idx1 < inputs_count - 1) { + idx1++; + phase2_request_next_input(); + } else { + idx1 = 0; + send_req_5_output(); + } + return; - case STAGE_REQUEST_5_OUTPUT: - if (compile_output(coin, &root, tx->outputs, &bin_output,false) <= 0) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile output")); - signing_abort(); - return; - } - resp.has_serialized = true; - resp.serialized.has_serialized_tx = true; - resp.serialized.serialized_tx.size = tx_serialize_output(&to, &bin_output, resp.serialized.serialized_tx.bytes); - if (idx1 < outputs_count - 1) { - idx1++; - send_req_5_output(); - } else if (to.is_segwit) { - idx1 = 0; - send_req_segwit_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; + case STAGE_REQUEST_5_OUTPUT: + if (compile_output(coin, &root, tx->outputs, &bin_output, false) <= 0) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile output")); + signing_abort(); + return; + } + resp.has_serialized = true; + resp.serialized.has_serialized_tx = true; + resp.serialized.serialized_tx.size = tx_serialize_output( + &to, &bin_output, resp.serialized.serialized_tx.bytes); + if (idx1 < outputs_count - 1) { + idx1++; + send_req_5_output(); + } else if (to.is_segwit) { + idx1 = 0; + send_req_segwit_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; - case STAGE_REQUEST_SEGWIT_WITNESS: - if (!signing_sign_segwit_input(&tx->inputs[0])) { - return; - } - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - send_req_segwit_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; + case STAGE_REQUEST_SEGWIT_WITNESS: + if (!signing_sign_segwit_input(&tx->inputs[0])) { + return; + } + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_segwit_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; - case STAGE_REQUEST_DECRED_WITNESS: - progress = 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); - if (idx1 == 0) { - // witness - tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); - to.is_decred = true; - } + case STAGE_REQUEST_DECRED_WITNESS: + progress = + 500 + ((signatures * progress_step + idx2 * progress_meta_step) >> + PROGRESS_PRECISION); + if (idx1 == 0) { + // witness + tx_init(&to, inputs_count, outputs_count, version, lock_time, expiry, 0, + coin->curve->hasher_sign, overwintered, version_group_id); + to.is_decred = true; + } - // witness hash - tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, coin->curve->hasher_sign, overwintered, version_group_id); - ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); - ti.is_decred = true; - if (!compile_input_script_sig(&tx->inputs[0])) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to compile input")); - signing_abort(); - return; - } + // witness hash + tx_init(&ti, inputs_count, outputs_count, version, lock_time, expiry, 0, + coin->curve->hasher_sign, overwintered, version_group_id); + ti.version |= (DECRED_SERIALIZE_WITNESS_SIGNING << 16); + ti.is_decred = true; + if (!compile_input_script_sig(&tx->inputs[0])) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to compile input")); + signing_abort(); + return; + } - for (idx2 = 0; idx2 < inputs_count; idx2++) { - uint32_t r; - if (idx2 == idx1) { - r = tx_serialize_decred_witness_hash(&ti, &tx->inputs[0]); - } else { - r = tx_serialize_decred_witness_hash(&ti, NULL); - } + for (idx2 = 0; idx2 < inputs_count; idx2++) { + uint32_t r; + if (idx2 == idx1) { + r = tx_serialize_decred_witness_hash(&ti, &tx->inputs[0]); + } else { + r = tx_serialize_decred_witness_hash(&ti, NULL); + } - if (!r) { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to serialize input")); - signing_abort(); - return; - } - } + if (!r) { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Failed to serialize input")); + signing_abort(); + return; + } + } - if (!signing_sign_decred_input(&tx->inputs[0])) { - return; - } - // since this took a longer time, update progress - signatures++; - progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); - layoutProgress(_("Signing transaction"), progress); - update_ctr = 0; - if (idx1 < inputs_count - 1) { - idx1++; - send_req_decred_witness(); - } else { - send_req_finished(); - signing_abort(); - } - return; - } - - fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); - signing_abort(); + if (!signing_sign_decred_input(&tx->inputs[0])) { + return; + } + // since this took a longer time, update progress + signatures++; + progress = 500 + ((signatures * progress_step) >> PROGRESS_PRECISION); + layoutProgress(_("Signing transaction"), progress); + update_ctr = 0; + if (idx1 < inputs_count - 1) { + idx1++; + send_req_decred_witness(); + } else { + send_req_finished(); + signing_abort(); + } + return; + } + + fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing error")); + signing_abort(); } -void signing_abort(void) -{ - if (signing) { - layoutHome(); - signing = false; - } - memzero(&root, sizeof(root)); - memzero(&node, sizeof(node)); +void signing_abort(void) { + if (signing) { + layoutHome(); + signing = false; + } + memzero(&root, sizeof(root)); + memzero(&node, sizeof(node)); } diff --git a/firmware/signing.h b/firmware/signing.h index d27ebf7cf1..af74d4a6b0 100644 --- a/firmware/signing.h +++ b/firmware/signing.h @@ -20,14 +20,15 @@ #ifndef __SIGNING_H__ #define __SIGNING_H__ -#include #include +#include #include "bip32.h" #include "coins.h" #include "hasher.h" #include "messages-bitcoin.pb.h" -void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root); +void signing_init(const SignTx *msg, const CoinInfo *_coin, + const HDNode *_root); void signing_abort(void); void signing_txack(TransactionType *tx); diff --git a/firmware/stellar.c b/firmware/stellar.c index 5ee64d8574..d4f46e4e84 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -19,32 +19,34 @@ // Stellar signing workflow: // -// 1. Client sends a StellarSignTx method to the device with transaction header information -// 2. Device confirms transaction details with the user and requests first operation +// 1. Client sends a StellarSignTx method to the device with transaction header +// information +// 2. Device confirms transaction details with the user and requests first +// operation // 3. Client sends protobuf message with details about the operation to sign // 4. Device confirms operation with user -// 5a. If there are more operations in the transaction, device responds with StellarTxOpRequest. Go to 3 -// 5b. If the operation is the last one, device responds with StellarSignedTx +// 5a. If there are more operations in the transaction, device responds with +// StellarTxOpRequest. Go to 3 5b. If the operation is the last one, device +// responds with StellarSignedTx +#include "stellar.h" #include #include +#include "base32.h" +#include "bignum.h" +#include "bip32.h" +#include "config.h" +#include "crypto.h" +#include "fonts.h" +#include "fsm.h" +#include "gettext.h" +#include "layout2.h" +#include "memzero.h" #include "messages.h" #include "messages.pb.h" -#include "stellar.h" -#include "bip32.h" -#include "crypto.h" -#include "layout2.h" -#include "gettext.h" -#include "bignum.h" #include "oled.h" -#include "base32.h" -#include "config.h" -#include "fsm.h" #include "protect.h" #include "util.h" -#include "layout2.h" -#include "fonts.h" -#include "memzero.h" static bool stellar_signing = false; static StellarTransaction stellar_activeTx; @@ -52,1216 +54,1141 @@ static StellarTransaction stellar_activeTx; /* * Starts the signing process and parses the transaction header */ -bool stellar_signingInit(const StellarSignTx *msg) -{ - memzero(&stellar_activeTx, sizeof(StellarTransaction)); - stellar_signing = true; - // Initialize signing context - sha256_Init(&(stellar_activeTx.sha256_ctx)); +bool stellar_signingInit(const StellarSignTx *msg) { + memzero(&stellar_activeTx, sizeof(StellarTransaction)); + stellar_signing = true; + // Initialize signing context + sha256_Init(&(stellar_activeTx.sha256_ctx)); - // Calculate sha256 for network passphrase - // max length defined in messages.options - uint8_t network_hash[32]; - sha256_Raw((uint8_t *)msg->network_passphrase, strnlen(msg->network_passphrase, 1024), network_hash); + // Calculate sha256 for network passphrase + // max length defined in messages.options + uint8_t network_hash[32]; + sha256_Raw((uint8_t *)msg->network_passphrase, + strnlen(msg->network_passphrase, 1024), network_hash); - uint8_t tx_type_bytes[4] = { 0x00, 0x00, 0x00, 0x02 }; + uint8_t tx_type_bytes[4] = {0x00, 0x00, 0x00, 0x02}; - // Copy some data into the active tx - stellar_activeTx.num_operations = msg->num_operations; + // Copy some data into the active tx + stellar_activeTx.num_operations = msg->num_operations; - // Start building what will be signed: - // sha256 of: - // sha256(network passphrase) - // 4-byte unsigned big-endian int type constant (2 for tx) - // remaining bytes are operations added in subsequent messages - stellar_hashupdate_bytes(network_hash, sizeof(network_hash)); - stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); + // Start building what will be signed: + // sha256 of: + // sha256(network passphrase) + // 4-byte unsigned big-endian int type constant (2 for tx) + // remaining bytes are operations added in subsequent messages + stellar_hashupdate_bytes(network_hash, sizeof(network_hash)); + stellar_hashupdate_bytes(tx_type_bytes, sizeof(tx_type_bytes)); - // Public key comes from deriving the specified account path - const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); - if (!node) { - return false; - } - memcpy(&(stellar_activeTx.signing_pubkey), node->public_key + 1, sizeof(stellar_activeTx.signing_pubkey)); + // Public key comes from deriving the specified account path + const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + if (!node) { + return false; + } + memcpy(&(stellar_activeTx.signing_pubkey), node->public_key + 1, + sizeof(stellar_activeTx.signing_pubkey)); - stellar_activeTx.address_n_count = msg->address_n_count; - // todo: fix sizeof check - memcpy(&(stellar_activeTx.address_n), &(msg->address_n), sizeof(stellar_activeTx.address_n)); + stellar_activeTx.address_n_count = msg->address_n_count; + // todo: fix sizeof check + memcpy(&(stellar_activeTx.address_n), &(msg->address_n), + sizeof(stellar_activeTx.address_n)); - // Hash: public key - stellar_hashupdate_address(node->public_key + 1); + // Hash: public key + stellar_hashupdate_address(node->public_key + 1); - // Hash: fee - stellar_hashupdate_uint32(msg->fee); + // Hash: fee + stellar_hashupdate_uint32(msg->fee); - // Hash: sequence number - stellar_hashupdate_uint64(msg->sequence_number); + // Hash: sequence number + stellar_hashupdate_uint64(msg->sequence_number); - // Timebounds are only present if timebounds_start or timebounds_end is non-zero - uint8_t has_timebounds = (msg->timebounds_start > 0 || msg->timebounds_end > 0); - if (has_timebounds) { - // Hash: the "has timebounds?" boolean - stellar_hashupdate_bool(true); + // Timebounds are only present if timebounds_start or timebounds_end is + // non-zero + uint8_t has_timebounds = + (msg->timebounds_start > 0 || msg->timebounds_end > 0); + if (has_timebounds) { + // Hash: the "has timebounds?" boolean + stellar_hashupdate_bool(true); - // Timebounds are sent as uint32s since that's all we can display, but they must be hashed as - // 64-bit values - stellar_hashupdate_uint32(0); - stellar_hashupdate_uint32(msg->timebounds_start); - - stellar_hashupdate_uint32(0); - stellar_hashupdate_uint32(msg->timebounds_end); - } - // No timebounds, hash a false boolean - else { - stellar_hashupdate_bool(false); - } - - // Hash: memo - stellar_hashupdate_uint32(msg->memo_type); - switch (msg->memo_type) { - // None, nothing else to do - case 0: - break; - // Text: 4 bytes (size) + up to 28 bytes - case 1: - stellar_hashupdate_string((unsigned char*)&(msg->memo_text), strnlen(msg->memo_text, 28)); - break; - // ID (8 bytes, uint64) - case 2: - stellar_hashupdate_uint64(msg->memo_id); - break; - // Hash and return are the same data structure (32 byte tx hash) - case 3: - case 4: - stellar_hashupdate_bytes(msg->memo_hash.bytes, msg->memo_hash.size); - break; - default: - break; - } - - // Hash: number of operations - stellar_hashupdate_uint32(msg->num_operations); - - // Determine what type of network this transaction is for - if (strncmp("Public Global Stellar Network ; September 2015", msg->network_passphrase, 1024) == 0) { - stellar_activeTx.network_type = 1; - } - else if (strncmp("Test SDF Network ; September 2015", msg->network_passphrase, 1024) == 0) { - stellar_activeTx.network_type = 2; - } - else { - stellar_activeTx.network_type = 3; - } - - return true; -} - -bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account) -{ - if (!has_source_account) { - stellar_hashupdate_bool(false); - return true; - } - - // Convert account string to public key bytes - uint8_t bytes[32]; - if (!stellar_getAddressBytes(str_account, bytes)) { - return false; - } - - const char **str_addr_rows = stellar_lineBreakAddress(bytes); - - stellar_layoutTransactionDialog( - _("Op src account OK?"), - NULL, - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // Hash: source account - stellar_hashupdate_address(bytes); - - return true; -} - -bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) -{ - if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } - - // Hash: operation type + // Timebounds are sent as uint32s since that's all we can display, but they + // must be hashed as 64-bit values stellar_hashupdate_uint32(0); + stellar_hashupdate_uint32(msg->timebounds_start); - // Validate new account and convert to bytes - uint8_t new_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->new_account, new_account_bytes)) { - stellar_signingAbort(_("Invalid new account address")); - return false; - } + stellar_hashupdate_uint32(0); + stellar_hashupdate_uint32(msg->timebounds_end); + } + // No timebounds, hash a false boolean + else { + stellar_hashupdate_bool(false); + } - const char **str_addr_rows = stellar_lineBreakAddress(new_account_bytes); + // Hash: memo + stellar_hashupdate_uint32(msg->memo_type); + switch (msg->memo_type) { + // None, nothing else to do + case 0: + break; + // Text: 4 bytes (size) + up to 28 bytes + case 1: + stellar_hashupdate_string((unsigned char *)&(msg->memo_text), + strnlen(msg->memo_text, 28)); + break; + // ID (8 bytes, uint64) + case 2: + stellar_hashupdate_uint64(msg->memo_id); + break; + // Hash and return are the same data structure (32 byte tx hash) + case 3: + case 4: + stellar_hashupdate_bytes(msg->memo_hash.bytes, msg->memo_hash.size); + break; + default: + break; + } - // Amount being funded - char str_amount_line[32]; - char str_amount[32]; - stellar_format_stroops(msg->starting_balance, str_amount, sizeof(str_amount)); + // Hash: number of operations + stellar_hashupdate_uint32(msg->num_operations); - strlcpy(str_amount_line, _("With "), sizeof(str_amount_line)); - strlcat(str_amount_line, str_amount, sizeof(str_amount_line)); - strlcat(str_amount_line, _(" XLM"), sizeof(str_amount_line)); + // Determine what type of network this transaction is for + if (strncmp("Public Global Stellar Network ; September 2015", + msg->network_passphrase, 1024) == 0) { + stellar_activeTx.network_type = 1; + } else if (strncmp("Test SDF Network ; September 2015", + msg->network_passphrase, 1024) == 0) { + stellar_activeTx.network_type = 2; + } else { + stellar_activeTx.network_type = 3; + } - stellar_layoutTransactionDialog( - _("Create account: "), - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2], - str_amount_line - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // Hash: address - stellar_hashupdate_address(new_account_bytes); - // Hash: starting amount - stellar_hashupdate_uint64(msg->starting_balance); - - stellar_activeTx.confirmed_operations++; - return true; + return true; } -bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) -{ - if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } - - // Hash: operation type - stellar_hashupdate_uint32(1); - - // Validate destination account and convert to bytes - uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { - stellar_signingAbort(_("Invalid destination account")); - return false; - } - - const char **str_addr_rows = stellar_lineBreakAddress(destination_account_bytes); - - // To: G... - char str_to[32]; - strlcpy(str_to, _("To: "), sizeof(str_to)); - strlcat(str_to, str_addr_rows[0], sizeof(str_to)); - - char str_asset_row[32]; - memzero(str_asset_row, sizeof(str_asset_row)); - stellar_format_asset(&(msg->asset), str_asset_row, sizeof(str_asset_row)); - - char str_pay_amount[32]; - char str_amount[32]; - stellar_format_stroops(msg->amount, str_amount, sizeof(str_amount)); - - strlcpy(str_pay_amount, _("Pay "), sizeof(str_pay_amount)); - strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); - - stellar_layoutTransactionDialog( - str_pay_amount, - str_asset_row, - str_to, - str_addr_rows[1], - str_addr_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // Hash destination - stellar_hashupdate_address(destination_account_bytes); - // asset - stellar_hashupdate_asset(&(msg->asset)); - // amount (even though amount is signed it doesn't matter for hashing) - stellar_hashupdate_uint64(msg->amount); - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; +bool stellar_confirmSourceAccount(bool has_source_account, + const char *str_account) { + if (!has_source_account) { + stellar_hashupdate_bool(false); return true; + } + + // Convert account string to public key bytes + uint8_t bytes[32]; + if (!stellar_getAddressBytes(str_account, bytes)) { + return false; + } + + const char **str_addr_rows = stellar_lineBreakAddress(bytes); + + stellar_layoutTransactionDialog(_("Op src account OK?"), NULL, + str_addr_rows[0], str_addr_rows[1], + str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash: source account + stellar_hashupdate_address(bytes); + + return true; } -bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } - // Hash: operation type - stellar_hashupdate_uint32(2); + // Hash: operation type + stellar_hashupdate_uint32(0); - // Validate destination account and convert to bytes - uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { - stellar_signingAbort(_("Invalid destination account")); - return false; - } - const char **str_dest_rows = stellar_lineBreakAddress(destination_account_bytes); + // Validate new account and convert to bytes + uint8_t new_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->new_account, new_account_bytes)) { + stellar_signingAbort(_("Invalid new account address")); + return false; + } - // To: G... - char str_to[32]; - strlcpy(str_to, _("To: "), sizeof(str_to)); - strlcat(str_to, str_dest_rows[0], sizeof(str_to)); + const char **str_addr_rows = stellar_lineBreakAddress(new_account_bytes); - char str_send_asset[32]; - char str_dest_asset[32]; - stellar_format_asset(&(msg->send_asset), str_send_asset, sizeof(str_send_asset)); - stellar_format_asset(&(msg->destination_asset), str_dest_asset, sizeof(str_dest_asset)); + // Amount being funded + char str_amount_line[32]; + char str_amount[32]; + stellar_format_stroops(msg->starting_balance, str_amount, sizeof(str_amount)); - char str_pay_amount[32]; - char str_amount[32]; - stellar_format_stroops(msg->destination_amount, str_amount, sizeof(str_amount)); + strlcpy(str_amount_line, _("With "), sizeof(str_amount_line)); + strlcat(str_amount_line, str_amount, sizeof(str_amount_line)); + strlcat(str_amount_line, _(" XLM"), sizeof(str_amount_line)); - strlcpy(str_pay_amount, _("Path Pay "), sizeof(str_pay_amount)); - strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); + stellar_layoutTransactionDialog(_("Create account: "), str_addr_rows[0], + str_addr_rows[1], str_addr_rows[2], + str_amount_line); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } - // Confirm what the receiver will get - /* - Path Pay 100 - JPY (G1234ABCDEF) - To: G.... - .... - .... - */ - stellar_layoutTransactionDialog( - str_pay_amount, - str_dest_asset, - str_to, - str_dest_rows[1], - str_dest_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } + // Hash: address + stellar_hashupdate_address(new_account_bytes); + // Hash: starting amount + stellar_hashupdate_uint64(msg->starting_balance); - // Confirm what the sender is using to pay - char str_source_amount[32]; - char str_source_number[32]; - stellar_format_stroops(msg->send_max, str_source_number, sizeof(str_source_number)); - - strlcpy(str_source_amount, _("Pay Using "), sizeof(str_source_amount)); - strlcat(str_source_amount, str_source_number, sizeof(str_source_amount)); - - stellar_layoutTransactionDialog( - str_source_amount, - str_send_asset, - NULL, - _("This is the amount debited"), - _("from your account.") - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - // Note: no confirmation for intermediate steps since they don't impact the user - - // Hash send asset - stellar_hashupdate_asset(&(msg->send_asset)); - // send max (signed vs. unsigned doesn't matter wrt hashing) - stellar_hashupdate_uint64(msg->send_max); - // destination account - stellar_hashupdate_address(destination_account_bytes); - // destination asset - stellar_hashupdate_asset(&(msg->destination_asset)); - // destination amount - stellar_hashupdate_uint64(msg->destination_amount); - - // paths are stored as an array so hash the number of elements as a uint32 - stellar_hashupdate_uint32(msg->paths_count); - for (uint8_t i=0; i < msg->paths_count; i++) { - stellar_hashupdate_asset(&(msg->paths[i])); - } - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + stellar_activeTx.confirmed_operations++; + return true; } -bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmPaymentOp(const StellarPaymentOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } - // Hash: operation type - stellar_hashupdate_uint32(3); + // Hash: operation type + stellar_hashupdate_uint32(1); - // New Offer / Delete #123 / Update #123 - char str_offer[32]; - if (msg->offer_id == 0) { - strlcpy(str_offer, _("New Offer"), sizeof(str_offer)); - } - else { - char str_offer_id[20]; - stellar_format_uint64(msg->offer_id, str_offer_id, sizeof(str_offer_id)); + // Validate destination account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, + destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } - if (msg->amount == 0) { - strlcpy(str_offer, _("Delete #"), sizeof(str_offer)); - } - else { - strlcpy(str_offer, _("Update #"), sizeof(str_offer)); - } + const char **str_addr_rows = + stellar_lineBreakAddress(destination_account_bytes); - strlcat(str_offer, str_offer_id, sizeof(str_offer)); - } + // To: G... + char str_to[32]; + strlcpy(str_to, _("To: "), sizeof(str_to)); + strlcat(str_to, str_addr_rows[0], sizeof(str_to)); - char str_selling[32]; - char str_sell_amount[32]; - char str_selling_asset[32]; + char str_asset_row[32]; + memzero(str_asset_row, sizeof(str_asset_row)); + stellar_format_asset(&(msg->asset), str_asset_row, sizeof(str_asset_row)); - stellar_format_asset(&(msg->selling_asset), str_selling_asset, sizeof(str_selling_asset)); - stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); + char str_pay_amount[32]; + char str_amount[32]; + stellar_format_stroops(msg->amount, str_amount, sizeof(str_amount)); - /* - Sell 200 - XLM (Native Asset) - */ - strlcpy(str_selling, _("Sell "), sizeof(str_selling)); - strlcat(str_selling, str_sell_amount, sizeof(str_selling)); + strlcpy(str_pay_amount, _("Pay "), sizeof(str_pay_amount)); + strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); - char str_buying[32]; - char str_buying_asset[32]; - char str_price[32]; + stellar_layoutTransactionDialog(str_pay_amount, str_asset_row, str_to, + str_addr_rows[1], str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } - stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); - stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); + // Hash destination + stellar_hashupdate_address(destination_account_bytes); + // asset + stellar_hashupdate_asset(&(msg->asset)); + // amount (even though amount is signed it doesn't matter for hashing) + stellar_hashupdate_uint64(msg->amount); - /* - For 0.675952 Per - USD (G12345678) - */ - strlcpy(str_buying, _("For "), sizeof(str_buying)); - strlcat(str_buying, str_price, sizeof(str_buying)); - strlcat(str_buying, _(" Per"), sizeof(str_buying)); - - stellar_layoutTransactionDialog( - str_offer, - str_selling, - str_selling_asset, - str_buying, - str_buying_asset - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // Hash selling asset - stellar_hashupdate_asset(&(msg->selling_asset)); - // buying asset - stellar_hashupdate_asset(&(msg->buying_asset)); - // amount to sell (signed vs. unsigned doesn't matter wrt hashing) - stellar_hashupdate_uint64(msg->amount); - // numerator - stellar_hashupdate_uint32(msg->price_n); - // denominator - stellar_hashupdate_uint32(msg->price_d); - // offer ID - stellar_hashupdate_uint64(msg->offer_id); - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; } -bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } - // Hash: operation type - stellar_hashupdate_uint32(4); + // Hash: operation type + stellar_hashupdate_uint32(2); + + // Validate destination account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, + destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + const char **str_dest_rows = + stellar_lineBreakAddress(destination_account_bytes); + + // To: G... + char str_to[32]; + strlcpy(str_to, _("To: "), sizeof(str_to)); + strlcat(str_to, str_dest_rows[0], sizeof(str_to)); + + char str_send_asset[32]; + char str_dest_asset[32]; + stellar_format_asset(&(msg->send_asset), str_send_asset, + sizeof(str_send_asset)); + stellar_format_asset(&(msg->destination_asset), str_dest_asset, + sizeof(str_dest_asset)); + + char str_pay_amount[32]; + char str_amount[32]; + stellar_format_stroops(msg->destination_amount, str_amount, + sizeof(str_amount)); + + strlcpy(str_pay_amount, _("Path Pay "), sizeof(str_pay_amount)); + strlcat(str_pay_amount, str_amount, sizeof(str_pay_amount)); + + // Confirm what the receiver will get + /* + Path Pay 100 + JPY (G1234ABCDEF) + To: G.... + .... + .... + */ + stellar_layoutTransactionDialog(str_pay_amount, str_dest_asset, str_to, + str_dest_rows[1], str_dest_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Confirm what the sender is using to pay + char str_source_amount[32]; + char str_source_number[32]; + stellar_format_stroops(msg->send_max, str_source_number, + sizeof(str_source_number)); + + strlcpy(str_source_amount, _("Pay Using "), sizeof(str_source_amount)); + strlcat(str_source_amount, str_source_number, sizeof(str_source_amount)); + + stellar_layoutTransactionDialog(str_source_amount, str_send_asset, NULL, + _("This is the amount debited"), + _("from your account.")); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + // Note: no confirmation for intermediate steps since they don't impact the + // user + + // Hash send asset + stellar_hashupdate_asset(&(msg->send_asset)); + // send max (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->send_max); + // destination account + stellar_hashupdate_address(destination_account_bytes); + // destination asset + stellar_hashupdate_asset(&(msg->destination_asset)); + // destination amount + stellar_hashupdate_uint64(msg->destination_amount); + + // paths are stored as an array so hash the number of elements as a uint32 + stellar_hashupdate_uint32(msg->paths_count); + for (uint8_t i = 0; i < msg->paths_count; i++) { + stellar_hashupdate_asset(&(msg->paths[i])); + } + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; +} + +bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg) { + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(3); + + // New Offer / Delete #123 / Update #123 + char str_offer[32]; + if (msg->offer_id == 0) { + strlcpy(str_offer, _("New Offer"), sizeof(str_offer)); + } else { + char str_offer_id[20]; + stellar_format_uint64(msg->offer_id, str_offer_id, sizeof(str_offer_id)); - // New Offer / Delete #123 / Update #123 - char str_offer[32]; if (msg->amount == 0) { - strlcpy(str_offer, _("Delete Passive Offer"), sizeof(str_offer)); - } - else { - strlcpy(str_offer, _("New Passive Offer"), sizeof(str_offer)); + strlcpy(str_offer, _("Delete #"), sizeof(str_offer)); + } else { + strlcpy(str_offer, _("Update #"), sizeof(str_offer)); } - char str_selling[32]; - char str_sell_amount[32]; - char str_selling_asset[32]; + strlcat(str_offer, str_offer_id, sizeof(str_offer)); + } - stellar_format_asset(&(msg->selling_asset), str_selling_asset, sizeof(str_selling_asset)); - stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); + char str_selling[32]; + char str_sell_amount[32]; + char str_selling_asset[32]; - /* - Sell 200 - XLM (Native Asset) - */ - strlcpy(str_selling, _("Sell "), sizeof(str_selling)); - strlcat(str_selling, str_sell_amount, sizeof(str_selling)); + stellar_format_asset(&(msg->selling_asset), str_selling_asset, + sizeof(str_selling_asset)); + stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); - char str_buying[32]; - char str_buying_asset[32]; - char str_price[32]; + /* + Sell 200 + XLM (Native Asset) + */ + strlcpy(str_selling, _("Sell "), sizeof(str_selling)); + strlcat(str_selling, str_sell_amount, sizeof(str_selling)); - stellar_format_asset(&(msg->buying_asset), str_buying_asset, sizeof(str_buying_asset)); - stellar_format_price(msg->price_n, msg->price_d, str_price, sizeof(str_price)); + char str_buying[32]; + char str_buying_asset[32]; + char str_price[32]; - /* - For 0.675952 Per - USD (G12345678) - */ - strlcpy(str_buying, _("For "), sizeof(str_buying)); - strlcat(str_buying, str_price, sizeof(str_buying)); - strlcat(str_buying, _(" Per"), sizeof(str_buying)); + stellar_format_asset(&(msg->buying_asset), str_buying_asset, + sizeof(str_buying_asset)); + stellar_format_price(msg->price_n, msg->price_d, str_price, + sizeof(str_price)); - stellar_layoutTransactionDialog( - str_offer, - str_selling, - str_selling_asset, - str_buying, - str_buying_asset - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } + /* + For 0.675952 Per + USD (G12345678) + */ + strlcpy(str_buying, _("For "), sizeof(str_buying)); + strlcat(str_buying, str_price, sizeof(str_buying)); + strlcat(str_buying, _(" Per"), sizeof(str_buying)); - // Hash selling asset - stellar_hashupdate_asset(&(msg->selling_asset)); - // buying asset - stellar_hashupdate_asset(&(msg->buying_asset)); - // amount to sell (signed vs. unsigned doesn't matter wrt hashing) - stellar_hashupdate_uint64(msg->amount); - // numerator - stellar_hashupdate_uint32(msg->price_n); - // denominator - stellar_hashupdate_uint32(msg->price_d); + stellar_layoutTransactionDialog(str_offer, str_selling, str_selling_asset, + str_buying, str_buying_asset); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + // Hash selling asset + stellar_hashupdate_asset(&(msg->selling_asset)); + // buying asset + stellar_hashupdate_asset(&(msg->buying_asset)); + // amount to sell (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->amount); + // numerator + stellar_hashupdate_uint32(msg->price_n); + // denominator + stellar_hashupdate_uint32(msg->price_d); + // offer ID + stellar_hashupdate_uint64(msg->offer_id); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; } -bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmCreatePassiveOfferOp( + const StellarCreatePassiveOfferOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(4); + + // New Offer / Delete #123 / Update #123 + char str_offer[32]; + if (msg->amount == 0) { + strlcpy(str_offer, _("Delete Passive Offer"), sizeof(str_offer)); + } else { + strlcpy(str_offer, _("New Passive Offer"), sizeof(str_offer)); + } + + char str_selling[32]; + char str_sell_amount[32]; + char str_selling_asset[32]; + + stellar_format_asset(&(msg->selling_asset), str_selling_asset, + sizeof(str_selling_asset)); + stellar_format_stroops(msg->amount, str_sell_amount, sizeof(str_sell_amount)); + + /* + Sell 200 + XLM (Native Asset) + */ + strlcpy(str_selling, _("Sell "), sizeof(str_selling)); + strlcat(str_selling, str_sell_amount, sizeof(str_selling)); + + char str_buying[32]; + char str_buying_asset[32]; + char str_price[32]; + + stellar_format_asset(&(msg->buying_asset), str_buying_asset, + sizeof(str_buying_asset)); + stellar_format_price(msg->price_n, msg->price_d, str_price, + sizeof(str_price)); + + /* + For 0.675952 Per + USD (G12345678) + */ + strlcpy(str_buying, _("For "), sizeof(str_buying)); + strlcat(str_buying, str_price, sizeof(str_buying)); + strlcat(str_buying, _(" Per"), sizeof(str_buying)); + + stellar_layoutTransactionDialog(str_offer, str_selling, str_selling_asset, + str_buying, str_buying_asset); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash selling asset + stellar_hashupdate_asset(&(msg->selling_asset)); + // buying asset + stellar_hashupdate_asset(&(msg->buying_asset)); + // amount to sell (signed vs. unsigned doesn't matter wrt hashing) + stellar_hashupdate_uint64(msg->amount); + // numerator + stellar_hashupdate_uint32(msg->price_n); + // denominator + stellar_hashupdate_uint32(msg->price_d); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; +} + +bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg) { + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(5); + + // Something like Set Inflation Destination + char str_title[32]; + char rows[4][32]; + int row_idx = 0; + memzero(rows, sizeof(rows)); + + // Inflation destination + stellar_hashupdate_bool(msg->has_inflation_destination_account); + if (msg->has_inflation_destination_account) { + strlcpy(str_title, _("Set Inflation Destination"), sizeof(str_title)); + + // Validate account and convert to bytes + uint8_t inflation_destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->inflation_destination_account, + inflation_destination_account_bytes)) { + stellar_signingAbort(_("Invalid inflation destination account")); + return false; + } + const char **str_addr_rows = + stellar_lineBreakAddress(inflation_destination_account_bytes); + + stellar_layoutTransactionDialog(str_title, NULL, str_addr_rows[0], + str_addr_rows[1], str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; } - // Hash: operation type - stellar_hashupdate_uint32(5); + // address + stellar_hashupdate_address(inflation_destination_account_bytes); + } - // Something like Set Inflation Destination - char str_title[32]; - char rows[4][32]; - int row_idx = 0; + // Clear flags + stellar_hashupdate_bool(msg->has_clear_flags); + if (msg->has_clear_flags) { + strlcpy(str_title, _("Clear Flag(s)"), sizeof(str_title)); + + // Auth required + if (msg->clear_flags & 0x01) { + strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); + row_idx++; + } + // Auth revocable + if (msg->clear_flags & 0x02) { + strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); + row_idx++; + } + + stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2], + rows[3]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } memzero(rows, sizeof(rows)); - - // Inflation destination - stellar_hashupdate_bool(msg->has_inflation_destination_account); - if (msg->has_inflation_destination_account) { - strlcpy(str_title, _("Set Inflation Destination"), sizeof(str_title)); - - // Validate account and convert to bytes - uint8_t inflation_destination_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->inflation_destination_account, inflation_destination_account_bytes)) { - stellar_signingAbort(_("Invalid inflation destination account")); - return false; - } - const char **str_addr_rows = stellar_lineBreakAddress(inflation_destination_account_bytes); - - stellar_layoutTransactionDialog( - str_title, - NULL, - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - - // address - stellar_hashupdate_address(inflation_destination_account_bytes); - } - - // Clear flags - stellar_hashupdate_bool(msg->has_clear_flags); - if (msg->has_clear_flags) { - strlcpy(str_title, _("Clear Flag(s)"), sizeof(str_title)); - - // Auth required - if (msg->clear_flags & 0x01) { - strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); - row_idx++; - } - // Auth revocable - if (msg->clear_flags & 0x02) { - strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); - row_idx++; - } - - stellar_layoutTransactionDialog( - str_title, - rows[0], - rows[1], - rows[2], - rows[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - memzero(rows, sizeof(rows)); - row_idx = 0; - - // Hash flags - stellar_hashupdate_uint32(msg->clear_flags); - } - - // Set flags - stellar_hashupdate_bool(msg->has_set_flags); - if (msg->has_set_flags) { - strlcpy(str_title, _("Set Flag(s)"), sizeof(str_title)); - - // Auth required - if (msg->set_flags & 0x01) { - strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); - row_idx++; - } - // Auth revocable - if (msg->set_flags & 0x02) { - strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); - row_idx++; - } - - stellar_layoutTransactionDialog( - str_title, - rows[0], - rows[1], - rows[2], - rows[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - memzero(rows, sizeof(rows)); - row_idx = 0; - - // Hash flags - stellar_hashupdate_uint32(msg->set_flags); - } - - // Account thresholds - bool show_thresholds_confirm = false; row_idx = 0; - stellar_hashupdate_bool(msg->has_master_weight); - if (msg->has_master_weight) { - char str_master_weight[10+1]; - show_thresholds_confirm = true; - stellar_format_uint32(msg->master_weight, str_master_weight, sizeof(str_master_weight)); - strlcpy(rows[row_idx], _("Master Weight: "), sizeof(rows[row_idx])); - strlcat(rows[row_idx], str_master_weight, sizeof(rows[row_idx])); - row_idx++; - // Hash master weight - stellar_hashupdate_uint32(msg->master_weight); + // Hash flags + stellar_hashupdate_uint32(msg->clear_flags); + } + + // Set flags + stellar_hashupdate_bool(msg->has_set_flags); + if (msg->has_set_flags) { + strlcpy(str_title, _("Set Flag(s)"), sizeof(str_title)); + + // Auth required + if (msg->set_flags & 0x01) { + strlcpy(rows[row_idx], _("AUTH_REQUIRED"), sizeof(rows[row_idx])); + row_idx++; + } + // Auth revocable + if (msg->set_flags & 0x02) { + strlcpy(rows[row_idx], _("AUTH_REVOCABLE"), sizeof(rows[row_idx])); + row_idx++; } - stellar_hashupdate_bool(msg->has_low_threshold); - if (msg->has_low_threshold) { - char str_low_threshold[10+1]; - show_thresholds_confirm = true; - stellar_format_uint32(msg->low_threshold, str_low_threshold, sizeof(str_low_threshold)); - strlcpy(rows[row_idx], _("Low: "), sizeof(rows[row_idx])); - strlcat(rows[row_idx], str_low_threshold, sizeof(rows[row_idx])); - row_idx++; - - // Hash low threshold - stellar_hashupdate_uint32(msg->low_threshold); - } - stellar_hashupdate_bool(msg->has_medium_threshold); - if (msg->has_medium_threshold) { - char str_med_threshold[10+1]; - show_thresholds_confirm = true; - stellar_format_uint32(msg->medium_threshold, str_med_threshold, sizeof(str_med_threshold)); - strlcpy(rows[row_idx], _("Medium: "), sizeof(rows[row_idx])); - strlcat(rows[row_idx], str_med_threshold, sizeof(rows[row_idx])); - row_idx++; - - // Hash medium threshold - stellar_hashupdate_uint32(msg->medium_threshold); - } - stellar_hashupdate_bool(msg->has_high_threshold); - if (msg->has_high_threshold) { - char str_high_threshold[10+1]; - show_thresholds_confirm = true; - stellar_format_uint32(msg->high_threshold, str_high_threshold, sizeof(str_high_threshold)); - strlcpy(rows[row_idx], _("High: "), sizeof(rows[row_idx])); - strlcat(rows[row_idx], str_high_threshold, sizeof(rows[row_idx])); - row_idx++; - - // Hash high threshold - stellar_hashupdate_uint32(msg->high_threshold); - } - - if (show_thresholds_confirm) { - strlcpy(str_title, _("Account Thresholds"), sizeof(str_title)); - stellar_layoutTransactionDialog( - str_title, - rows[0], - rows[1], - rows[2], - rows[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - memzero(rows, sizeof(rows)); - row_idx = 0; - } - - // Home domain - stellar_hashupdate_bool(msg->has_home_domain); - if (msg->has_home_domain) { - strlcpy(str_title, _("Home Domain"), sizeof(str_title)); - - // Split home domain if longer than 22 characters - int home_domain_len = strnlen(msg->home_domain, 32); - if (home_domain_len > 22) { - strlcpy(rows[0], msg->home_domain, 22); - strlcpy(rows[1], msg->home_domain + 21, sizeof(rows[1])); - } - else { - strlcpy(rows[0], msg->home_domain, sizeof(rows[0])); - } - - stellar_layoutTransactionDialog( - str_title, - rows[0], - rows[1], - NULL, - NULL - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - memzero(rows, sizeof(rows)); - row_idx = 0; - - stellar_hashupdate_string((unsigned char*)&(msg->home_domain), strnlen(msg->home_domain, 32)); - } - - // Signer - stellar_hashupdate_bool(msg->has_signer_type); - if (msg->has_signer_type) { - if (msg->signer_weight > 0) { - strlcpy(str_title, _("Add Signer: "), sizeof(str_title)); - } - else { - strlcpy(str_title, _("REMOVE Signer: "), sizeof(str_title)); - } - - // Format weight as a string - char str_weight[16]; - stellar_format_uint32(msg->signer_weight, str_weight, sizeof(str_weight)); - char str_weight_row[32]; - strlcpy(str_weight_row, _("Weight: "), sizeof(str_weight_row)); - strlcat(str_weight_row, str_weight, sizeof(str_weight_row)); - - // 0 = account, 1 = pre-auth, 2 = hash(x) - char str_signer_type[16]; - bool needs_hash_confirm = false; - if (msg->signer_type == 0) { - strlcpy(str_signer_type, _("account"), sizeof(str_signer_type)); - strlcat(str_title, str_signer_type, sizeof(str_title)); - - const char **str_addr_rows = stellar_lineBreakAddress(msg->signer_key.bytes); - stellar_layoutTransactionDialog( - str_title, - str_weight_row, - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - } - if (msg->signer_type == 1) { - needs_hash_confirm = true; - strlcpy(str_signer_type, _("pre-auth hash"), sizeof(str_signer_type)); - strlcat(str_title, str_signer_type, sizeof(str_title)); - - stellar_layoutTransactionDialog( - str_title, - str_weight_row, - NULL, - _("(confirm hash on next"), - _("screen)") - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - } - if (msg->signer_type == 2) { - needs_hash_confirm = true; - strlcpy(str_signer_type, _("hash(x)"), sizeof(str_signer_type)); - strlcat(str_title, str_signer_type, sizeof(str_title)); - - stellar_layoutTransactionDialog( - str_title, - str_weight_row, - NULL, - _("(confirm hash on next"), - _("screen)") - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - } - - // Extra confirmation step for hash signers - if (needs_hash_confirm) { - data2hex(msg->signer_key.bytes + 0, 8, rows[row_idx++]); - data2hex(msg->signer_key.bytes + 8, 8, rows[row_idx++]); - data2hex(msg->signer_key.bytes + 16, 8, rows[row_idx++]); - data2hex(msg->signer_key.bytes + 24, 8, rows[row_idx++]); - - stellar_layoutTransactionDialog( - _("Confirm Hash"), - rows[0], - rows[1], - rows[2], - rows[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - memzero(rows, sizeof(rows)); - row_idx = 0; - } - - // Hash: signer type - stellar_hashupdate_uint32(msg->signer_type); - // key - stellar_hashupdate_bytes(msg->signer_key.bytes, msg->signer_key.size); - // weight - stellar_hashupdate_uint32(msg->signer_weight); - } - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; -} - -bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) -{ - if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } - - // Hash: operation type - stellar_hashupdate_uint32(6); - - // Add Trust: USD - char str_title[32]; - if (msg->limit == 0) { - strlcpy(str_title, _("DELETE Trust: "), sizeof(str_title)); - } - else { - strlcpy(str_title, _("Add Trust: "), sizeof(str_title)); - } - strlcat(str_title, msg->asset.code, sizeof(str_title)); - - // Amount: MAX (or a number) - char str_amount_row[32]; - strlcpy(str_amount_row, _("Amount: "), sizeof(str_amount_row)); - - if (msg->limit == 9223372036854775807) { - strlcat(str_amount_row, _("[Maximum]"), sizeof(str_amount_row)); - } - else { - char str_amount[32]; - stellar_format_stroops(msg->limit, str_amount, sizeof(str_amount)); - strlcat(str_amount_row, str_amount, sizeof(str_amount_row)); - } - - // Validate destination account and convert to bytes - uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) { - stellar_signingAbort(_("User canceled")); - fsm_sendFailure(FailureType_Failure_ProcessError, _("Invalid asset issuer")); - return false; - } - - // Display full issuer address - const char **str_addr_rows = stellar_lineBreakAddress(asset_issuer_bytes); - - stellar_layoutTransactionDialog( - str_title, - str_amount_row, - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); + stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2], + rows[3]); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; + stellar_signingAbort(_("User canceled")); + return false; } + memzero(rows, sizeof(rows)); + row_idx = 0; - // Hash: asset - stellar_hashupdate_asset(&(msg->asset)); - // limit - stellar_hashupdate_uint64(msg->limit); + // Hash flags + stellar_hashupdate_uint32(msg->set_flags); + } - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; -} + // Account thresholds + bool show_thresholds_confirm = false; + row_idx = 0; + stellar_hashupdate_bool(msg->has_master_weight); + if (msg->has_master_weight) { + char str_master_weight[10 + 1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->master_weight, str_master_weight, + sizeof(str_master_weight)); + strlcpy(rows[row_idx], _("Master Weight: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_master_weight, sizeof(rows[row_idx])); + row_idx++; -bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) -{ - if (!stellar_signing) return false; + // Hash master weight + stellar_hashupdate_uint32(msg->master_weight); + } - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + stellar_hashupdate_bool(msg->has_low_threshold); + if (msg->has_low_threshold) { + char str_low_threshold[10 + 1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->low_threshold, str_low_threshold, + sizeof(str_low_threshold)); + strlcpy(rows[row_idx], _("Low: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_low_threshold, sizeof(rows[row_idx])); + row_idx++; - // Hash: operation type - stellar_hashupdate_uint32(7); + // Hash low threshold + stellar_hashupdate_uint32(msg->low_threshold); + } + stellar_hashupdate_bool(msg->has_medium_threshold); + if (msg->has_medium_threshold) { + char str_med_threshold[10 + 1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->medium_threshold, str_med_threshold, + sizeof(str_med_threshold)); + strlcpy(rows[row_idx], _("Medium: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_med_threshold, sizeof(rows[row_idx])); + row_idx++; - // Add Trust: USD - char str_title[32]; - if (msg->is_authorized) { - strlcpy(str_title, _("Allow Trust of"), sizeof(str_title)); - } - else { - strlcpy(str_title, _("REVOKE Trust of"), sizeof(str_title)); - } + // Hash medium threshold + stellar_hashupdate_uint32(msg->medium_threshold); + } + stellar_hashupdate_bool(msg->has_high_threshold); + if (msg->has_high_threshold) { + char str_high_threshold[10 + 1]; + show_thresholds_confirm = true; + stellar_format_uint32(msg->high_threshold, str_high_threshold, + sizeof(str_high_threshold)); + strlcpy(rows[row_idx], _("High: "), sizeof(rows[row_idx])); + strlcat(rows[row_idx], str_high_threshold, sizeof(rows[row_idx])); + row_idx++; - // Asset code - char str_asset_row[32]; - strlcpy(str_asset_row, msg->asset_code, sizeof(str_asset_row)); + // Hash high threshold + stellar_hashupdate_uint32(msg->high_threshold); + } - // Validate account and convert to bytes - uint8_t trusted_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->trusted_account, trusted_account_bytes)) { - stellar_signingAbort(_("Invalid trusted account")); - return false; - } - - const char **str_trustor_rows = stellar_lineBreakAddress(trusted_account_bytes); - - // By: G... - char str_by[32]; - strlcpy(str_by, _("By: "), sizeof(str_by)); - strlcat(str_by, str_trustor_rows[0], sizeof(str_by)); - - stellar_layoutTransactionDialog( - str_title, - str_asset_row, - str_by, - str_trustor_rows[1], - str_trustor_rows[2] - ); + if (show_thresholds_confirm) { + strlcpy(str_title, _("Account Thresholds"), sizeof(str_title)); + stellar_layoutTransactionDialog(str_title, rows[0], rows[1], rows[2], + rows[3]); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; + stellar_signingAbort(_("User canceled")); + return false; + } + memzero(rows, sizeof(rows)); + row_idx = 0; + } + + // Home domain + stellar_hashupdate_bool(msg->has_home_domain); + if (msg->has_home_domain) { + strlcpy(str_title, _("Home Domain"), sizeof(str_title)); + + // Split home domain if longer than 22 characters + int home_domain_len = strnlen(msg->home_domain, 32); + if (home_domain_len > 22) { + strlcpy(rows[0], msg->home_domain, 22); + strlcpy(rows[1], msg->home_domain + 21, sizeof(rows[1])); + } else { + strlcpy(rows[0], msg->home_domain, sizeof(rows[0])); } - // Hash: trustor account (the account being allowed to access the asset) - stellar_hashupdate_address(trusted_account_bytes); - // asset type - stellar_hashupdate_uint32(msg->asset_type); - // asset code - if (msg->asset_type == 1) { - char code4[4+1]; - memzero(code4, sizeof(code4)); - strlcpy(code4, msg->asset_code, sizeof(code4)); - stellar_hashupdate_bytes((uint8_t *)code4, 4); - } - if (msg->asset_type == 2) { - char code12[12+1]; - memzero(code12, sizeof(code12)); - strlcpy(code12, msg->asset_code, sizeof(code12)); - stellar_hashupdate_bytes((uint8_t *)code12, 12); - } - // is authorized - stellar_hashupdate_bool(msg->is_authorized); - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; -} - -bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) -{ - if (!stellar_signing) return false; - - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } - - // Hash: operation type - stellar_hashupdate_uint32(8); - - // Validate account and convert to bytes - uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; - if (!stellar_getAddressBytes(msg->destination_account, destination_account_bytes)) { - stellar_signingAbort(_("Invalid destination account")); - return false; - } - - const char **str_destination_rows = stellar_lineBreakAddress(destination_account_bytes); - - stellar_layoutTransactionDialog( - _("Merge Account"), - _("All XLM will be sent to:"), - str_destination_rows[0], - str_destination_rows[1], - str_destination_rows[2] - ); + stellar_layoutTransactionDialog(str_title, rows[0], rows[1], NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + memzero(rows, sizeof(rows)); + row_idx = 0; + + stellar_hashupdate_string((unsigned char *)&(msg->home_domain), + strnlen(msg->home_domain, 32)); + } + + // Signer + stellar_hashupdate_bool(msg->has_signer_type); + if (msg->has_signer_type) { + if (msg->signer_weight > 0) { + strlcpy(str_title, _("Add Signer: "), sizeof(str_title)); + } else { + strlcpy(str_title, _("REMOVE Signer: "), sizeof(str_title)); + } + + // Format weight as a string + char str_weight[16]; + stellar_format_uint32(msg->signer_weight, str_weight, sizeof(str_weight)); + char str_weight_row[32]; + strlcpy(str_weight_row, _("Weight: "), sizeof(str_weight_row)); + strlcat(str_weight_row, str_weight, sizeof(str_weight_row)); + + // 0 = account, 1 = pre-auth, 2 = hash(x) + char str_signer_type[16]; + bool needs_hash_confirm = false; + if (msg->signer_type == 0) { + strlcpy(str_signer_type, _("account"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + const char **str_addr_rows = + stellar_lineBreakAddress(msg->signer_key.bytes); + stellar_layoutTransactionDialog(str_title, str_weight_row, + str_addr_rows[0], str_addr_rows[1], + str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { stellar_signingAbort(_("User canceled")); return false; + } + } + if (msg->signer_type == 1) { + needs_hash_confirm = true; + strlcpy(str_signer_type, _("pre-auth hash"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + stellar_layoutTransactionDialog(str_title, str_weight_row, NULL, + _("(confirm hash on next"), _("screen)")); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + } + if (msg->signer_type == 2) { + needs_hash_confirm = true; + strlcpy(str_signer_type, _("hash(x)"), sizeof(str_signer_type)); + strlcat(str_title, str_signer_type, sizeof(str_title)); + + stellar_layoutTransactionDialog(str_title, str_weight_row, NULL, + _("(confirm hash on next"), _("screen)")); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } } - // Hash: destination account - stellar_hashupdate_address(destination_account_bytes); + // Extra confirmation step for hash signers + if (needs_hash_confirm) { + data2hex(msg->signer_key.bytes + 0, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 8, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 16, 8, rows[row_idx++]); + data2hex(msg->signer_key.bytes + 24, 8, rows[row_idx++]); - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + stellar_layoutTransactionDialog(_("Confirm Hash"), rows[0], rows[1], + rows[2], rows[3]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + memzero(rows, sizeof(rows)); + row_idx = 0; + } + + // Hash: signer type + stellar_hashupdate_uint32(msg->signer_type); + // key + stellar_hashupdate_bytes(msg->signer_key.bytes, msg->signer_key.size); + // weight + stellar_hashupdate_uint32(msg->signer_weight); + } + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; } -bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } - // Hash: operation type - stellar_hashupdate_uint32(10); + // Hash: operation type + stellar_hashupdate_uint32(6); - char str_title[32]; - if (msg->has_value) { - strlcpy(str_title, _("Set data value key:"), sizeof(str_title)); - } - else { - strlcpy(str_title, _("CLEAR data value key:"), sizeof(str_title)); - } + // Add Trust: USD + char str_title[32]; + if (msg->limit == 0) { + strlcpy(str_title, _("DELETE Trust: "), sizeof(str_title)); + } else { + strlcpy(str_title, _("Add Trust: "), sizeof(str_title)); + } + strlcat(str_title, msg->asset.code, sizeof(str_title)); - // Confirm key - const char **str_key_lines = split_message((const uint8_t*)(msg->key), strnlen(msg->key, 64), 16); + // Amount: MAX (or a number) + char str_amount_row[32]; + strlcpy(str_amount_row, _("Amount: "), sizeof(str_amount_row)); - stellar_layoutTransactionDialog( - str_title, - str_key_lines[0], - str_key_lines[1], - str_key_lines[2], - str_key_lines[3] - ); + if (msg->limit == 9223372036854775807) { + strlcat(str_amount_row, _("[Maximum]"), sizeof(str_amount_row)); + } else { + char str_amount[32]; + stellar_format_stroops(msg->limit, str_amount, sizeof(str_amount)); + strlcat(str_amount_row, str_amount, sizeof(str_amount_row)); + } + + // Validate destination account and convert to bytes + uint8_t asset_issuer_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->asset.issuer, asset_issuer_bytes)) { + stellar_signingAbort(_("User canceled")); + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Invalid asset issuer")); + return false; + } + + // Display full issuer address + const char **str_addr_rows = stellar_lineBreakAddress(asset_issuer_bytes); + + stellar_layoutTransactionDialog(str_title, str_amount_row, str_addr_rows[0], + str_addr_rows[1], str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash: asset + stellar_hashupdate_asset(&(msg->asset)); + // limit + stellar_hashupdate_uint64(msg->limit); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; +} + +bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg) { + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(7); + + // Add Trust: USD + char str_title[32]; + if (msg->is_authorized) { + strlcpy(str_title, _("Allow Trust of"), sizeof(str_title)); + } else { + strlcpy(str_title, _("REVOKE Trust of"), sizeof(str_title)); + } + + // Asset code + char str_asset_row[32]; + strlcpy(str_asset_row, msg->asset_code, sizeof(str_asset_row)); + + // Validate account and convert to bytes + uint8_t trusted_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->trusted_account, trusted_account_bytes)) { + stellar_signingAbort(_("Invalid trusted account")); + return false; + } + + const char **str_trustor_rows = + stellar_lineBreakAddress(trusted_account_bytes); + + // By: G... + char str_by[32]; + strlcpy(str_by, _("By: "), sizeof(str_by)); + strlcat(str_by, str_trustor_rows[0], sizeof(str_by)); + + stellar_layoutTransactionDialog(str_title, str_asset_row, str_by, + str_trustor_rows[1], str_trustor_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash: trustor account (the account being allowed to access the asset) + stellar_hashupdate_address(trusted_account_bytes); + // asset type + stellar_hashupdate_uint32(msg->asset_type); + // asset code + if (msg->asset_type == 1) { + char code4[4 + 1]; + memzero(code4, sizeof(code4)); + strlcpy(code4, msg->asset_code, sizeof(code4)); + stellar_hashupdate_bytes((uint8_t *)code4, 4); + } + if (msg->asset_type == 2) { + char code12[12 + 1]; + memzero(code12, sizeof(code12)); + strlcpy(code12, msg->asset_code, sizeof(code12)); + stellar_hashupdate_bytes((uint8_t *)code12, 12); + } + // is authorized + stellar_hashupdate_bool(msg->is_authorized); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; +} + +bool stellar_confirmAccountMergeOp(const StellarAccountMergeOp *msg) { + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(8); + + // Validate account and convert to bytes + uint8_t destination_account_bytes[STELLAR_KEY_SIZE]; + if (!stellar_getAddressBytes(msg->destination_account, + destination_account_bytes)) { + stellar_signingAbort(_("Invalid destination account")); + return false; + } + + const char **str_destination_rows = + stellar_lineBreakAddress(destination_account_bytes); + + stellar_layoutTransactionDialog( + _("Merge Account"), _("All XLM will be sent to:"), + str_destination_rows[0], str_destination_rows[1], + str_destination_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Hash: destination account + stellar_hashupdate_address(destination_account_bytes); + + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; +} + +bool stellar_confirmManageDataOp(const StellarManageDataOp *msg) { + if (!stellar_signing) return false; + + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } + + // Hash: operation type + stellar_hashupdate_uint32(10); + + char str_title[32]; + if (msg->has_value) { + strlcpy(str_title, _("Set data value key:"), sizeof(str_title)); + } else { + strlcpy(str_title, _("CLEAR data value key:"), sizeof(str_title)); + } + + // Confirm key + const char **str_key_lines = + split_message((const uint8_t *)(msg->key), strnlen(msg->key, 64), 16); + + stellar_layoutTransactionDialog(str_title, str_key_lines[0], str_key_lines[1], + str_key_lines[2], str_key_lines[3]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } + + // Confirm value by displaying sha256 hash since this can contain + // non-printable characters + if (msg->has_value) { + strlcpy(str_title, _("Confirm sha256 of value:"), sizeof(str_title)); + + char str_hash_digest[SHA256_DIGEST_STRING_LENGTH]; + sha256_Data(msg->value.bytes, msg->value.size, str_hash_digest); + const char **str_hash_lines = split_message( + (const uint8_t *)str_hash_digest, sizeof(str_hash_digest), 16); + + stellar_layoutTransactionDialog(str_title, str_hash_lines[0], + str_hash_lines[1], str_hash_lines[2], + str_hash_lines[3]); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; + stellar_signingAbort(_("User canceled")); + return false; } + } - // Confirm value by displaying sha256 hash since this can contain non-printable characters - if (msg->has_value) { - strlcpy(str_title, _("Confirm sha256 of value:"), sizeof(str_title)); + // Hash: key + stellar_hashupdate_string((unsigned char *)&(msg->key), + strnlen(msg->key, 64)); + // value + if (msg->has_value) { + stellar_hashupdate_bool(true); + // Variable opaque field is length + raw bytes + stellar_hashupdate_uint32(msg->value.size); + stellar_hashupdate_bytes(msg->value.bytes, msg->value.size); + } else { + stellar_hashupdate_bool(false); + } - char str_hash_digest[SHA256_DIGEST_STRING_LENGTH]; - sha256_Data(msg->value.bytes, msg->value.size, str_hash_digest); - const char **str_hash_lines = split_message((const uint8_t*)str_hash_digest, sizeof(str_hash_digest), 16); - - stellar_layoutTransactionDialog( - str_title, - str_hash_lines[0], - str_hash_lines[1], - str_hash_lines[2], - str_hash_lines[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } - } - - // Hash: key - stellar_hashupdate_string((unsigned char*)&(msg->key), strnlen(msg->key, 64)); - // value - if (msg->has_value) { - stellar_hashupdate_bool(true); - // Variable opaque field is length + raw bytes - stellar_hashupdate_uint32(msg->value.size); - stellar_hashupdate_bytes(msg->value.bytes, msg->value.size); - } - else { - stellar_hashupdate_bool(false); - } - - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; } -bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) -{ - if (!stellar_signing) return false; +bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg) { + if (!stellar_signing) return false; - if (!stellar_confirmSourceAccount(msg->has_source_account, msg->source_account)) { - stellar_signingAbort(_("Source account error")); - return false; - } + if (!stellar_confirmSourceAccount(msg->has_source_account, + msg->source_account)) { + stellar_signingAbort(_("Source account error")); + return false; + } - // Hash: operation type - stellar_hashupdate_uint32(11); + // Hash: operation type + stellar_hashupdate_uint32(11); - char str_bump_to[20]; - stellar_format_uint64(msg->bump_to, str_bump_to, sizeof(str_bump_to)); + char str_bump_to[20]; + stellar_format_uint64(msg->bump_to, str_bump_to, sizeof(str_bump_to)); - stellar_layoutTransactionDialog( - _("Bump Sequence"), - _("Set sequence to:"), - str_bump_to, - NULL, - NULL - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return false; - } + stellar_layoutTransactionDialog(_("Bump Sequence"), _("Set sequence to:"), + str_bump_to, NULL, NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return false; + } - // Hash: bump to - stellar_hashupdate_uint64(msg->bump_to); + // Hash: bump to + stellar_hashupdate_uint64(msg->bump_to); - // At this point, the operation is confirmed - stellar_activeTx.confirmed_operations++; - return true; + // At this point, the operation is confirmed + stellar_activeTx.confirmed_operations++; + return true; } -void stellar_signingAbort(const char *reason) -{ - if (!reason) { - reason = _("Unknown error"); - } +void stellar_signingAbort(const char *reason) { + if (!reason) { + reason = _("Unknown error"); + } - stellar_signing = false; - fsm_sendFailure(FailureType_Failure_ProcessError, reason); - layoutHome(); + stellar_signing = false; + fsm_sendFailure(FailureType_Failure_ProcessError, reason); + layoutHome(); } /** * Populates the fields of resp with the signature of the active transaction */ -void stellar_fillSignedTx(StellarSignedTx *resp) -{ - // Finalize the transaction by hashing 4 null bytes representing a (currently unused) empty union - stellar_hashupdate_uint32(0); +void stellar_fillSignedTx(StellarSignedTx *resp) { + // Finalize the transaction by hashing 4 null bytes representing a (currently + // unused) empty union + stellar_hashupdate_uint32(0); - // Add the public key for verification that the right account was used for signing - memcpy(resp->public_key.bytes, stellar_activeTx.signing_pubkey, 32); - resp->public_key.size = 32; - resp->has_public_key = true; + // Add the public key for verification that the right account was used for + // signing + memcpy(resp->public_key.bytes, stellar_activeTx.signing_pubkey, 32); + resp->public_key.size = 32; + resp->has_public_key = true; - // Add the signature (note that this does not include the 4-byte hint since it can be calculated from the public key) - uint8_t signature[64]; - // Note: this calls sha256_Final on the hash context - stellar_getSignatureForActiveTx(signature); - memcpy(resp->signature.bytes, signature, sizeof(signature)); - resp->signature.size = sizeof(signature); - resp->has_signature = true; + // Add the signature (note that this does not include the 4-byte hint since it + // can be calculated from the public key) + uint8_t signature[64]; + // Note: this calls sha256_Final on the hash context + stellar_getSignatureForActiveTx(signature); + memcpy(resp->signature.bytes, signature, sizeof(signature)); + resp->signature.size = sizeof(signature); + resp->has_signature = true; } -bool stellar_allOperationsConfirmed() -{ - return stellar_activeTx.confirmed_operations == stellar_activeTx.num_operations; +bool stellar_allOperationsConfirmed() { + return stellar_activeTx.confirmed_operations == + stellar_activeTx.num_operations; } /* * Calculates and sets the signature for the active transaction */ -void stellar_getSignatureForActiveTx(uint8_t *out_signature) -{ - const HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, stellar_activeTx.address_n_count); - if (!node) { - // return empty signature when we can't derive node - memzero(out_signature, 64); - return; - } +void stellar_getSignatureForActiveTx(uint8_t *out_signature) { + const HDNode *node = stellar_deriveNode(stellar_activeTx.address_n, + stellar_activeTx.address_n_count); + if (!node) { + // return empty signature when we can't derive node + memzero(out_signature, 64); + return; + } - // Signature is the ed25519 detached signature of the sha256 of all the bytes - // that have been read so far - uint8_t to_sign[32]; - sha256_Final(&(stellar_activeTx.sha256_ctx), to_sign); + // Signature is the ed25519 detached signature of the sha256 of all the bytes + // that have been read so far + uint8_t to_sign[32]; + sha256_Final(&(stellar_activeTx.sha256_ctx), to_sign); - uint8_t signature[64]; - ed25519_sign(to_sign, sizeof(to_sign), node->private_key, node->public_key + 1, signature); + uint8_t signature[64]; + ed25519_sign(to_sign, sizeof(to_sign), node->private_key, + node->public_key + 1, signature); - memcpy(out_signature, signature, sizeof(signature)); + memcpy(out_signature, signature, sizeof(signature)); } /* * Returns number (representing stroops) formatted as XLM - * For example, if number has value 1000000000 then it will be returned as "100.0" + * For example, if number has value 1000000000 then it will be returned as + * "100.0" */ -void stellar_format_stroops(uint64_t number, char *out, size_t outlen) -{ - bn_format_uint64(number, NULL, NULL, 7, 0, false, out, outlen); +void stellar_format_stroops(uint64_t number, char *out, size_t outlen) { + bn_format_uint64(number, NULL, NULL, 7, 0, false, out, outlen); } /* * Formats a price represented as a uint32 numerator and uint32 denominator * - * Note that there may be a loss of precision between the real price value and what - * is shown to the user + * Note that there may be a loss of precision between the real price value and + * what is shown to the user * * Smallest possible price is 1 / 4294967296 which is: * 0.00000000023283064365386962890625 @@ -1269,77 +1196,74 @@ void stellar_format_stroops(uint64_t number, char *out, size_t outlen) * largest possible price is: * 4294967296 */ -void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen) -{ - memzero(out, outlen); +void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, + size_t outlen) { + memzero(out, outlen); - // early exit for invalid denominator - if (denominator == 0) { - strlcpy(out, _("[Invalid Price]"), outlen); - return; - } + // early exit for invalid denominator + if (denominator == 0) { + strlcpy(out, _("[Invalid Price]"), outlen); + return; + } - // early exit for zero - if (numerator == 0) { - strlcpy(out, "0", outlen); - return; - } + // early exit for zero + if (numerator == 0) { + strlcpy(out, "0", outlen); + return; + } - int scale = 0; - uint64_t value = numerator; - while (value < (UINT64_MAX / 10)) { - value *= 10; - scale++; - } - value /= denominator; - while (value < (UINT64_MAX / 10)) { - value *= 10; - scale++; - } + int scale = 0; + uint64_t value = numerator; + while (value < (UINT64_MAX / 10)) { + value *= 10; + scale++; + } + value /= denominator; + while (value < (UINT64_MAX / 10)) { + value *= 10; + scale++; + } - // Format with bn_format_uint64 - bn_format_uint64(value, NULL, NULL, scale, 0, false, out, outlen); + // Format with bn_format_uint64 + bn_format_uint64(value, NULL, NULL, scale, 0, false, out, outlen); } /* * Returns a uint32 formatted as a string */ -void stellar_format_uint32(uint32_t number, char *out, size_t outlen) -{ - bignum256 bn_number; - bn_read_uint32(number, &bn_number); - bn_format(&bn_number, NULL, NULL, 0, 0, false, out, outlen); +void stellar_format_uint32(uint32_t number, char *out, size_t outlen) { + bignum256 bn_number; + bn_read_uint32(number, &bn_number); + bn_format(&bn_number, NULL, NULL, 0, 0, false, out, outlen); } /* * Returns a uint64 formatted as a string */ -void stellar_format_uint64(uint64_t number, char *out, size_t outlen) -{ - bn_format_uint64(number, NULL, NULL, 0, 0, false, out, outlen); +void stellar_format_uint64(uint64_t number, char *out, size_t outlen) { + bn_format_uint64(number, NULL, NULL, 0, 0, false, out, outlen); } /* * Breaks a 56 character address into 3 lines of lengths 16, 20, 20 * This is to allow a small label to be prepended to the first line */ -const char **stellar_lineBreakAddress(const uint8_t *addrbytes) -{ - char str_fulladdr[56+1]; - static char rows[3][20+1]; +const char **stellar_lineBreakAddress(const uint8_t *addrbytes) { + char str_fulladdr[56 + 1]; + static char rows[3][20 + 1]; - memzero(rows, sizeof(rows)); + memzero(rows, sizeof(rows)); - // get full address string - stellar_publicAddressAsStr(addrbytes, str_fulladdr, sizeof(str_fulladdr)); + // get full address string + stellar_publicAddressAsStr(addrbytes, str_fulladdr, sizeof(str_fulladdr)); - // Break it into 3 lines - strlcpy(rows[0], str_fulladdr + 0, 17); - strlcpy(rows[1], str_fulladdr + 16, 21); - strlcpy(rows[2], str_fulladdr + 16 + 20, 21); + // Break it into 3 lines + strlcpy(rows[0], str_fulladdr + 0, 17); + strlcpy(rows[1], str_fulladdr + 16, 21); + strlcpy(rows[2], str_fulladdr + 16 + 20, 21); - static const char *ret[3] = { rows[0], rows[1], rows[2] }; - return ret; + static const char *ret[3] = {rows[0], rows[1], rows[2]}; + return ret; } /* @@ -1350,450 +1274,429 @@ const char **stellar_lineBreakAddress(const uint8_t *addrbytes) * MOBI (G123456789000) * ALPHA12EXAMP (G0987) */ -void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len) -{ - char str_asset_code[12 + 1]; - // truncated asset issuer, final length depends on length of asset code - char str_asset_issuer_trunc[13 + 1]; +void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, + size_t len) { + char str_asset_code[12 + 1]; + // truncated asset issuer, final length depends on length of asset code + char str_asset_issuer_trunc[13 + 1]; - memzero(str_formatted, len); - memzero(str_asset_code, sizeof(str_asset_code)); - memzero(str_asset_issuer_trunc, sizeof(str_asset_issuer_trunc)); + memzero(str_formatted, len); + memzero(str_asset_code, sizeof(str_asset_code)); + memzero(str_asset_issuer_trunc, sizeof(str_asset_issuer_trunc)); - // Validate issuer account for non-native assets - if (asset->type != 0 && !stellar_validateAddress(asset->issuer)) { - stellar_signingAbort(_("Invalid asset issuer")); - return; - } + // Validate issuer account for non-native assets + if (asset->type != 0 && !stellar_validateAddress(asset->issuer)) { + stellar_signingAbort(_("Invalid asset issuer")); + return; + } - // Native asset - if (asset->type == 0) { - strlcpy(str_formatted, _("XLM (native asset)"), len); - } - // 4-character custom - if (asset->type == 1) { - memcpy(str_asset_code, asset->code, 4); - strlcpy(str_formatted, str_asset_code, len); + // Native asset + if (asset->type == 0) { + strlcpy(str_formatted, _("XLM (native asset)"), len); + } + // 4-character custom + if (asset->type == 1) { + memcpy(str_asset_code, asset->code, 4); + strlcpy(str_formatted, str_asset_code, len); - // Truncate issuer to 13 chars - memcpy(str_asset_issuer_trunc, asset->issuer, 13); - } - // 12-character custom - if (asset->type == 2) { - memcpy(str_asset_code, asset->code, 12); - strlcpy(str_formatted, str_asset_code, len); + // Truncate issuer to 13 chars + memcpy(str_asset_issuer_trunc, asset->issuer, 13); + } + // 12-character custom + if (asset->type == 2) { + memcpy(str_asset_code, asset->code, 12); + strlcpy(str_formatted, str_asset_code, len); - // Truncate issuer to 5 characters - memcpy(str_asset_issuer_trunc, asset->issuer, 5); - } - // Issuer is read the same way for both types of custom assets - if (asset->type == 1 || asset->type == 2) { - strlcat(str_formatted, _(" ("), len); - strlcat(str_formatted, str_asset_issuer_trunc, len); - strlcat(str_formatted, _(")"), len); - } + // Truncate issuer to 5 characters + memcpy(str_asset_issuer_trunc, asset->issuer, 5); + } + // Issuer is read the same way for both types of custom assets + if (asset->type == 1 || asset->type == 2) { + strlcat(str_formatted, _(" ("), len); + strlcat(str_formatted, str_asset_issuer_trunc, len); + strlcat(str_formatted, _(")"), len); + } } -size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen) -{ - // version + key bytes + checksum - uint8_t keylen = 1 + 32 + 2; - uint8_t bytes_full[keylen]; - bytes_full[0] = 6 << 3; // 'G' +size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, + size_t outlen) { + // version + key bytes + checksum + uint8_t keylen = 1 + 32 + 2; + uint8_t bytes_full[keylen]; + bytes_full[0] = 6 << 3; // 'G' - memcpy(bytes_full + 1, bytes, 32); + memcpy(bytes_full + 1, bytes, 32); - // Last two bytes are the checksum - uint16_t checksum = stellar_crc16(bytes_full, 33); - bytes_full[keylen-2] = checksum & 0x00ff; - bytes_full[keylen-1] = (checksum>>8) & 0x00ff; + // Last two bytes are the checksum + uint16_t checksum = stellar_crc16(bytes_full, 33); + bytes_full[keylen - 2] = checksum & 0x00ff; + bytes_full[keylen - 1] = (checksum >> 8) & 0x00ff; - base32_encode(bytes_full, keylen, out, outlen, BASE32_ALPHABET_RFC4648); + base32_encode(bytes_full, keylen, out, outlen, BASE32_ALPHABET_RFC4648); - // Public key will always be 56 characters - return 56; + // Public key will always be 56 characters + return 56; } /** * Stellar account string is a base32-encoded string that starts with "G" * * It decodes to the following format: - * Byte 0 - always 0x30 ("G" when base32 encoded), version byte indicating a public key - * Bytes 1-33 - 32-byte public key bytes - * Bytes 34-35 - 2-byte CRC16 checksum of the version byte + public key bytes (first 33 bytes) + * Byte 0 - always 0x30 ("G" when base32 encoded), version byte indicating a + * public key Bytes 1-33 - 32-byte public key bytes Bytes 34-35 - 2-byte CRC16 + * checksum of the version byte + public key bytes (first 33 bytes) * - * Note that the stellar "seed" (private key) also uses this format except the version byte - * is 0xC0 which encodes to "S" in base32 + * Note that the stellar "seed" (private key) also uses this format except the + * version byte is 0xC0 which encodes to "S" in base32 */ -bool stellar_validateAddress(const char *str_address) -{ - bool valid = false; - uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; +bool stellar_validateAddress(const char *str_address) { + bool valid = false; + uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; - if (strlen(str_address) != STELLAR_ADDRESS_SIZE) { - return false; - } + if (strlen(str_address) != STELLAR_ADDRESS_SIZE) { + return false; + } - // Check that it decodes correctly - uint8_t *ret = base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, sizeof(decoded), BASE32_ALPHABET_RFC4648); - valid = (ret != NULL); + // Check that it decodes correctly + uint8_t *ret = base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, + sizeof(decoded), BASE32_ALPHABET_RFC4648); + valid = (ret != NULL); - // ... and that version byte is 0x30 - if (valid && decoded[0] != 0x30) { - valid = false; - } + // ... and that version byte is 0x30 + if (valid && decoded[0] != 0x30) { + valid = false; + } - // ... and that checksums match - uint16_t checksum_expected = stellar_crc16(decoded, 33); - uint16_t checksum_actual = (decoded[34] << 8) | decoded[33]; // unsigned short (little endian) - if (valid && checksum_expected != checksum_actual) { - valid = false; - } + // ... and that checksums match + uint16_t checksum_expected = stellar_crc16(decoded, 33); + uint16_t checksum_actual = + (decoded[34] << 8) | decoded[33]; // unsigned short (little endian) + if (valid && checksum_expected != checksum_actual) { + valid = false; + } - memzero(decoded, sizeof(decoded)); - return valid; + memzero(decoded, sizeof(decoded)); + return valid; } /** * Converts a string address (G...) to the 32-byte raw address */ -bool stellar_getAddressBytes(const char* str_address, uint8_t *out_bytes) -{ - uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; +bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes) { + uint8_t decoded[STELLAR_ADDRESS_SIZE_RAW]; - // Ensure address is valid - if (!stellar_validateAddress(str_address)) return false; + // Ensure address is valid + if (!stellar_validateAddress(str_address)) return false; - base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, sizeof(decoded), BASE32_ALPHABET_RFC4648); + base32_decode(str_address, STELLAR_ADDRESS_SIZE, decoded, sizeof(decoded), + BASE32_ALPHABET_RFC4648); - // The 32 bytes with offset 1-33 represent the public key - memcpy(out_bytes, &decoded[1], 32); + // The 32 bytes with offset 1-33 represent the public key + memcpy(out_bytes, &decoded[1], 32); - memzero(decoded, sizeof(decoded)); - return true; + memzero(decoded, sizeof(decoded)); + return true; } /* * CRC16 implementation compatible with the Stellar version - * Ported from this implementation: http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java.html - * Initial value changed to 0x0000 to match Stellar + * Ported from this implementation: + * http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java.html Initial + * value changed to 0x0000 to match Stellar */ -uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) -{ - // Calculate checksum for existing bytes - uint16_t crc = 0x0000; - uint16_t polynomial = 0x1021; - uint32_t i; - uint8_t bit; - uint8_t byte; - uint8_t bitidx; - uint8_t c15; +uint16_t stellar_crc16(uint8_t *bytes, uint32_t length) { + // Calculate checksum for existing bytes + uint16_t crc = 0x0000; + uint16_t polynomial = 0x1021; + uint32_t i; + uint8_t bit; + uint8_t byte; + uint8_t bitidx; + uint8_t c15; - for (i=0; i < length; i++) { - byte = bytes[i]; - for (bitidx=0; bitidx < 8; bitidx++) { - bit = ((byte >> (7 - bitidx) & 1) == 1); - c15 = ((crc >> 15 & 1) == 1); - crc <<= 1; - if (c15 ^ bit) crc ^= polynomial; - } + for (i = 0; i < length; i++) { + byte = bytes[i]; + for (bitidx = 0; bitidx < 8; bitidx++) { + bit = ((byte >> (7 - bitidx) & 1) == 1); + c15 = ((crc >> 15 & 1) == 1); + crc <<= 1; + if (c15 ^ bit) crc ^= polynomial; } + } - return crc & 0xffff; + return crc & 0xffff; } /* * Derives the HDNode at the given index - * Standard Stellar prefix is m/44'/148'/ and the default account is m/44'/148'/0' + * Standard Stellar prefix is m/44'/148'/ and the default account is + * m/44'/148'/0' * * All paths must be hardened */ -const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count) -{ - static CONFIDENTIAL HDNode node; - const char *curve = "ed25519"; +const HDNode *stellar_deriveNode(const uint32_t *address_n, + size_t address_n_count) { + static CONFIDENTIAL HDNode node; + const char *curve = "ed25519"; - // Device not initialized, passphrase request cancelled, or unsupported curve - if (!config_getRootNode(&node, curve, true)) { - return 0; - } - // Failed to derive private key - if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { - return 0; - } + // Device not initialized, passphrase request cancelled, or unsupported curve + if (!config_getRootNode(&node, curve, true)) { + return 0; + } + // Failed to derive private key + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, NULL) == 0) { + return 0; + } - hdnode_fill_public_key(&node); + hdnode_fill_public_key(&node); - return &node; + return &node; } -void stellar_hashupdate_uint32(uint32_t value) -{ - // Ensure uint32 is big endian +void stellar_hashupdate_uint32(uint32_t value) { + // Ensure uint32 is big endian #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE32(value, value); + REVERSE32(value, value); #endif - // Byte values must be hashed as big endian - uint8_t data[4]; - data[3] = (value >> 24) & 0xFF; - data[2] = (value >> 16) & 0xFF; - data[1] = (value >> 8) & 0xFF; - data[0] = value & 0xFF; + // Byte values must be hashed as big endian + uint8_t data[4]; + data[3] = (value >> 24) & 0xFF; + data[2] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[0] = value & 0xFF; - stellar_hashupdate_bytes(data, sizeof(data)); + stellar_hashupdate_bytes(data, sizeof(data)); } -void stellar_hashupdate_uint64(uint64_t value) -{ - // Ensure uint64 is big endian +void stellar_hashupdate_uint64(uint64_t value) { + // Ensure uint64 is big endian #if BYTE_ORDER == LITTLE_ENDIAN - REVERSE64(value, value); + REVERSE64(value, value); #endif - // Byte values must be hashed as big endian - uint8_t data[8]; - data[7] = (value >> 56) & 0xFF; - data[6] = (value >> 48) & 0xFF; - data[5] = (value >> 40) & 0xFF; - data[4] = (value >> 32) & 0xFF; - data[3] = (value >> 24) & 0xFF; - data[2] = (value >> 16) & 0xFF; - data[1] = (value >> 8) & 0xFF; - data[0] = value & 0xFF; + // Byte values must be hashed as big endian + uint8_t data[8]; + data[7] = (value >> 56) & 0xFF; + data[6] = (value >> 48) & 0xFF; + data[5] = (value >> 40) & 0xFF; + data[4] = (value >> 32) & 0xFF; + data[3] = (value >> 24) & 0xFF; + data[2] = (value >> 16) & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[0] = value & 0xFF; - stellar_hashupdate_bytes(data, sizeof(data)); + stellar_hashupdate_bytes(data, sizeof(data)); } -void stellar_hashupdate_bool(bool value) -{ - if (value) { - stellar_hashupdate_uint32(1); - } - else { - stellar_hashupdate_uint32(0); - } -} - -void stellar_hashupdate_string(const uint8_t *data, size_t len) -{ - // Hash the length of the string - stellar_hashupdate_uint32((uint32_t)len); - - // Hash the raw bytes of the string - stellar_hashupdate_bytes(data, len); - - // If len isn't a multiple of 4, add padding bytes - int remainder = len % 4; - uint8_t null_byte[1] = { 0x00 }; - if (remainder) { - while (remainder < 4) { - stellar_hashupdate_bytes(null_byte, 1); - remainder++; - } - } -} - -void stellar_hashupdate_address(const uint8_t *address_bytes) -{ - // First 4 bytes of an address are the type. There's only one type (0) +void stellar_hashupdate_bool(bool value) { + if (value) { + stellar_hashupdate_uint32(1); + } else { stellar_hashupdate_uint32(0); + } +} - // Remaining part of the address is 32 bytes - stellar_hashupdate_bytes(address_bytes, 32); +void stellar_hashupdate_string(const uint8_t *data, size_t len) { + // Hash the length of the string + stellar_hashupdate_uint32((uint32_t)len); + + // Hash the raw bytes of the string + stellar_hashupdate_bytes(data, len); + + // If len isn't a multiple of 4, add padding bytes + int remainder = len % 4; + uint8_t null_byte[1] = {0x00}; + if (remainder) { + while (remainder < 4) { + stellar_hashupdate_bytes(null_byte, 1); + remainder++; + } + } +} + +void stellar_hashupdate_address(const uint8_t *address_bytes) { + // First 4 bytes of an address are the type. There's only one type (0) + stellar_hashupdate_uint32(0); + + // Remaining part of the address is 32 bytes + stellar_hashupdate_bytes(address_bytes, 32); } /* - * Note about string handling below: this field is an XDR "opaque" field and not a typical string, - * so if "TEST" is the asset code then the hashed value needs to be 4 bytes and not include the null - * at the end of the string + * Note about string handling below: this field is an XDR "opaque" field and not + * a typical string, so if "TEST" is the asset code then the hashed value needs + * to be 4 bytes and not include the null at the end of the string */ -void stellar_hashupdate_asset(const StellarAssetType *asset) -{ - stellar_hashupdate_uint32(asset->type); +void stellar_hashupdate_asset(const StellarAssetType *asset) { + stellar_hashupdate_uint32(asset->type); - // For non-native assets, validate issuer account and convert to bytes - uint8_t issuer_bytes[STELLAR_KEY_SIZE]; - if (asset->type != 0 && !stellar_getAddressBytes(asset->issuer, issuer_bytes)) { - stellar_signingAbort(_("Invalid asset issuer")); - return; - } + // For non-native assets, validate issuer account and convert to bytes + uint8_t issuer_bytes[STELLAR_KEY_SIZE]; + if (asset->type != 0 && + !stellar_getAddressBytes(asset->issuer, issuer_bytes)) { + stellar_signingAbort(_("Invalid asset issuer")); + return; + } - // 4-character asset code - if (asset->type == 1) { - char code4[4 + 1]; - memzero(code4, sizeof(code4)); - strlcpy(code4, asset->code, sizeof(code4)); + // 4-character asset code + if (asset->type == 1) { + char code4[4 + 1]; + memzero(code4, sizeof(code4)); + strlcpy(code4, asset->code, sizeof(code4)); - stellar_hashupdate_bytes((uint8_t *)code4, 4); - stellar_hashupdate_address(issuer_bytes); - } + stellar_hashupdate_bytes((uint8_t *)code4, 4); + stellar_hashupdate_address(issuer_bytes); + } - // 12-character asset code - if (asset->type == 2) { - char code12[12 + 1]; - memzero(code12, sizeof(code12)); - strlcpy(code12, asset->code, sizeof(code12)); + // 12-character asset code + if (asset->type == 2) { + char code12[12 + 1]; + memzero(code12, sizeof(code12)); + strlcpy(code12, asset->code, sizeof(code12)); - stellar_hashupdate_bytes((uint8_t *)code12, 12); - stellar_hashupdate_address(issuer_bytes); - } + stellar_hashupdate_bytes((uint8_t *)code12, 12); + stellar_hashupdate_address(issuer_bytes); + } } -void stellar_hashupdate_bytes(const uint8_t *data, size_t len) -{ - sha256_Update(&(stellar_activeTx.sha256_ctx), data, len); +void stellar_hashupdate_bytes(const uint8_t *data, size_t len) { + sha256_Update(&(stellar_activeTx.sha256_ctx), data, len); } /* * Displays a summary of the overall transaction */ -void stellar_layoutTransactionSummary(const StellarSignTx *msg) -{ - char str_lines[5][32]; - memzero(str_lines, sizeof(str_lines)); +void stellar_layoutTransactionSummary(const StellarSignTx *msg) { + char str_lines[5][32]; + memzero(str_lines, sizeof(str_lines)); - char str_fee[12]; - char str_num_ops[12]; + char str_fee[12]; + char str_num_ops[12]; - // Will be set to true for some large hashes that don't fit on one screen - uint8_t needs_memo_hash_confirm = 0; + // Will be set to true for some large hashes that don't fit on one screen + uint8_t needs_memo_hash_confirm = 0; - // Format the fee - stellar_format_stroops(msg->fee, str_fee, sizeof(str_fee)); + // Format the fee + stellar_format_stroops(msg->fee, str_fee, sizeof(str_fee)); - strlcpy(str_lines[0], _("Fee: "), sizeof(str_lines[0])); - strlcat(str_lines[0], str_fee, sizeof(str_lines[0])); - strlcat(str_lines[0], _(" XLM"), sizeof(str_lines[0])); + strlcpy(str_lines[0], _("Fee: "), sizeof(str_lines[0])); + strlcat(str_lines[0], str_fee, sizeof(str_lines[0])); + strlcat(str_lines[0], _(" XLM"), sizeof(str_lines[0])); - // add in numOperations - stellar_format_uint32(msg->num_operations, str_num_ops, sizeof(str_num_ops)); + // add in numOperations + stellar_format_uint32(msg->num_operations, str_num_ops, sizeof(str_num_ops)); - strlcat(str_lines[0], _(" ("), sizeof(str_lines[0])); - strlcat(str_lines[0], str_num_ops, sizeof(str_lines[0])); - if (msg->num_operations == 1) { - strlcat(str_lines[0], _(" op)"), sizeof(str_lines[0])); + strlcat(str_lines[0], _(" ("), sizeof(str_lines[0])); + strlcat(str_lines[0], str_num_ops, sizeof(str_lines[0])); + if (msg->num_operations == 1) { + strlcat(str_lines[0], _(" op)"), sizeof(str_lines[0])); + } else { + strlcat(str_lines[0], _(" ops)"), sizeof(str_lines[0])); + } + + // Display full address being used to sign transaction + const char **str_addr_rows = + stellar_lineBreakAddress(stellar_activeTx.signing_pubkey); + + stellar_layoutTransactionDialog(str_lines[0], _("Signing with:"), + str_addr_rows[0], str_addr_rows[1], + str_addr_rows[2]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return; + } + + // Reset lines for displaying memo + memzero(str_lines, sizeof(str_lines)); + + // Memo: none + if (msg->memo_type == 0) { + strlcpy(str_lines[0], _("[No Memo Set]"), sizeof(str_lines[0])); + strlcpy(str_lines[1], _("Important:"), sizeof(str_lines[0])); + strlcpy(str_lines[2], _("Many exchanges require"), sizeof(str_lines[0])); + strlcpy(str_lines[3], _("a memo when depositing."), sizeof(str_lines[0])); + } + // Memo: text + if (msg->memo_type == 1) { + strlcpy(str_lines[0], _("Memo (TEXT)"), sizeof(str_lines[0])); + + // Split 28-character string into two lines of 19 / 9 + // todo: word wrap method? + strlcpy(str_lines[1], (const char *)msg->memo_text, 19 + 1); + strlcpy(str_lines[2], (const char *)(msg->memo_text + 19), 9 + 1); + } + // Memo: ID + if (msg->memo_type == 2) { + strlcpy(str_lines[0], _("Memo (ID)"), sizeof(str_lines[0])); + stellar_format_uint64(msg->memo_id, str_lines[1], sizeof(str_lines[1])); + } + // Memo: hash + if (msg->memo_type == 3) { + needs_memo_hash_confirm = 1; + strlcpy(str_lines[0], _("Memo (HASH)"), sizeof(str_lines[0])); + } + // Memo: return + if (msg->memo_type == 4) { + needs_memo_hash_confirm = 1; + strlcpy(str_lines[0], _("Memo (RETURN)"), sizeof(str_lines[0])); + } + + if (needs_memo_hash_confirm) { + data2hex(msg->memo_hash.bytes + 0, 8, str_lines[1]); + data2hex(msg->memo_hash.bytes + 8, 8, str_lines[2]); + data2hex(msg->memo_hash.bytes + 16, 8, str_lines[3]); + data2hex(msg->memo_hash.bytes + 24, 8, str_lines[4]); + } + + stellar_layoutTransactionDialog(str_lines[0], str_lines[1], str_lines[2], + str_lines[3], str_lines[4]); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + stellar_signingAbort(_("User canceled")); + return; + } + + // Verify timebounds, if present + memzero(str_lines, sizeof(str_lines)); + + // Timebound: lower + if (msg->timebounds_start || msg->timebounds_end) { + time_t timebound; + char str_timebound[32]; + const struct tm *tm; + + timebound = (time_t)msg->timebounds_start; + strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); + if (timebound) { + tm = gmtime(&timebound); + strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); + strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); } else { - strlcat(str_lines[0], _(" ops)"), sizeof(str_lines[0])); + strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); } - // Display full address being used to sign transaction - const char **str_addr_rows = stellar_lineBreakAddress(stellar_activeTx.signing_pubkey); + // Reset for timebound_max + memzero(str_timebound, sizeof(str_timebound)); - stellar_layoutTransactionDialog( - str_lines[0], - _("Signing with:"), - str_addr_rows[0], - str_addr_rows[1], - str_addr_rows[2] - ); + timebound = (time_t)msg->timebounds_end; + strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); + if (timebound) { + tm = gmtime(&timebound); + strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); + strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); + } else { + strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); + } + } + + if (msg->timebounds_start || msg->timebounds_end) { + stellar_layoutTransactionDialog(_("Confirm Time Bounds"), str_lines[0], + str_lines[1], str_lines[2], str_lines[3]); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return; - } - - // Reset lines for displaying memo - memzero(str_lines, sizeof(str_lines)); - - // Memo: none - if (msg->memo_type == 0) { - strlcpy(str_lines[0], _("[No Memo Set]"), sizeof(str_lines[0])); - strlcpy(str_lines[1], _("Important:"), sizeof(str_lines[0])); - strlcpy(str_lines[2], _("Many exchanges require"), sizeof(str_lines[0])); - strlcpy(str_lines[3], _("a memo when depositing."), sizeof(str_lines[0])); - } - // Memo: text - if (msg->memo_type == 1) { - strlcpy(str_lines[0], _("Memo (TEXT)"), sizeof(str_lines[0])); - - // Split 28-character string into two lines of 19 / 9 - // todo: word wrap method? - strlcpy(str_lines[1], (const char*)msg->memo_text, 19 + 1); - strlcpy(str_lines[2], (const char*)(msg->memo_text + 19), 9 + 1); - } - // Memo: ID - if (msg->memo_type == 2) { - strlcpy(str_lines[0], _("Memo (ID)"), sizeof(str_lines[0])); - stellar_format_uint64(msg->memo_id, str_lines[1], sizeof(str_lines[1])); - } - // Memo: hash - if (msg->memo_type == 3) { - needs_memo_hash_confirm = 1; - strlcpy(str_lines[0], _("Memo (HASH)"), sizeof(str_lines[0])); - } - // Memo: return - if (msg->memo_type == 4) { - needs_memo_hash_confirm = 1; - strlcpy(str_lines[0], _("Memo (RETURN)"), sizeof(str_lines[0])); - } - - if (needs_memo_hash_confirm) { - data2hex(msg->memo_hash.bytes + 0, 8, str_lines[1]); - data2hex(msg->memo_hash.bytes + 8, 8, str_lines[2]); - data2hex(msg->memo_hash.bytes + 16, 8, str_lines[3]); - data2hex(msg->memo_hash.bytes + 24, 8, str_lines[4]); - } - - stellar_layoutTransactionDialog( - str_lines[0], - str_lines[1], - str_lines[2], - str_lines[3], - str_lines[4] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return; - } - - // Verify timebounds, if present - memzero(str_lines, sizeof(str_lines)); - - // Timebound: lower - if (msg->timebounds_start || msg->timebounds_end) { - time_t timebound; - char str_timebound[32]; - const struct tm *tm; - - timebound = (time_t)msg->timebounds_start; - strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); - if (timebound) { - tm = gmtime(&timebound); - strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); - strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); - } - else { - strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); - } - - // Reset for timebound_max - memzero(str_timebound, sizeof(str_timebound)); - - timebound = (time_t)msg->timebounds_end; - strlcpy(str_lines[0], _("Valid from:"), sizeof(str_lines[0])); - if (timebound) { - tm = gmtime(&timebound); - strftime(str_timebound, sizeof(str_timebound), "%F %T (UTC)", tm); - strlcpy(str_lines[1], str_timebound, sizeof(str_lines[1])); - } - else { - strlcpy(str_lines[1], _("[no restriction]"), sizeof(str_lines[1])); - } - } - - if (msg->timebounds_start || msg->timebounds_end) { - stellar_layoutTransactionDialog( - _("Confirm Time Bounds"), - str_lines[0], - str_lines[1], - str_lines[2], - str_lines[3] - ); - if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { - stellar_signingAbort(_("User canceled")); - return; - } + stellar_signingAbort(_("User canceled")); + return; } + } } /* @@ -1803,119 +1706,126 @@ void stellar_layoutTransactionSummary(const StellarSignTx *msg) * - Cancel / Next buttons * - Warning message can appear between cancel/next buttons */ -void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step) -{ - // Start with some initial padding and use these to track position as rendering moves down the screen - int offset_x = 1; - int offset_y = 1; - int line_height = 9; +void stellar_layoutSigningDialog(const char *line1, const char *line2, + const char *line3, const char *line4, + const char *line5, uint32_t *address_n, + size_t address_n_count, const char *warning, + bool is_final_step) { + // Start with some initial padding and use these to track position as + // rendering moves down the screen + int offset_x = 1; + int offset_y = 1; + int line_height = 9; - const HDNode *node = stellar_deriveNode(address_n, address_n_count); - if (!node) { - // abort on error - return; - } + const HDNode *node = stellar_deriveNode(address_n, address_n_count); + if (!node) { + // abort on error + return; + } - char str_pubaddr_truncated[12]; // G???? + null - memzero(str_pubaddr_truncated, sizeof(str_pubaddr_truncated)); + char str_pubaddr_truncated[12]; // G???? + null + memzero(str_pubaddr_truncated, sizeof(str_pubaddr_truncated)); - layoutLast = layoutDialogSwipe; - layoutSwipe(); - oledClear(); + layoutLast = layoutDialogSwipe; + layoutSwipe(); + oledClear(); - // Load up public address - char str_pubaddr[56 + 1]; - memzero(str_pubaddr, sizeof(str_pubaddr)); - stellar_publicAddressAsStr(node->public_key + 1, str_pubaddr, sizeof(str_pubaddr)); - memcpy(str_pubaddr_truncated, str_pubaddr, sizeof(str_pubaddr_truncated) - 1); + // Load up public address + char str_pubaddr[56 + 1]; + memzero(str_pubaddr, sizeof(str_pubaddr)); + stellar_publicAddressAsStr(node->public_key + 1, str_pubaddr, + sizeof(str_pubaddr)); + memcpy(str_pubaddr_truncated, str_pubaddr, sizeof(str_pubaddr_truncated) - 1); - // Header - // Ends up as: Signing with GABCDEFGHIJKL - char str_header[32]; - memzero(str_header, sizeof(str_header)); - strlcpy(str_header, _("Signing with "), sizeof(str_header)); - strlcat(str_header, str_pubaddr_truncated, sizeof(str_header)); + // Header + // Ends up as: Signing with GABCDEFGHIJKL + char str_header[32]; + memzero(str_header, sizeof(str_header)); + strlcpy(str_header, _("Signing with "), sizeof(str_header)); + strlcat(str_header, str_pubaddr_truncated, sizeof(str_header)); - oledDrawString(offset_x, offset_y, str_header, FONT_STANDARD); - offset_y += line_height; - // Invert color on header - oledInvert(0, 0, OLED_WIDTH, offset_y - 2); + oledDrawString(offset_x, offset_y, str_header, FONT_STANDARD); + offset_y += line_height; + // Invert color on header + oledInvert(0, 0, OLED_WIDTH, offset_y - 2); - // Dialog contents begin - if (line1) { - oledDrawString(offset_x, offset_y, line1, FONT_STANDARD); - } - offset_y += line_height; - if (line2) { - oledDrawString(offset_x, offset_y, line2, FONT_STANDARD); - } - offset_y += line_height; - if (line3) { - oledDrawString(offset_x, offset_y, line3, FONT_STANDARD); - } - offset_y += line_height; - if (line4) { - oledDrawString(offset_x, offset_y, line4, FONT_STANDARD); - } - offset_y += line_height; - if (line5) { - oledDrawString(offset_x, offset_y, line5, FONT_STANDARD); - } - offset_y += line_height; + // Dialog contents begin + if (line1) { + oledDrawString(offset_x, offset_y, line1, FONT_STANDARD); + } + offset_y += line_height; + if (line2) { + oledDrawString(offset_x, offset_y, line2, FONT_STANDARD); + } + offset_y += line_height; + if (line3) { + oledDrawString(offset_x, offset_y, line3, FONT_STANDARD); + } + offset_y += line_height; + if (line4) { + oledDrawString(offset_x, offset_y, line4, FONT_STANDARD); + } + offset_y += line_height; + if (line5) { + oledDrawString(offset_x, offset_y, line5, FONT_STANDARD); + } + offset_y += line_height; - // Cancel button - oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); - oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, "Cancel", FONT_STANDARD); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth("Cancel", FONT_STANDARD) + 2, OLED_HEIGHT - 1); + // Cancel button + oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); + oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, + "Cancel", FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, + fontCharWidth(FONT_STANDARD, '\x15') + + oledStringWidth("Cancel", FONT_STANDARD) + 2, + OLED_HEIGHT - 1); - // Warnings (drawn centered between the buttons - if (warning) { - oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, warning, FONT_STANDARD); - } + // Warnings (drawn centered between the buttons + if (warning) { + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, warning, + FONT_STANDARD); + } - // Next / sign button - char str_next_label[8]; - if (is_final_step) { - strlcpy(str_next_label, _("SIGN"), sizeof(str_next_label)); - } - else { - strlcpy(str_next_label, _("Next"), sizeof(str_next_label)); - } + // Next / sign button + char str_next_label[8]; + if (is_final_step) { + strlcpy(str_next_label, _("SIGN"), sizeof(str_next_label)); + } else { + strlcpy(str_next_label, _("Next"), sizeof(str_next_label)); + } - oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); - oledDrawString(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, str_next_label, FONT_STANDARD); - oledInvert(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, + OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawString(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - + fontCharWidth(FONT_STANDARD, '\x06') - 3, + OLED_HEIGHT - 8, str_next_label, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(str_next_label, FONT_STANDARD) - + fontCharWidth(FONT_STANDARD, '\x06') - 4, + OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); - oledRefresh(); + oledRefresh(); } /* * Main dialog helper method. Allows displaying 5 lines. * A title showing the account being used to sign is always displayed. */ -void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5) -{ - char str_warning[16]; - memzero(str_warning, sizeof(str_warning)); +void stellar_layoutTransactionDialog(const char *line1, const char *line2, + const char *line3, const char *line4, + const char *line5) { + char str_warning[16]; + memzero(str_warning, sizeof(str_warning)); - if (stellar_activeTx.network_type == 2) { - // Warning: testnet - strlcpy(str_warning, _("WRN:TN"), sizeof(str_warning)); - } - if (stellar_activeTx.network_type == 3) { - // Warning: private network - strlcpy(str_warning, _("WRN:PN"), sizeof(str_warning)); - } + if (stellar_activeTx.network_type == 2) { + // Warning: testnet + strlcpy(str_warning, _("WRN:TN"), sizeof(str_warning)); + } + if (stellar_activeTx.network_type == 3) { + // Warning: private network + strlcpy(str_warning, _("WRN:PN"), sizeof(str_warning)); + } - stellar_layoutSigningDialog( - line1, - line2, - line3, - line4, - line5, - stellar_activeTx.address_n, - stellar_activeTx.address_n_count, - str_warning, - false - ); + stellar_layoutSigningDialog( + line1, line2, line3, line4, line5, stellar_activeTx.address_n, + stellar_activeTx.address_n_count, str_warning, false); } diff --git a/firmware/stellar.h b/firmware/stellar.h index 14ce551f92..92eda1d7b2 100644 --- a/firmware/stellar.h +++ b/firmware/stellar.h @@ -21,11 +21,11 @@ #define __STELLAR_H__ #include +#include "base32.h" #include "bip32.h" #include "crypto.h" -#include "messages.pb.h" #include "fsm.h" -#include "base32.h" +#include "messages.pb.h" // 56 character base-32 encoded string #define STELLAR_ADDRESS_SIZE 56 @@ -35,32 +35,34 @@ #define STELLAR_KEY_SIZE 32 typedef struct { - // BIP32 path to the address being used for signing - uint32_t address_n[10]; - size_t address_n_count; - uint8_t signing_pubkey[32]; + // BIP32 path to the address being used for signing + uint32_t address_n[10]; + size_t address_n_count; + uint8_t signing_pubkey[32]; - // 1 - public network, 2 - official testnet, 3 - other private network - uint8_t network_type; + // 1 - public network, 2 - official testnet, 3 - other private network + uint8_t network_type; - // Total number of operations expected - uint32_t num_operations; - // Number that have been confirmed by the user - uint32_t confirmed_operations; + // Total number of operations expected + uint32_t num_operations; + // Number that have been confirmed by the user + uint32_t confirmed_operations; - // sha256 context that will eventually be signed - SHA256_CTX sha256_ctx; + // sha256 context that will eventually be signed + SHA256_CTX sha256_ctx; } StellarTransaction; // Signing process bool stellar_signingInit(const StellarSignTx *tx); void stellar_signingAbort(const char *reason); -bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account); +bool stellar_confirmSourceAccount(bool has_source_account, + const char *str_account); bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg); bool stellar_confirmPaymentOp(const StellarPaymentOp *msg); bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg); bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg); -bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg); +bool stellar_confirmCreatePassiveOfferOp( + const StellarCreatePassiveOfferOp *msg); bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg); bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg); bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg); @@ -69,14 +71,22 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg); bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg); // Layout -void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); +void stellar_layoutTransactionDialog(const char *line1, const char *line2, + const char *line3, const char *line4, + const char *line5); void stellar_layoutTransactionSummary(const StellarSignTx *msg); -void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); +void stellar_layoutSigningDialog(const char *line1, const char *line2, + const char *line3, const char *line4, + const char *line5, uint32_t *address_n, + size_t address_n_count, const char *warning, + bool is_final_step); // Helpers -const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); +const HDNode *stellar_deriveNode(const uint32_t *address_n, + size_t address_n_count); -size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen); +size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, + size_t outlen); const char **stellar_lineBreakAddress(const uint8_t *addrbytes); void stellar_hashupdate_uint32(uint32_t value); @@ -94,11 +104,13 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature); void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen); void stellar_format_stroops(uint64_t number, char *out, size_t outlen); -void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len); -void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); +void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, + size_t len); +void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, + size_t outlen); bool stellar_validateAddress(const char *str_address); -bool stellar_getAddressBytes(const char* str_address, uint8_t *out_bytes); +bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes); uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); #endif diff --git a/firmware/transaction.c b/firmware/transaction.c index fbfd5c2f72..dd917291a1 100644 --- a/firmware/transaction.c +++ b/firmware/transaction.c @@ -17,28 +17,28 @@ * along with this library. If not, see . */ -#include #include "transaction.h" -#include "ecdsa.h" -#include "coins.h" -#include "util.h" -#include "debug.h" -#include "protect.h" -#include "layout2.h" -#include "crypto.h" -#include "ripemd160.h" -#include "base58.h" +#include #include "address.h" -#include "messages.pb.h" -#include "segwit_addr.h" +#include "base58.h" #include "cash_addr.h" +#include "coins.h" +#include "crypto.h" +#include "debug.h" +#include "ecdsa.h" +#include "layout2.h" #include "memzero.h" +#include "messages.pb.h" +#include "protect.h" +#include "ripemd160.h" +#include "segwit_addr.h" +#include "util.h" #define SEGWIT_VERSION_0 0 #define CASHADDR_P2KH (0) #define CASHADDR_P2SH (8) -#define CASHADDR_160 (0) +#define CASHADDR_160 (0) /* transaction input size (without script): 32 prevhash, 4 idx, 4 sequence */ #define TXSIZE_INPUT 40 @@ -58,798 +58,843 @@ #define TXSIZE_P2PKHASH 25 /* size of a p2sh script (hash, push, 20 scripthash, equal) */ #define TXSIZE_P2SCRIPT 23 -/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block index */ +/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block + * index */ #define TXSIZE_DECRED_WITNESS 16 -static const uint8_t segwit_header[2] = {0,1}; +static const uint8_t segwit_header[2] = {0, 1}; static inline uint32_t op_push_size(uint32_t i) { - if (i < 0x4C) { - return 1; - } - if (i < 0x100) { - return 2; - } - if (i < 0x10000) { - return 3; - } - return 5; + if (i < 0x4C) { + return 1; + } + if (i < 0x100) { + return 2; + } + if (i < 0x10000) { + return 3; + } + return 5; } uint32_t op_push(uint32_t i, uint8_t *out) { - if (i < 0x4C) { - out[0] = i & 0xFF; - return 1; - } - if (i < 0x100) { - out[0] = 0x4C; - out[1] = i & 0xFF; - return 2; - } - if (i < 0x10000) { - out[0] = 0x4D; - out[1] = i & 0xFF; - out[2] = (i >> 8) & 0xFF; - return 3; - } - out[0] = 0x4E; - out[1] = i & 0xFF; - out[2] = (i >> 8) & 0xFF; - out[3] = (i >> 16) & 0xFF; - out[4] = (i >> 24) & 0xFF; - return 5; + if (i < 0x4C) { + out[0] = i & 0xFF; + return 1; + } + if (i < 0x100) { + out[0] = 0x4C; + out[1] = i & 0xFF; + return 2; + } + if (i < 0x10000) { + out[0] = 0x4D; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + return 3; + } + out[0] = 0x4E; + out[1] = i & 0xFF; + out[2] = (i >> 8) & 0xFF; + out[3] = (i >> 16) & 0xFF; + out[4] = (i >> 24) & 0xFF; + return 5; } -bool compute_address(const CoinInfo *coin, - InputScriptType script_type, - const HDNode *node, - bool has_multisig, const MultisigRedeemScriptType *multisig, - char address[MAX_ADDR_SIZE]) { +bool compute_address(const CoinInfo *coin, InputScriptType script_type, + const HDNode *node, bool has_multisig, + const MultisigRedeemScriptType *multisig, + char address[MAX_ADDR_SIZE]) { + uint8_t raw[MAX_ADDR_RAW_SIZE]; + uint8_t digest[32]; + size_t prelen; - uint8_t raw[MAX_ADDR_RAW_SIZE]; - uint8_t digest[32]; - size_t prelen; - - if (has_multisig) { - if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) { - return 0; - } - if (compile_script_multisig_hash(coin, multisig, digest) == 0) { - return 0; - } - if (script_type == InputScriptType_SPENDWITNESS) { - // segwit p2wsh: script hash is single sha256 - if (!coin->has_segwit || !coin->bech32_prefix) { - return 0; - } - if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 32)) { - return 0; - } - } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { - // segwit p2wsh encapsuled in p2sh address - if (!coin->has_segwit) { - return 0; - } - if (!coin->has_address_type_p2sh) { - return 0; - } - raw[0] = 0; // push version - raw[1] = 32; // push 32 bytes - memcpy(raw + 2, digest, 32); // push hash - hasher_Raw(coin->curve->hasher_pubkey, raw, 34, digest); - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - memcpy(raw + prelen, digest, 32); - if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { - return 0; - } - } else if (coin->cashaddr_prefix) { - raw[0] = CASHADDR_P2SH | CASHADDR_160; - ripemd160(digest, 32, raw + 1); - if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { - return 0; - } - } else { - // non-segwit p2sh multisig - prelen = address_prefix_bytes_len(coin->address_type_p2sh); - address_write_prefix_bytes(coin->address_type_p2sh, raw); - ripemd160(digest, 32, raw + prelen); - if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { - return 0; - } - } - } else if (script_type == InputScriptType_SPENDWITNESS) { - // segwit p2wpkh: pubkey hash is ripemd160 of sha256 - if (!coin->has_segwit || !coin->bech32_prefix) { - return 0; - } - ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest); - if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { - return 0; - } - } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { - // segwit p2wpkh embedded in p2sh - if (!coin->has_segwit) { - return 0; - } - if (!coin->has_address_type_p2sh) { - return 0; - } - ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); - } else if (coin->cashaddr_prefix) { - ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_pubkey, raw); - if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { - return 0; - } - } else { - ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); - } - return 1; + if (has_multisig) { + if (cryptoMultisigPubkeyIndex(coin, multisig, node->public_key) < 0) { + return 0; + } + if (compile_script_multisig_hash(coin, multisig, digest) == 0) { + return 0; + } + if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wsh: script hash is single sha256 + if (!coin->has_segwit || !coin->bech32_prefix) { + return 0; + } + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, + digest, 32)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wsh encapsuled in p2sh address + if (!coin->has_segwit) { + return 0; + } + if (!coin->has_address_type_p2sh) { + return 0; + } + raw[0] = 0; // push version + raw[1] = 32; // push 32 bytes + memcpy(raw + 2, digest, 32); // push hash + hasher_Raw(coin->curve->hasher_pubkey, raw, 34, digest); + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + memcpy(raw + prelen, digest, 32); + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, + address, MAX_ADDR_SIZE)) { + return 0; + } + } else if (coin->cashaddr_prefix) { + raw[0] = CASHADDR_P2SH | CASHADDR_160; + ripemd160(digest, 32, raw + 1); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } + } else { + // non-segwit p2sh multisig + prelen = address_prefix_bytes_len(coin->address_type_p2sh); + address_write_prefix_bytes(coin->address_type_p2sh, raw); + ripemd160(digest, 32, raw + prelen); + if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, + address, MAX_ADDR_SIZE)) { + return 0; + } + } + } else if (script_type == InputScriptType_SPENDWITNESS) { + // segwit p2wpkh: pubkey hash is ripemd160 of sha256 + if (!coin->has_segwit || !coin->bech32_prefix) { + return 0; + } + ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest); + if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, + digest, 20)) { + return 0; + } + } else if (script_type == InputScriptType_SPENDP2SHWITNESS) { + // segwit p2wpkh embedded in p2sh + if (!coin->has_segwit) { + return 0; + } + if (!coin->has_address_type_p2sh) { + return 0; + } + ecdsa_get_address_segwit_p2sh( + node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, + coin->curve->hasher_base58, address, MAX_ADDR_SIZE); + } else if (coin->cashaddr_prefix) { + ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, + coin->curve->hasher_pubkey, raw); + if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { + return 0; + } + } else { + ecdsa_get_address(node->public_key, coin->address_type, + coin->curve->hasher_pubkey, coin->curve->hasher_base58, + address, MAX_ADDR_SIZE); + } + return 1; } -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) -{ - memzero(out, sizeof(TxOutputBinType)); - out->amount = in->amount; - out->decred_script_version = in->decred_script_version; - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - size_t addr_raw_len; +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, + TxOutputBinType *out, bool needs_confirm) { + memzero(out, sizeof(TxOutputBinType)); + out->amount = in->amount; + out->decred_script_version = in->decred_script_version; + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + size_t addr_raw_len; - if (in->script_type == OutputScriptType_PAYTOOPRETURN) { - // only 0 satoshi allowed for OP_RETURN - if (in->amount != 0) { - return 0; // failed to compile output - } - if (needs_confirm) { - if (in->op_return_data.size >= 8 && memcmp(in->op_return_data.bytes, "omni", 4) == 0) { // OMNI transaction - layoutConfirmOmni(in->op_return_data.bytes, in->op_return_data.size); - } else { - layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); - } - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; // user aborted - } - } - uint32_t r = 0; - out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN - r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); - memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; - out->script_pubkey.size = r; - return r; - } + if (in->script_type == OutputScriptType_PAYTOOPRETURN) { + // only 0 satoshi allowed for OP_RETURN + if (in->amount != 0) { + return 0; // failed to compile output + } + if (needs_confirm) { + if (in->op_return_data.size >= 8 && + memcmp(in->op_return_data.bytes, "omni", 4) == + 0) { // OMNI transaction + layoutConfirmOmni(in->op_return_data.bytes, in->op_return_data.size); + } else { + layoutConfirmOpReturn(in->op_return_data.bytes, + in->op_return_data.size); + } + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, + false)) { + return -1; // user aborted + } + } + uint32_t r = 0; + out->script_pubkey.bytes[0] = 0x6A; + r++; // OP_RETURN + r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); + memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, + in->op_return_data.size); + r += in->op_return_data.size; + out->script_pubkey.size = r; + return r; + } - if (in->address_n_count > 0) { - static CONFIDENTIAL HDNode node; - InputScriptType input_script_type; + if (in->address_n_count > 0) { + static CONFIDENTIAL HDNode node; + InputScriptType input_script_type; - switch (in->script_type) { - case OutputScriptType_PAYTOADDRESS: - input_script_type = InputScriptType_SPENDADDRESS; - break; - case OutputScriptType_PAYTOMULTISIG: - input_script_type = InputScriptType_SPENDMULTISIG; - break; - case OutputScriptType_PAYTOWITNESS: - input_script_type = InputScriptType_SPENDWITNESS; - break; - case OutputScriptType_PAYTOP2SHWITNESS: - input_script_type = InputScriptType_SPENDP2SHWITNESS; - break; - default: - return 0; // failed to compile output - } - memcpy(&node, root, sizeof(HDNode)); - if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { - return 0; // failed to compile output - } - hdnode_fill_public_key(&node); - if (!compute_address(coin, input_script_type, &node, - in->has_multisig, &in->multisig, - in->address)) { - return 0; // failed to compile output - } - } else if (!in->has_address) { - return 0; // failed to compile output - } + switch (in->script_type) { + case OutputScriptType_PAYTOADDRESS: + input_script_type = InputScriptType_SPENDADDRESS; + break; + case OutputScriptType_PAYTOMULTISIG: + input_script_type = InputScriptType_SPENDMULTISIG; + break; + case OutputScriptType_PAYTOWITNESS: + input_script_type = InputScriptType_SPENDWITNESS; + break; + case OutputScriptType_PAYTOP2SHWITNESS: + input_script_type = InputScriptType_SPENDP2SHWITNESS; + break; + default: + return 0; // failed to compile output + } + memcpy(&node, root, sizeof(HDNode)); + if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, + NULL) == 0) { + return 0; // failed to compile output + } + hdnode_fill_public_key(&node); + if (!compute_address(coin, input_script_type, &node, in->has_multisig, + &in->multisig, in->address)) { + return 0; // failed to compile output + } + } else if (!in->has_address) { + return 0; // failed to compile output + } - addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - size_t prefix_len; - if (coin->has_address_type // p2pkh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) - && address_check_prefix(addr_raw, coin->address_type)) { - out->script_pubkey.bytes[0] = 0x76; // OP_DUP - out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY - out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG - out->script_pubkey.size = 25; - } else if (coin->has_address_type_p2sh // p2sh - && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh)) - && address_check_prefix(addr_raw, coin->address_type_p2sh)) { - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - } else if (coin->cashaddr_prefix - && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) { - if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { - out->script_pubkey.bytes[0] = 0x76; // OP_DUP - out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); - out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY - out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG - out->script_pubkey.size = 25; + addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58, + addr_raw, MAX_ADDR_RAW_SIZE); + size_t prefix_len; + if (coin->has_address_type // p2pkh + && addr_raw_len == + 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) && + address_check_prefix(addr_raw, coin->address_type)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + prefix_len, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; + } else if (coin->has_address_type_p2sh // p2sh + && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len( + coin->address_type_p2sh)) && + address_check_prefix(addr_raw, coin->address_type_p2sh)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else if (coin->cashaddr_prefix && + cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, + in->address)) { + if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0x76; // OP_DUP + out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 3, addr_raw + 1, 20); + out->script_pubkey.bytes[23] = 0x88; // OP_EQUALVERIFY + out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG + out->script_pubkey.size = 25; - } else if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { - out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 - out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes - memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); - out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL - out->script_pubkey.size = 23; - } else { - return 0; - } - } else if (coin->bech32_prefix) { - int witver; - if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { - return 0; - } - // segwit: - // push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i) - // push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40) - out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver; - out->script_pubkey.bytes[1] = addr_raw_len; - memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len); - out->script_pubkey.size = addr_raw_len + 2; - } else { - return 0; - } + } else if (addr_raw_len == 21 && + addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 + out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes + memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); + out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL + out->script_pubkey.size = 23; + } else { + return 0; + } + } else if (coin->bech32_prefix) { + int witver; + if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, + coin->bech32_prefix, in->address)) { + return 0; + } + // segwit: + // push 1 byte version id (opcode OP_0 = 0, OP_i = 80+i) + // push addr_raw (segwit_addr_decode makes sure addr_raw_len is at most 40) + out->script_pubkey.bytes[0] = witver == 0 ? 0 : 80 + witver; + out->script_pubkey.bytes[1] = addr_raw_len; + memcpy(out->script_pubkey.bytes + 2, addr_raw, addr_raw_len); + out->script_pubkey.size = addr_raw_len + 2; + } else { + return 0; + } - if (needs_confirm) { - layoutConfirmOutput(coin, in); - if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { - return -1; // user aborted - } - } + if (needs_confirm) { + layoutConfirmOutput(coin, in); + if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { + return -1; // user aborted + } + } - return out->script_pubkey.size; + return out->script_pubkey.size; } -uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out) -{ - if (coinByAddressType(address_type)) { // valid coin type - out[0] = 0x76; // OP_DUP - out[1] = 0xA9; // OP_HASH_160 - out[2] = 0x14; // pushing 20 bytes - memcpy(out + 3, pubkeyhash, 20); - out[23] = 0x88; // OP_EQUALVERIFY - out[24] = 0xAC; // OP_CHECKSIG - return 25; - } else { - return 0; // unsupported - } +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, + uint8_t *out) { + if (coinByAddressType(address_type)) { // valid coin type + out[0] = 0x76; // OP_DUP + out[1] = 0xA9; // OP_HASH_160 + out[2] = 0x14; // pushing 20 bytes + memcpy(out + 3, pubkeyhash, 20); + out[23] = 0x88; // OP_EQUALVERIFY + out[24] = 0xAC; // OP_CHECKSIG + return 25; + } else { + return 0; // unsupported + } } // if out == NULL just compute the length -uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out) -{ - if (!multisig->has_m) return 0; - const uint32_t m = multisig->m; - const uint32_t n = cryptoMultisigPubkeyCount(multisig); - if (m < 1 || m > 15) return 0; - if (n < 1 || n > 15) return 0; - uint32_t r = 0; - if (out) { - out[r] = 0x50 + m; r++; - for (uint32_t i = 0; i < n; i++) { - out[r] = 33; r++; // OP_PUSH 33 - const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); - if (!pubnode) return 0; - memcpy(out + r, pubnode->public_key, 33); r += 33; - } - out[r] = 0x50 + n; r++; - out[r] = 0xAE; r++; // OP_CHECKMULTISIG - } else { - r = 1 + 34 * n + 2; - } - return r; +uint32_t compile_script_multisig(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *out) { + if (!multisig->has_m) return 0; + const uint32_t m = multisig->m; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; + uint32_t r = 0; + if (out) { + out[r] = 0x50 + m; + r++; + for (uint32_t i = 0; i < n; i++) { + out[r] = 33; + r++; // OP_PUSH 33 + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + memcpy(out + r, pubnode->public_key, 33); + r += 33; + } + out[r] = 0x50 + n; + r++; + out[r] = 0xAE; + r++; // OP_CHECKMULTISIG + } else { + r = 1 + 34 * n + 2; + } + return r; } -uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash) -{ - if (!multisig->has_m) return 0; - const uint32_t m = multisig->m; - const uint32_t n = cryptoMultisigPubkeyCount(multisig); - if (m < 1 || m > 15) return 0; - if (n < 1 || n > 15) return 0; +uint32_t compile_script_multisig_hash(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *hash) { + if (!multisig->has_m) return 0; + const uint32_t m = multisig->m; + const uint32_t n = cryptoMultisigPubkeyCount(multisig); + if (m < 1 || m > 15) return 0; + if (n < 1 || n > 15) return 0; - Hasher hasher; - hasher_Init(&hasher, coin->curve->hasher_script); + Hasher hasher; + hasher_Init(&hasher, coin->curve->hasher_script); - uint8_t d[2]; - d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); - for (uint32_t i = 0; i < n; i++) { - d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 - const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); - if (!pubnode) return 0; - hasher_Update(&hasher, pubnode->public_key, 33); - } - d[0] = 0x50 + n; - d[1] = 0xAE; - hasher_Update(&hasher, d, 2); + uint8_t d[2]; + d[0] = 0x50 + m; + hasher_Update(&hasher, d, 1); + for (uint32_t i = 0; i < n; i++) { + d[0] = 33; + hasher_Update(&hasher, d, 1); // OP_PUSH 33 + const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); + if (!pubnode) return 0; + hasher_Update(&hasher, pubnode->public_key, 33); + } + d[0] = 0x50 + n; + d[1] = 0xAE; + hasher_Update(&hasher, d, 2); - hasher_Final(&hasher, hash); + hasher_Final(&hasher, hash); - return 1; + return 1; } -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out) -{ - uint32_t r = 0; - r += op_push(signature_len + 1, out + r); - memcpy(out + r, signature, signature_len); r += signature_len; - out[r] = sighash; r++; - r += op_push(pubkey_len, out + r); - memcpy(out + r, pubkey, pubkey_len); r += pubkey_len; - return r; +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, + const uint8_t *pubkey, uint32_t pubkey_len, + uint8_t sighash, uint8_t *out) { + uint32_t r = 0; + r += op_push(signature_len + 1, out + r); + memcpy(out + r, signature, signature_len); + r += signature_len; + out[r] = sighash; + r++; + r += op_push(pubkey_len, out + r); + memcpy(out + r, pubkey, pubkey_len); + r += pubkey_len; + return r; } -uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) -{ - uint32_t r = 0; - if (!coin->decred) { - // Decred fixed the off-by-one bug - out[r] = 0x00; r++; - } - for (uint32_t i = 0; i < multisig->signatures_count; i++) { - if (multisig->signatures[i].size == 0) { - continue; - } - r += op_push(multisig->signatures[i].size + 1, out + r); - memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; - out[r] = sighash; r++; - } - uint32_t script_len = compile_script_multisig(coin, multisig, 0); - if (script_len == 0) { - return 0; - } - r += op_push(script_len, out + r); - r += compile_script_multisig(coin, multisig, out + r); - return r; +uint32_t serialize_script_multisig(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t sighash, uint8_t *out) { + uint32_t r = 0; + if (!coin->decred) { + // Decred fixed the off-by-one bug + out[r] = 0x00; + r++; + } + for (uint32_t i = 0; i < multisig->signatures_count; i++) { + if (multisig->signatures[i].size == 0) { + continue; + } + r += op_push(multisig->signatures[i].size + 1, out + r); + memcpy(out + r, multisig->signatures[i].bytes, + multisig->signatures[i].size); + r += multisig->signatures[i].size; + out[r] = sighash; + r++; + } + uint32_t script_len = compile_script_multisig(coin, multisig, 0); + if (script_len == 0) { + return 0; + } + r += op_push(script_len, out + r); + r += compile_script_multisig(coin, multisig, out + r); + return r; } // tx methods -uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) -{ - for (int i = 0; i < 32; i++) { - hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); - } - hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); - return 36; +uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) { + for (int i = 0; i < 32; i++) { + hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); + } + hasher_Update(hasher, (const uint8_t *)&input->prev_index, 4); + return 36; } -uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) -{ - int r = ser_length_hash(hasher, size); - hasher_Update(hasher, data, size); - return r + size; +uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) { + int r = ser_length_hash(hasher, size); + hasher_Update(hasher, data, size); + return r + size; } -uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) -{ - hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); - return 4; +uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) { + hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); + return 4; } -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) -{ - uint32_t r = 0; - hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; - if (decred) { - uint16_t script_version = output->decred_script_version & 0xFFFF; - hasher_Update(hasher, (const uint8_t *)&script_version, 2); r += 2; - } - r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); - return r; +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, + bool decred) { + uint32_t r = 0; + hasher_Update(hasher, (const uint8_t *)&output->amount, 8); + r += 8; + if (decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + hasher_Update(hasher, (const uint8_t *)&script_version, 2); + r += 2; + } + r += tx_script_hash(hasher, output->script_pubkey.size, + output->script_pubkey.bytes); + return r; } -uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) -{ - int r = ser_length(size, out); - memcpy(out + r, data, size); - return r + size; +uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) { + int r = ser_length(size, out); + memcpy(out + r, data, size); + return r + size; } -uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) -{ - int r = 4; - if (tx->overwintered) { - uint32_t ver = tx->version | TX_OVERWINTERED; - memcpy(out, &ver, 4); - memcpy(out + 4, &(tx->version_group_id), 4); - r += 4; - } else { - memcpy(out, &(tx->version), 4); - if (tx->is_segwit) { - memcpy(out + r, segwit_header, 2); - r += 2; - } - } - return r + ser_length(tx->inputs_len, out + r); +uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) { + int r = 4; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + memcpy(out, &ver, 4); + memcpy(out + 4, &(tx->version_group_id), 4); + r += 4; + } else { + memcpy(out, &(tx->version), 4); + if (tx->is_segwit) { + memcpy(out + r, segwit_header, 2); + r += 2; + } + } + return r + ser_length(tx->inputs_len, out + r); } -uint32_t tx_serialize_header_hash(TxStruct *tx) -{ - int r = 4; - if (tx->overwintered) { - uint32_t ver = tx->version | TX_OVERWINTERED; - hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version_group_id), 4); - r += 4; - } else { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); - if (tx->is_segwit) { - hasher_Update(&(tx->hasher), segwit_header, 2); - r += 2; - } - } - return r + ser_length_hash(&(tx->hasher), tx->inputs_len); +uint32_t tx_serialize_header_hash(TxStruct *tx) { + int r = 4; + if (tx->overwintered) { + uint32_t ver = tx->version | TX_OVERWINTERED; + hasher_Update(&(tx->hasher), (const uint8_t *)&ver, 4); + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version_group_id), 4); + r += 4; + } else { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->version), 4); + if (tx->is_segwit) { + hasher_Update(&(tx->hasher), segwit_header, 2); + r += 2; + } + } + return r + ser_length_hash(&(tx->hasher), tx->inputs_len); } -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header(tx, out + r); - } - for (int i = 0; i < 32; i++) { - *(out + r + i) = input->prev_hash.bytes[31 - i]; - } - r += 32; - memcpy(out + r, &input->prev_index, 4); r += 4; - if (tx->is_decred) { - uint8_t tree = input->decred_tree & 0xFF; - out[r++] = tree; - } else { - r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); - } - memcpy(out + r, &input->sequence, 4); r += 4; +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, + uint8_t *out) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header(tx, out + r); + } + for (int i = 0; i < 32; i++) { + *(out + r + i) = input->prev_hash.bytes[31 - i]; + } + r += 32; + memcpy(out + r, &input->prev_index, 4); + r += 4; + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + out[r++] = tree; + } else { + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, + out + r); + } + memcpy(out + r, &input->sequence, 4); + r += 4; - tx->have_inputs++; - tx->size += r; + tx->have_inputs++; + tx->size += r; - return r; + return r; } -uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header_hash(tx); - } - r += tx_prevout_hash(&(tx->hasher), input); - if (tx->is_decred) { - uint8_t tree = input->decred_tree & 0xFF; - hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); r++; - } else { - r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); - } - r += tx_sequence_hash(&(tx->hasher), input); +uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + r += tx_prevout_hash(&(tx->hasher), input); + if (tx->is_decred) { + uint8_t tree = input->decred_tree & 0xFF; + hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); + r++; + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, + input->script_sig.bytes); + } + r += tx_sequence_hash(&(tx->hasher), input); - tx->have_inputs++; - tx->size += r; + tx->have_inputs++; + tx->size += r; - return r; + return r; } -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) -{ - static const uint64_t amount = 0; - static const uint32_t block_height = 0x00000000; - static const uint32_t block_index = 0xFFFFFFFF; +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, + uint8_t *out) { + static const uint64_t amount = 0; + static const uint32_t block_height = 0x00000000; + static const uint32_t block_index = 0xFFFFFFFF; - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += ser_length(tx->inputs_len, out + r); - } - memcpy(out + r, &amount, 8); r += 8; - memcpy(out + r, &block_height, 4); r += 4; - memcpy(out + r, &block_index, 4); r += 4; - r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += ser_length(tx->inputs_len, out + r); + } + memcpy(out + r, &amount, 8); + r += 8; + memcpy(out + r, &block_height, 4); + r += 4; + memcpy(out + r, &block_index, 4); + r += 4; + r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, + out + r); - tx->have_inputs++; - tx->size += r; + tx->have_inputs++; + tx->size += r; - return r; + return r; } -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) -{ - if (tx->have_inputs >= tx->inputs_len) { - // already got all inputs - return 0; - } - uint32_t r = 0; - if (tx->have_inputs == 0) { - r += tx_serialize_header_hash(tx); - } - if (input == NULL) { - r += ser_length_hash(&(tx->hasher), 0); - } else { - r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); - } +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, + const TxInputType *input) { + if (tx->have_inputs >= tx->inputs_len) { + // already got all inputs + return 0; + } + uint32_t r = 0; + if (tx->have_inputs == 0) { + r += tx_serialize_header_hash(tx); + } + if (input == NULL) { + r += ser_length_hash(&(tx->hasher), 0); + } else { + r += tx_script_hash(&(tx->hasher), input->script_sig.size, + input->script_sig.bytes); + } - tx->have_inputs++; - tx->size += r; + tx->have_inputs++; + tx->size += r; - return r; + return r; } -uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) -{ - return ser_length(tx->outputs_len, out); +uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) { + return ser_length(tx->outputs_len, out); } -uint32_t tx_serialize_middle_hash(TxStruct *tx) -{ - return ser_length_hash(&(tx->hasher), tx->outputs_len); +uint32_t tx_serialize_middle_hash(TxStruct *tx) { + return ser_length_hash(&(tx->hasher), tx->outputs_len); } -uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) -{ - memcpy(out, &(tx->lock_time), 4); - if (tx->overwintered) { - if (tx->version == 3) { - memcpy(out + 4, &(tx->expiry), 4); - out[8] = 0x00; // nJoinSplit - return 9; - } else - if (tx->version == 4) { - memcpy(out + 4, &(tx->expiry), 4); - memzero(out + 8, 8); // valueBalance - out[16] = 0x00; // nShieldedSpend - out[17] = 0x00; // nShieldedOutput - out[18] = 0x00; // nJoinSplit - return 19; - } - } - if (tx->is_decred) { - memcpy(out + 4, &(tx->expiry), 4); - return 8; - } - return 4; +uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) { + memcpy(out, &(tx->lock_time), 4); + if (tx->overwintered) { + if (tx->version == 3) { + memcpy(out + 4, &(tx->expiry), 4); + out[8] = 0x00; // nJoinSplit + return 9; + } else if (tx->version == 4) { + memcpy(out + 4, &(tx->expiry), 4); + memzero(out + 8, 8); // valueBalance + out[16] = 0x00; // nShieldedSpend + out[17] = 0x00; // nShieldedOutput + out[18] = 0x00; // nJoinSplit + return 19; + } + } + if (tx->is_decred) { + memcpy(out + 4, &(tx->expiry), 4); + return 8; + } + return 4; } -uint32_t tx_serialize_footer_hash(TxStruct *tx) -{ - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); - if (tx->overwintered) { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); - hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit - return 9; - } - if (tx->is_decred) { - hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); - return 8; - } - return 4; +uint32_t tx_serialize_footer_hash(TxStruct *tx) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); + if (tx->overwintered) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); + hasher_Update(&(tx->hasher), (const uint8_t *)"\x00", 1); // nJoinSplit + return 9; + } + if (tx->is_decred) { + hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); + return 8; + } + return 4; } -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs >= tx->outputs_len) { - // already got all outputs - return 0; - } - uint32_t r = 0; - if (tx->have_outputs == 0) { - r += tx_serialize_middle(tx, out + r); - } - memcpy(out + r, &output->amount, 8); r += 8; - if (tx->is_decred) { - uint16_t script_version = output->decred_script_version & 0xFFFF; - memcpy(out + r, &script_version, 2); r += 2; - } - r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); - tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len - && !tx->is_segwit) { - r += tx_serialize_footer(tx, out + r); - } - tx->size += r; - return r; +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, + uint8_t *out) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle(tx, out + r); + } + memcpy(out + r, &output->amount, 8); + r += 8; + if (tx->is_decred) { + uint16_t script_version = output->decred_script_version & 0xFFFF; + memcpy(out + r, &script_version, 2); + r += 2; + } + r += tx_serialize_script(output->script_pubkey.size, + output->script_pubkey.bytes, out + r); + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { + r += tx_serialize_footer(tx, out + r); + } + tx->size += r; + return r; } -uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs >= tx->outputs_len) { - // already got all outputs - return 0; - } - uint32_t r = 0; - if (tx->have_outputs == 0) { - r += tx_serialize_middle_hash(tx); - } - r += tx_output_hash(&(tx->hasher), output, tx->is_decred); - tx->have_outputs++; - if (tx->have_outputs == tx->outputs_len - && !tx->is_segwit) { - r += tx_serialize_footer_hash(tx); - } - tx->size += r; - return r; +uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs >= tx->outputs_len) { + // already got all outputs + return 0; + } + uint32_t r = 0; + if (tx->have_outputs == 0) { + r += tx_serialize_middle_hash(tx); + } + r += tx_output_hash(&(tx->hasher), output, tx->is_decred); + tx->have_outputs++; + if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) { + r += tx_serialize_footer_hash(tx); + } + tx->size += r; + return r; } -uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen) -{ - if (tx->have_inputs < tx->inputs_len) { - // not all inputs provided - return 0; - } - if (tx->have_outputs < tx->outputs_len) { - // not all inputs provided - return 0; - } - if (tx->extra_data_received + datalen > tx->extra_data_len) { - // we are receiving too much data - return 0; - } - hasher_Update(&(tx->hasher), data, datalen); - tx->extra_data_received += datalen; - tx->size += datalen; - return datalen; +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, + uint32_t datalen) { + if (tx->have_inputs < tx->inputs_len) { + // not all inputs provided + return 0; + } + if (tx->have_outputs < tx->outputs_len) { + // not all inputs provided + return 0; + } + if (tx->extra_data_received + datalen > tx->extra_data_len) { + // we are receiving too much data + return 0; + } + hasher_Update(&(tx->hasher), data, datalen); + tx->extra_data_received += datalen; + tx->size += datalen; + return datalen; } -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id) -{ - tx->inputs_len = inputs_len; - tx->outputs_len = outputs_len; - tx->version = version; - tx->lock_time = lock_time; - tx->expiry = expiry; - tx->have_inputs = 0; - tx->have_outputs = 0; - tx->extra_data_len = extra_data_len; - tx->extra_data_received = 0; - tx->size = 0; - tx->is_segwit = false; - tx->is_decred = false; - tx->overwintered = overwintered; - tx->version_group_id = version_group_id; - hasher_Init(&(tx->hasher), hasher_sign); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, + uint32_t version, uint32_t lock_time, uint32_t expiry, + uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, + uint32_t version_group_id) { + tx->inputs_len = inputs_len; + tx->outputs_len = outputs_len; + tx->version = version; + tx->lock_time = lock_time; + tx->expiry = expiry; + tx->have_inputs = 0; + tx->have_outputs = 0; + tx->extra_data_len = extra_data_len; + tx->extra_data_received = 0; + tx->size = 0; + tx->is_segwit = false; + tx->is_decred = false; + tx->overwintered = overwintered; + tx->version_group_id = version_group_id; + hasher_Init(&(tx->hasher), hasher_sign); } -void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) -{ - hasher_Final(&(t->hasher), hash); - if (!reverse) return; - for (uint8_t i = 0; i < 16; i++) { - uint8_t k = hash[31 - i]; - hash[31 - i] = hash[i]; - hash[i] = k; - } +void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) { + hasher_Final(&(t->hasher), hash); + if (!reverse) return; + for (uint8_t i = 0; i < 16; i++) { + uint8_t k = hash[31 - i]; + hash[31 - i] = hash[i]; + hash[i] = k; + } } static uint32_t tx_input_script_size(const TxInputType *txinput) { - uint32_t input_script_size; - if (txinput->has_multisig) { - uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT - + txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); - input_script_size = 1 // the OP_FALSE bug in multisig - + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) - + op_push_size(multisig_script_size) + multisig_script_size; - } else { - input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); - } + uint32_t input_script_size; + if (txinput->has_multisig) { + uint32_t multisig_script_size = + TXSIZE_MULTISIGSCRIPT + + txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); + input_script_size = 1 // the OP_FALSE bug in multisig + + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) + + op_push_size(multisig_script_size) + + multisig_script_size; + } else { + input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); + } - return input_script_size; + return input_script_size; } uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) { - if (coin->decred) { - return 4 * (TXSIZE_INPUT + 1); // Decred tree - } + if (coin->decred) { + return 4 * (TXSIZE_INPUT + 1); // Decred tree + } - uint32_t input_script_size = tx_input_script_size(txinput); - uint32_t weight = 4 * TXSIZE_INPUT; - if (txinput->script_type == InputScriptType_SPENDADDRESS - || txinput->script_type == InputScriptType_SPENDMULTISIG) { - input_script_size += ser_length_size(input_script_size); - weight += 4 * input_script_size; - } else if (txinput->script_type == InputScriptType_SPENDWITNESS - || txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { - weight += 4 * (2 + (txinput->has_multisig - ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH)); - } else { - weight += 4; // empty input script - } - weight += input_script_size; // discounted witness - } - return weight; + uint32_t input_script_size = tx_input_script_size(txinput); + uint32_t weight = 4 * TXSIZE_INPUT; + if (txinput->script_type == InputScriptType_SPENDADDRESS || + txinput->script_type == InputScriptType_SPENDMULTISIG) { + input_script_size += ser_length_size(input_script_size); + weight += 4 * input_script_size; + } else if (txinput->script_type == InputScriptType_SPENDWITNESS || + txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { + weight += 4 * (2 + (txinput->has_multisig ? TXSIZE_WITNESSSCRIPT + : TXSIZE_WITNESSPKHASH)); + } else { + weight += 4; // empty input script + } + weight += input_script_size; // discounted witness + } + return weight; } uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { - uint32_t output_script_size = 0; - if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { - output_script_size = 1 + op_push_size(txoutput->op_return_data.size) - + txoutput->op_return_data.size; - } else if (txoutput->address_n_count > 0) { - if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { - output_script_size = txoutput->has_multisig - ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; - } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { - output_script_size = TXSIZE_P2SCRIPT; - } else { - output_script_size = txoutput->has_multisig - ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; - } - } else { - uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; - int witver; - size_t addr_raw_len; - if (coin->cashaddr_prefix - && cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) { - if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { - output_script_size = TXSIZE_P2PKHASH; - } else if (addr_raw_len == 21 - && addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { - output_script_size = TXSIZE_P2SCRIPT; - } - } else if (coin->bech32_prefix - && segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { - output_script_size = 2 + addr_raw_len; - } else { - addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); - if (coin->has_address_type - && address_check_prefix(addr_raw, coin->address_type)) { - output_script_size = TXSIZE_P2PKHASH; - } else if (coin->has_address_type_p2sh - && address_check_prefix(addr_raw, coin->address_type_p2sh)) { - output_script_size = TXSIZE_P2SCRIPT; - } - } - } - output_script_size += ser_length_size(output_script_size); + uint32_t output_script_size = 0; + if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { + output_script_size = 1 + op_push_size(txoutput->op_return_data.size) + + txoutput->op_return_data.size; + } else if (txoutput->address_n_count > 0) { + if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { + output_script_size = + txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; + } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { + output_script_size = TXSIZE_P2SCRIPT; + } else { + output_script_size = + txoutput->has_multisig ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; + } + } else { + uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; + int witver; + size_t addr_raw_len; + if (coin->cashaddr_prefix && + cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, + txoutput->address)) { + if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (addr_raw_len == 21 && + addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } else if (coin->bech32_prefix && + segwit_addr_decode(&witver, addr_raw, &addr_raw_len, + coin->bech32_prefix, txoutput->address)) { + output_script_size = 2 + addr_raw_len; + } else { + addr_raw_len = + base58_decode_check(txoutput->address, coin->curve->hasher_base58, + addr_raw, MAX_ADDR_RAW_SIZE); + if (coin->has_address_type && + address_check_prefix(addr_raw, coin->address_type)) { + output_script_size = TXSIZE_P2PKHASH; + } else if (coin->has_address_type_p2sh && + address_check_prefix(addr_raw, coin->address_type_p2sh)) { + output_script_size = TXSIZE_P2SCRIPT; + } + } + } + output_script_size += ser_length_size(output_script_size); - uint32_t size = TXSIZE_OUTPUT; - if (coin->decred) { - size += 2; // Decred script version - } + uint32_t size = TXSIZE_OUTPUT; + if (coin->decred) { + size += 2; // Decred script version + } - return 4 * (size + output_script_size); + return 4 * (size + output_script_size); } uint32_t tx_decred_witness_weight(const TxInputType *txinput) { - uint32_t input_script_size = tx_input_script_size(txinput); - uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; + uint32_t input_script_size = tx_input_script_size(txinput); + uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + + input_script_size; - return 4 * size; + return 4 * size; } diff --git a/firmware/transaction.h b/firmware/transaction.h index 5180a58e5a..3a13f351d3 100644 --- a/firmware/transaction.h +++ b/firmware/transaction.h @@ -22,62 +22,84 @@ #include #include -#include "sha2.h" #include "bip32.h" #include "coins.h" #include "hasher.h" #include "messages-bitcoin.pb.h" +#include "sha2.h" #define TX_OVERWINTERED 0x80000000 typedef struct { - uint32_t inputs_len; - uint32_t outputs_len; + uint32_t inputs_len; + uint32_t outputs_len; - uint32_t version; - uint32_t version_group_id; - uint32_t lock_time; - uint32_t expiry; - bool is_segwit; - bool is_decred; + uint32_t version; + uint32_t version_group_id; + uint32_t lock_time; + uint32_t expiry; + bool is_segwit; + bool is_decred; - uint32_t have_inputs; - uint32_t have_outputs; + uint32_t have_inputs; + uint32_t have_outputs; - bool overwintered; - uint32_t extra_data_len; - uint32_t extra_data_received; + bool overwintered; + uint32_t extra_data_len; + uint32_t extra_data_received; - uint32_t size; + uint32_t size; - Hasher hasher; + Hasher hasher; } TxStruct; -bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); -uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); -uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out); -uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); -uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); -uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); -int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); +bool compute_address(const CoinInfo *coin, InputScriptType script_type, + const HDNode *node, bool has_multisig, + const MultisigRedeemScriptType *multisig, + char address[MAX_ADDR_SIZE]); +uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, + uint8_t *out); +uint32_t compile_script_multisig(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *out); +uint32_t compile_script_multisig_hash(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t *hash); +uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, + const uint8_t *pubkey, uint32_t pubkey_len, + uint8_t sighash, uint8_t *out); +uint32_t serialize_script_multisig(const CoinInfo *coin, + const MultisigRedeemScriptType *multisig, + uint8_t sighash, uint8_t *out); +int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, + TxOutputBinType *out, bool needs_confirm); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); -uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); +uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, + bool decred); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); -uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); -uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); -uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); +uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, + uint8_t *out); +uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, + uint8_t *out); +uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, + uint8_t *out); -void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id); +void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, + uint32_t version, uint32_t lock_time, uint32_t expiry, + uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, + uint32_t version_group_id); uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); -uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); -uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); +uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, + uint32_t datalen); +uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, + const TxInputType *input); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput); diff --git a/firmware/trezor.c b/firmware/trezor.c index 7a68329324..b112a87e70 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -17,140 +17,143 @@ * along with this library. If not, see . */ -#include "common.h" #include "trezor.h" -#include "oled.h" #include "bitmaps.h" -#include "util.h" -#include "usb.h" -#include "setup.h" +#include "bl_check.h" +#include "buttons.h" +#include "common.h" #include "config.h" +#include "gettext.h" #include "layout.h" #include "layout2.h" -#include "rng.h" -#include "timer.h" -#include "buttons.h" -#include "gettext.h" -#include "bl_check.h" #include "memzero.h" +#include "oled.h" +#include "rng.h" +#include "setup.h" +#include "timer.h" +#include "usb.h" +#include "util.h" #if !EMULATOR -#include "otp.h" #include +#include "otp.h" #endif /* Screen timeout */ uint32_t system_millis_lock_start; -void check_lock_screen(void) -{ - buttonUpdate(); +void check_lock_screen(void) { + buttonUpdate(); - // wake from screensaver on any button - if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { - layoutHome(); - return; - } + // wake from screensaver on any button + if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { + layoutHome(); + return; + } - // button held for long enough (2 seconds) - if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { + // button held for long enough (2 seconds) + if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { + layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL, + _("Do you really want to"), _("lock your TREZOR?"), NULL, NULL, + NULL, NULL); - layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL, _("Do you really want to"), _("lock your TREZOR?"), NULL, NULL, NULL, NULL); + // wait until NoButton is released + usbTiny(1); + do { + usbSleep(5); + buttonUpdate(); + } while (!button.NoUp); - // wait until NoButton is released - usbTiny(1); - do { - usbSleep(5); - buttonUpdate(); - } while (!button.NoUp); + // wait for confirmation/cancellation of the dialog + do { + usbSleep(5); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + usbTiny(0); - // wait for confirmation/cancellation of the dialog - do { - usbSleep(5); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - usbTiny(0); + if (button.YesUp) { + // lock the screen + session_clear(true); + layoutScreensaver(); + } else { + // resume homescreen + layoutHome(); + } + } - if (button.YesUp) { - // lock the screen - session_clear(true); - layoutScreensaver(); - } else { - // resume homescreen - layoutHome(); - } - } - - // if homescreen is shown for too long - if (layoutLast == layoutHome) { - if ((timer_ms() - system_millis_lock_start) >= config_getAutoLockDelayMs()) { - // lock the screen - session_clear(true); - layoutScreensaver(); - } - } + // if homescreen is shown for too long + if (layoutLast == layoutHome) { + if ((timer_ms() - system_millis_lock_start) >= + config_getAutoLockDelayMs()) { + // lock the screen + session_clear(true); + layoutScreensaver(); + } + } } -static void collect_hw_entropy(bool privileged) -{ +static void collect_hw_entropy(bool privileged) { #if EMULATOR - (void)privileged; - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); + (void)privileged; + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); #else - if (privileged) { - desig_get_unique_id((uint32_t *)HW_ENTROPY_DATA); - // set entropy in the OTP randomness block - if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { - uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; - random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); - flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE); - flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS); - } - // collect entropy from OTP randomness block - flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, FLASH_OTP_BLOCK_SIZE); - } else { - // unprivileged mode => use fixed HW_ENTROPY - memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); - } + if (privileged) { + desig_get_unique_id((uint32_t *)HW_ENTROPY_DATA); + // set entropy in the OTP randomness block + if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { + uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; + random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); + flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, + FLASH_OTP_BLOCK_SIZE); + flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS); + } + // collect entropy from OTP randomness block + flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, + FLASH_OTP_BLOCK_SIZE); + } else { + // unprivileged mode => use fixed HW_ENTROPY + memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); + } #endif } -int main(void) -{ +int main(void) { #ifndef APPVER - setup(); - __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks - oledInit(); + setup(); + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks + oledInit(); #else - check_bootloader(); - setupApp(); - __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks + check_bootloader(); + setupApp(); + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks #endif - if (!is_mode_unprivileged()) { - collect_hw_entropy(true); - timer_init(); + if (!is_mode_unprivileged()) { + collect_hw_entropy(true); + timer_init(); #ifdef APPVER - // enable MPU (Memory Protection Unit) - mpu_config_firmware(); + // enable MPU (Memory Protection Unit) + mpu_config_firmware(); #endif - } else { - collect_hw_entropy(false); - } + } else { + collect_hw_entropy(false); + } #if DEBUG_LINK - oledSetDebugLink(1); - config_wipe(); + oledSetDebugLink(1); + config_wipe(); #endif - oledDrawBitmap(40, 0, &bmp_logo64); - oledRefresh(); + oledDrawBitmap(40, 0, &bmp_logo64); + oledRefresh(); - config_init(); - layoutHome(); - usbInit(); - for (;;) { - usbPoll(); - check_lock_screen(); - } + config_init(); + layoutHome(); + usbInit(); + for (;;) { + usbPoll(); + check_lock_screen(); + } - return 0; + return 0; } diff --git a/firmware/u2f.c b/firmware/u2f.c index 1b856aa707..1c799dc495 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -17,32 +17,32 @@ * along with this library. If not, see . */ -#include #include +#include -#include "debug.h" -#include "config.h" #include "bip32.h" -#include "layout2.h" -#include "usb.h" #include "buttons.h" -#include "trezor.h" +#include "config.h" #include "curves.h" +#include "debug.h" +#include "gettext.h" +#include "hmac.h" +#include "layout2.h" +#include "memzero.h" #include "nist256p1.h" #include "rng.h" -#include "hmac.h" +#include "trezor.h" +#include "usb.h" #include "util.h" -#include "gettext.h" -#include "memzero.h" +#include "u2f.h" #include "u2f/u2f.h" #include "u2f/u2f_hid.h" #include "u2f/u2f_keys.h" #include "u2f_knownapps.h" -#include "u2f.h" // About 1/2 Second according to values used in protect.c -#define U2F_TIMEOUT (800000/2) +#define U2F_TIMEOUT (800000 / 2) #define U2F_OUT_PKT_BUFFER_LEN 130 // Initialise without a cid @@ -61,44 +61,44 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE]; #define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t)) // Defined as UsbSignHandler.BOGUS_APP_ID_HASH -// in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 +// in +// https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 #define BOGUS_APPID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" // Auth/Register request state machine typedef enum { - INIT = 0, - AUTH = 10, - AUTH_PASS = 11, - REG = 20, - REG_PASS = 21 + INIT = 0, + AUTH = 10, + AUTH_PASS = 11, + REG = 20, + REG_PASS = 21 } U2F_STATE; static U2F_STATE last_req_state = INIT; typedef struct { - uint8_t reserved; - uint8_t appId[U2F_APPID_SIZE]; - uint8_t chal[U2F_CHAL_SIZE]; - uint8_t keyHandle[KEY_HANDLE_LEN]; - uint8_t pubKey[U2F_PUBKEY_LEN]; + uint8_t reserved; + uint8_t appId[U2F_APPID_SIZE]; + uint8_t chal[U2F_CHAL_SIZE]; + uint8_t keyHandle[KEY_HANDLE_LEN]; + uint8_t pubKey[U2F_PUBKEY_LEN]; } U2F_REGISTER_SIG_STR; typedef struct { - uint8_t appId[U2F_APPID_SIZE]; - uint8_t flags; - uint8_t ctr[4]; - uint8_t chal[U2F_CHAL_SIZE]; + uint8_t appId[U2F_APPID_SIZE]; + uint8_t flags; + uint8_t ctr[4]; + uint8_t chal[U2F_CHAL_SIZE]; } U2F_AUTHENTICATE_SIG_STR; static uint32_t dialog_timeout = 0; -uint32_t next_cid(void) -{ - // extremely unlikely but hey - do { - cid = random32(); - } while (cid == 0 || cid == CID_BROADCAST); - return cid; +uint32_t next_cid(void) { + // extremely unlikely but hey + do { + cid = random32(); + } while (cid == 0 || cid == CID_BROADCAST); + return cid; } // https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html#message--and-packet-structure @@ -107,667 +107,649 @@ uint32_t next_cid(void) // the maximum message payload length is 64 - 7 + 128 * (64 - 5) = 7609 bytes. #define U2F_MAXIMUM_PAYLOAD_LENGTH 7609 typedef struct { - uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH]; - uint8_t *buf_ptr; - uint32_t len; - uint8_t seq; - uint8_t cmd; + uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH]; + uint8_t *buf_ptr; + uint32_t len; + uint8_t seq; + uint8_t cmd; } U2F_ReadBuffer; U2F_ReadBuffer *reader; -void u2fhid_read(char tiny, const U2FHID_FRAME *f) -{ - // Always handle init packets directly - if (f->init.cmd == U2FHID_INIT) { - u2fhid_init(f); - if (tiny && reader && f->cid == cid) { - // abort current channel - reader->cmd = 0; - reader->len = 0; - reader->seq = 255; - } - return; - } +void u2fhid_read(char tiny, const U2FHID_FRAME *f) { + // Always handle init packets directly + if (f->init.cmd == U2FHID_INIT) { + u2fhid_init(f); + if (tiny && reader && f->cid == cid) { + // abort current channel + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + } + return; + } - if (tiny) { - // read continue packet - if (reader == 0 || cid != f->cid) { - send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY); - return; - } + if (tiny) { + // read continue packet + if (reader == 0 || cid != f->cid) { + send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY); + return; + } - if ((f->type & TYPE_INIT) && reader->seq == 255) { - u2fhid_init_cmd(f); - return; - } + if ((f->type & TYPE_INIT) && reader->seq == 255) { + u2fhid_init_cmd(f); + return; + } - if (reader->seq != f->cont.seq) { - send_u2fhid_error(f->cid, ERR_INVALID_SEQ); - reader->cmd = 0; - reader->len = 0; - reader->seq = 255; - return; - } + if (reader->seq != f->cont.seq) { + send_u2fhid_error(f->cid, ERR_INVALID_SEQ); + reader->cmd = 0; + reader->len = 0; + reader->seq = 255; + return; + } - // check out of bounds - if ((reader->buf_ptr - reader->buf) >= (signed) reader->len - || (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) - return; - reader->seq++; - memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); - reader->buf_ptr += sizeof(f->cont.data); - return; - } + // check out of bounds + if ((reader->buf_ptr - reader->buf) >= (signed)reader->len || + (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > + (signed)sizeof(reader->buf)) + return; + reader->seq++; + memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); + reader->buf_ptr += sizeof(f->cont.data); + return; + } - u2fhid_read_start(f); + u2fhid_read_start(f); } void u2fhid_init_cmd(const U2FHID_FRAME *f) { - reader->seq = 0; - reader->buf_ptr = reader->buf; - reader->len = MSG_LEN(*f); - reader->cmd = f->type; - memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); - reader->buf_ptr += sizeof(f->init.data); - cid = f->cid; + reader->seq = 0; + reader->buf_ptr = reader->buf; + reader->len = MSG_LEN(*f); + reader->cmd = f->type; + memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); + reader->buf_ptr += sizeof(f->init.data); + cid = f->cid; } void u2fhid_read_start(const U2FHID_FRAME *f) { - U2F_ReadBuffer readbuffer; - memzero(&readbuffer, sizeof(readbuffer)); + U2F_ReadBuffer readbuffer; + memzero(&readbuffer, sizeof(readbuffer)); - if (!(f->type & TYPE_INIT)) { - return; - } + if (!(f->type & TYPE_INIT)) { + return; + } - // Broadcast is reserved for init - if (f->cid == CID_BROADCAST || f->cid == 0) { - send_u2fhid_error(f->cid, ERR_INVALID_CID); - return; - } + // Broadcast is reserved for init + if (f->cid == CID_BROADCAST || f->cid == 0) { + send_u2fhid_error(f->cid, ERR_INVALID_CID); + return; + } - if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) { - send_u2fhid_error(f->cid, ERR_INVALID_LEN); - return; - } + if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) { + send_u2fhid_error(f->cid, ERR_INVALID_LEN); + return; + } - reader = &readbuffer; - u2fhid_init_cmd(f); + reader = &readbuffer; + u2fhid_init_cmd(f); - usbTiny(1); - for(;;) { - // Do we need to wait for more data - while ((reader->buf_ptr - reader->buf) < (signed)reader->len) { - uint8_t lastseq = reader->seq; - uint8_t lastcmd = reader->cmd; - int counter = U2F_TIMEOUT; - while (reader->seq == lastseq && reader->cmd == lastcmd) { - if (counter-- == 0) { - // timeout - send_u2fhid_error(cid, ERR_MSG_TIMEOUT); - cid = 0; - reader = 0; - usbTiny(0); - layoutHome(); - return; - } - usbPoll(); - } - } + usbTiny(1); + for (;;) { + // Do we need to wait for more data + while ((reader->buf_ptr - reader->buf) < (signed)reader->len) { + uint8_t lastseq = reader->seq; + uint8_t lastcmd = reader->cmd; + int counter = U2F_TIMEOUT; + while (reader->seq == lastseq && reader->cmd == lastcmd) { + if (counter-- == 0) { + // timeout + send_u2fhid_error(cid, ERR_MSG_TIMEOUT); + cid = 0; + reader = 0; + usbTiny(0); + layoutHome(); + return; + } + usbPoll(); + } + } - // We have all the data - switch (reader->cmd) { - case 0: - // message was aborted by init - break; - case U2FHID_PING: - u2fhid_ping(reader->buf, reader->len); - break; - case U2FHID_MSG: - u2fhid_msg((APDU *)reader->buf, reader->len); - break; - case U2FHID_WINK: - u2fhid_wink(reader->buf, reader->len); - break; - default: - send_u2fhid_error(cid, ERR_INVALID_CMD); - break; - } + // We have all the data + switch (reader->cmd) { + case 0: + // message was aborted by init + break; + case U2FHID_PING: + u2fhid_ping(reader->buf, reader->len); + break; + case U2FHID_MSG: + u2fhid_msg((APDU *)reader->buf, reader->len); + break; + case U2FHID_WINK: + u2fhid_wink(reader->buf, reader->len); + break; + default: + send_u2fhid_error(cid, ERR_INVALID_CMD); + break; + } - // wait for next commmand/ button press - reader->cmd = 0; - reader->seq = 255; - while (dialog_timeout > 0 && reader->cmd == 0) { - dialog_timeout--; - usbPoll(); // may trigger new request - buttonUpdate(); - if (button.YesUp && - (last_req_state == AUTH || last_req_state == REG)) { - last_req_state++; - // standard requires to remember button press for 10 seconds. - dialog_timeout = 10 * U2F_TIMEOUT; - } - } + // wait for next commmand/ button press + reader->cmd = 0; + reader->seq = 255; + while (dialog_timeout > 0 && reader->cmd == 0) { + dialog_timeout--; + usbPoll(); // may trigger new request + buttonUpdate(); + if (button.YesUp && (last_req_state == AUTH || last_req_state == REG)) { + last_req_state++; + // standard requires to remember button press for 10 seconds. + dialog_timeout = 10 * U2F_TIMEOUT; + } + } - if (reader->cmd == 0) { - last_req_state = INIT; - cid = 0; - reader = 0; - usbTiny(0); - layoutHome(); - return; - } - } + if (reader->cmd == 0) { + last_req_state = INIT; + cid = 0; + reader = 0; + usbTiny(0); + layoutHome(); + return; + } + } } -void u2fhid_ping(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_ping"); - send_u2fhid_msg(U2FHID_PING, buf, len); +void u2fhid_ping(const uint8_t *buf, uint32_t len) { + debugLog(0, "", "u2fhid_ping"); + send_u2fhid_msg(U2FHID_PING, buf, len); } -void u2fhid_wink(const uint8_t *buf, uint32_t len) -{ - debugLog(0, "", "u2fhid_wink"); - (void)buf; +void u2fhid_wink(const uint8_t *buf, uint32_t len) { + debugLog(0, "", "u2fhid_wink"); + (void)buf; - if (len > 0) - return send_u2fhid_error(cid, ERR_INVALID_LEN); + if (len > 0) return send_u2fhid_error(cid, ERR_INVALID_LEN); - if (dialog_timeout > 0) - dialog_timeout = U2F_TIMEOUT; + if (dialog_timeout > 0) dialog_timeout = U2F_TIMEOUT; - U2FHID_FRAME f; - memzero(&f, sizeof(f)); - f.cid = cid; - f.init.cmd = U2FHID_WINK; - f.init.bcntl = 0; - queue_u2f_pkt(&f); + U2FHID_FRAME f; + memzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = U2FHID_WINK; + f.init.bcntl = 0; + queue_u2f_pkt(&f); } -void u2fhid_init(const U2FHID_FRAME *in) -{ - const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; - U2FHID_FRAME f; - U2FHID_INIT_RESP resp; - memzero(&resp, sizeof(resp)); +void u2fhid_init(const U2FHID_FRAME *in) { + const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; + U2FHID_FRAME f; + U2FHID_INIT_RESP resp; + memzero(&resp, sizeof(resp)); - debugLog(0, "", "u2fhid_init"); + debugLog(0, "", "u2fhid_init"); - if (in->cid == 0) { - send_u2fhid_error(in->cid, ERR_INVALID_CID); - return; - } + if (in->cid == 0) { + send_u2fhid_error(in->cid, ERR_INVALID_CID); + return; + } - memzero(&f, sizeof(f)); - f.cid = in->cid; - f.init.cmd = U2FHID_INIT; - f.init.bcnth = 0; - f.init.bcntl = sizeof(resp); + memzero(&f, sizeof(f)); + f.cid = in->cid; + f.init.cmd = U2FHID_INIT; + f.init.bcnth = 0; + f.init.bcntl = sizeof(resp); - memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); - resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; - resp.versionInterface = U2FHID_IF_VERSION; - resp.versionMajor = VERSION_MAJOR; - resp.versionMinor = VERSION_MINOR; - resp.versionBuild = VERSION_PATCH; - resp.capFlags = CAPFLAG_WINK; - memcpy(&f.init.data, &resp, sizeof(resp)); + memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); + resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid; + resp.versionInterface = U2FHID_IF_VERSION; + resp.versionMajor = VERSION_MAJOR; + resp.versionMinor = VERSION_MINOR; + resp.versionBuild = VERSION_PATCH; + resp.capFlags = CAPFLAG_WINK; + memcpy(&f.init.data, &resp, sizeof(resp)); - queue_u2f_pkt(&f); + queue_u2f_pkt(&f); } -void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) -{ - // debugLog(0, "", "u2f_write_pkt"); - uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN; - if (u2f_out_start == next) { - debugLog(0, "", "u2f_write_pkt full"); - return; // Buffer full :( - } - memcpy(u2f_out_packets[u2f_out_end], u2f_pkt, HID_RPT_SIZE); - u2f_out_end = next; +void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) { + // debugLog(0, "", "u2f_write_pkt"); + uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN; + if (u2f_out_start == next) { + debugLog(0, "", "u2f_write_pkt full"); + return; // Buffer full :( + } + memcpy(u2f_out_packets[u2f_out_end], u2f_pkt, HID_RPT_SIZE); + u2f_out_end = next; } -uint8_t *u2f_out_data(void) -{ - if (u2f_out_start == u2f_out_end) - return NULL; // No data - // debugLog(0, "", "u2f_out_data"); - uint32_t t = u2f_out_start; - u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN; - return u2f_out_packets[t]; +uint8_t *u2f_out_data(void) { + if (u2f_out_start == u2f_out_end) return NULL; // No data + // debugLog(0, "", "u2f_out_data"); + uint32_t t = u2f_out_start; + u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN; + return u2f_out_packets[t]; } -void u2fhid_msg(const APDU *a, uint32_t len) -{ - if ((APDU_LEN(*a) + sizeof(APDU)) > len) { - debugLog(0, "", "BAD APDU LENGTH"); - debugInt(APDU_LEN(*a)); - debugInt(len); - return; - } +void u2fhid_msg(const APDU *a, uint32_t len) { + if ((APDU_LEN(*a) + sizeof(APDU)) > len) { + debugLog(0, "", "BAD APDU LENGTH"); + debugInt(APDU_LEN(*a)); + debugInt(len); + return; + } - if (a->cla != 0) { - send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED); - return; - } + if (a->cla != 0) { + send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED); + return; + } - switch (a->ins) { - case U2F_REGISTER: - u2f_register(a); - break; - case U2F_AUTHENTICATE: - u2f_authenticate(a); - break; - case U2F_VERSION: - u2f_version(a); - break; - default: - debugLog(0, "", "u2f unknown cmd"); - send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); - } + switch (a->ins) { + case U2F_REGISTER: + u2f_register(a); + break; + case U2F_AUTHENTICATE: + u2f_authenticate(a); + break; + case U2F_VERSION: + u2f_version(a); + break; + default: + debugLog(0, "", "u2f unknown cmd"); + send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); + } } -void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) -{ - if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { - debugLog(0, "", "send_u2fhid_msg failed"); - return; - } +void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, + const uint32_t len) { + if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { + debugLog(0, "", "send_u2fhid_msg failed"); + return; + } - U2FHID_FRAME f; - uint8_t *p = (uint8_t *)data; - uint32_t l = len; - uint32_t psz; - uint8_t seq = 0; + U2FHID_FRAME f; + uint8_t *p = (uint8_t *)data; + uint32_t l = len; + uint32_t psz; + uint8_t seq = 0; - // debugLog(0, "", "send_u2fhid_msg"); + // debugLog(0, "", "send_u2fhid_msg"); - memzero(&f, sizeof(f)); - f.cid = cid; - f.init.cmd = cmd; - f.init.bcnth = len >> 8; - f.init.bcntl = len & 0xff; + memzero(&f, sizeof(f)); + f.cid = cid; + f.init.cmd = cmd; + f.init.bcnth = len >> 8; + f.init.bcntl = len & 0xff; - // Init packet - psz = MIN(sizeof(f.init.data), l); - memcpy(f.init.data, p, psz); - queue_u2f_pkt(&f); - l -= psz; - p += psz; + // Init packet + psz = MIN(sizeof(f.init.data), l); + memcpy(f.init.data, p, psz); + queue_u2f_pkt(&f); + l -= psz; + p += psz; - // Cont packet(s) - for (; l > 0; l -= psz, p += psz) { - // debugLog(0, "", "send_u2fhid_msg con"); - memzero(&f.cont.data, sizeof(f.cont.data)); - f.cont.seq = seq++; - psz = MIN(sizeof(f.cont.data), l); - memcpy(f.cont.data, p, psz); - queue_u2f_pkt(&f); - } + // Cont packet(s) + for (; l > 0; l -= psz, p += psz) { + // debugLog(0, "", "send_u2fhid_msg con"); + memzero(&f.cont.data, sizeof(f.cont.data)); + f.cont.seq = seq++; + psz = MIN(sizeof(f.cont.data), l); + memcpy(f.cont.data, p, psz); + queue_u2f_pkt(&f); + } - if (data + len != p) { - debugLog(0, "", "send_u2fhid_msg is bad"); - debugInt(data + len - p); - } + if (data + len != p) { + debugLog(0, "", "send_u2fhid_msg is bad"); + debugInt(data + len - p); + } } -void send_u2fhid_error(uint32_t fcid, uint8_t err) -{ - U2FHID_FRAME f; +void send_u2fhid_error(uint32_t fcid, uint8_t err) { + U2FHID_FRAME f; - memzero(&f, sizeof(f)); - f.cid = fcid; - f.init.cmd = U2FHID_ERROR; - f.init.bcntl = 1; - f.init.data[0] = err; - queue_u2f_pkt(&f); + memzero(&f, sizeof(f)); + f.cid = fcid; + f.init.cmd = U2FHID_ERROR; + f.init.bcntl = 1; + f.init.data[0] = err; + queue_u2f_pkt(&f); } -void u2f_version(const APDU *a) -{ - if (APDU_LEN(*a) != 0) { - debugLog(0, "", "u2f version - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } +void u2f_version(const APDU *a) { + if (APDU_LEN(*a) != 0) { + debugLog(0, "", "u2f version - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } - // INCLUDES SW_NO_ERROR - static const uint8_t version_response[] = {'U', '2', 'F', '_', - 'V', '2', 0x90, 0x00}; - debugLog(0, "", "u2f version"); - send_u2f_msg(version_response, sizeof(version_response)); + // INCLUDES SW_NO_ERROR + static const uint8_t version_response[] = {'U', '2', 'F', '_', + 'V', '2', 0x90, 0x00}; + debugLog(0, "", "u2f version"); + send_u2f_msg(version_response, sizeof(version_response)); } -static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname) { - static char buf[8+2+8+1]; +static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], + const char **appname) { + static char buf[8 + 2 + 8 + 1]; - for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { - if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { - *appname = u2f_well_known[i].appname; - return; - } - } + for (unsigned int i = 0; i < sizeof(u2f_well_known) / sizeof(U2FWellKnown); + i++) { + if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { + *appname = u2f_well_known[i].appname; + return; + } + } - data2hex(appid, 4, &buf[0]); - buf[8] = buf[9] = '.'; - data2hex(appid + (U2F_APPID_SIZE - 4), 4, &buf[10]); - *appname = buf; + data2hex(appid, 4, &buf[0]); + buf[8] = buf[9] = '.'; + data2hex(appid + (U2F_APPID_SIZE - 4), 4, &buf[10]); + *appname = buf; } -static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) -{ - static CONFIDENTIAL HDNode node; - if (!config_getU2FRoot(&node)) { - layoutHome(); - debugLog(0, "", "ERR: Device not init"); - return 0; - } - if (!address_n || address_n_count == 0) { - return &node; - } - for (size_t i = 0; i < address_n_count; i++) { - if (hdnode_private_ckd(&node, address_n[i]) == 0) { - layoutHome(); - debugLog(0, "", "ERR: Derive private failed"); - return 0; - } - } - return &node; +static const HDNode *getDerivedNode(uint32_t *address_n, + size_t address_n_count) { + static CONFIDENTIAL HDNode node; + if (!config_getU2FRoot(&node)) { + layoutHome(); + debugLog(0, "", "ERR: Device not init"); + return 0; + } + if (!address_n || address_n_count == 0) { + return &node; + } + for (size_t i = 0; i < address_n_count; i++) { + if (hdnode_private_ckd(&node, address_n[i]) == 0) { + layoutHome(); + debugLog(0, "", "ERR: Derive private failed"); + return 0; + } + } + return &node; } -static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) -{ - uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; +static const HDNode *generateKeyHandle(const uint8_t app_id[], + uint8_t key_handle[]) { + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' - uint32_t key_path[KEY_PATH_ENTRIES]; - for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) { - // high bit for hardened keys - key_path[i]= 0x80000000 | random32(); - } + // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' + uint32_t key_path[KEY_PATH_ENTRIES]; + for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) { + // high bit for hardened keys + key_path[i] = 0x80000000 | random32(); + } - // First half of keyhandle is key_path - memcpy(key_handle, key_path, KEY_PATH_LEN); + // First half of keyhandle is key_path + memcpy(key_handle, key_path, KEY_PATH_LEN); - // prepare keypair from /random data - const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - if (!node) - return NULL; + // prepare keypair from /random data + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) return NULL; - // For second half of keyhandle - // Signature of app_id and random data - memcpy(&keybase[0], app_id, U2F_APPID_SIZE); - memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - hmac_sha256(node->private_key, sizeof(node->private_key), - keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]); + // For second half of keyhandle + // Signature of app_id and random data + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); + hmac_sha256(node->private_key, sizeof(node->private_key), keybase, + sizeof(keybase), &key_handle[KEY_PATH_LEN]); - // Done! - return node; + // Done! + return node; } +static const HDNode *validateKeyHandle(const uint8_t app_id[], + const uint8_t key_handle[]) { + uint32_t key_path[KEY_PATH_ENTRIES]; + memcpy(key_path, key_handle, KEY_PATH_LEN); + for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { + // check high bit for hardened keys + if (!(key_path[i] & 0x80000000)) { + return NULL; + } + } -static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) -{ - uint32_t key_path[KEY_PATH_ENTRIES]; - memcpy(key_path, key_handle, KEY_PATH_LEN); - for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { - // check high bit for hardened keys - if (! (key_path[i] & 0x80000000)) { - return NULL; - } - } + const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); + if (!node) return NULL; - const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); - if (!node) - return NULL; + uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; + memcpy(&keybase[0], app_id, U2F_APPID_SIZE); + memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); - uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; - memcpy(&keybase[0], app_id, U2F_APPID_SIZE); - memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); + uint8_t hmac[SHA256_DIGEST_LENGTH]; + hmac_sha256(node->private_key, sizeof(node->private_key), keybase, + sizeof(keybase), hmac); + if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) + return NULL; - uint8_t hmac[SHA256_DIGEST_LENGTH]; - hmac_sha256(node->private_key, sizeof(node->private_key), - keybase, sizeof(keybase), hmac); - - if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) - return NULL; - - // Done! - return node; + // Done! + return node; } +void u2f_register(const APDU *a) { + static U2F_REGISTER_REQ last_req; + const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; -void u2f_register(const APDU *a) -{ - static U2F_REGISTER_REQ last_req; - const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; + if (!config_isInitialized()) { + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } - if (!config_isInitialized()) { - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - return; - } + // Validate basic request parameters + debugLog(0, "", "u2f register"); + if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { + debugLog(0, "", "u2f register - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } - // Validate basic request parameters - debugLog(0, "", "u2f register"); - if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { - debugLog(0, "", "u2f register - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } + // If this request is different from last request, reset state machine + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } - // If this request is different from last request, reset state machine - if (memcmp(&last_req, req, sizeof(last_req)) != 0) { - memcpy(&last_req, req, sizeof(last_req)); - last_req_state = INIT; - } + // First Time request, return not present and display request dialog + if (last_req_state == INIT) { + // error: testof-user-presence is required + buttonUpdate(); // Clear button state + if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { + layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL, + _("Another U2F device"), _("was used to register"), + _("in this application."), NULL, NULL, NULL); + } else { + const char *appname; + getReadableAppId(req->appId, &appname); + layoutU2FDialog(_("Register"), appname); + } + last_req_state = REG; + } - // First Time request, return not present and display request dialog - if (last_req_state == INIT) { - // error: testof-user-presence is required - buttonUpdate(); // Clear button state - if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { - layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL, _("Another U2F device"), _("was used to register"), _("in this application."), NULL, NULL, NULL); - } else { - const char *appname; - getReadableAppId(req->appId, &appname); - layoutU2FDialog(_("Register"), appname); - } - last_req_state = REG; - } + // Still awaiting Keypress + if (last_req_state == REG) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } - // Still awaiting Keypress - if (last_req_state == REG) { - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; - return; - } + // Buttons said yes + if (last_req_state == REG_PASS) { + uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; + U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; + memzero(data, sizeof(data)); - // Buttons said yes - if (last_req_state == REG_PASS) { - uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; - U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; - memzero(data, sizeof(data)); + resp->registerId = U2F_REGISTER_ID; + resp->keyHandleLen = KEY_HANDLE_LEN; + // Generate keypair for this appId + const HDNode *node = + generateKeyHandle(req->appId, (uint8_t *)&resp->keyHandleCertSig); - resp->registerId = U2F_REGISTER_ID; - resp->keyHandleLen = KEY_HANDLE_LEN; - // Generate keypair for this appId - const HDNode *node = - generateKeyHandle(req->appId, (uint8_t*)&resp->keyHandleCertSig); + if (!node) { + debugLog(0, "", "getDerivedNode Fail"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } - if (!node) { - debugLog(0, "", "getDerivedNode Fail"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } + ecdsa_get_public_key65(node->curve->params, node->private_key, + (uint8_t *)&resp->pubKey); - ecdsa_get_public_key65(node->curve->params, node->private_key, - (uint8_t *)&resp->pubKey); + memcpy(resp->keyHandleCertSig + resp->keyHandleLen, U2F_ATT_CERT, + sizeof(U2F_ATT_CERT)); - memcpy(resp->keyHandleCertSig + resp->keyHandleLen, - U2F_ATT_CERT, sizeof(U2F_ATT_CERT)); + uint8_t sig[64]; + U2F_REGISTER_SIG_STR sig_base; + sig_base.reserved = 0; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); + memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); + if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, + (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, + NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } - uint8_t sig[64]; - U2F_REGISTER_SIG_STR sig_base; - sig_base.reserved = 0; - memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); - memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); - memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); - if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } + // Where to write the signature in the response + uint8_t *resp_sig = + resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT); + // Convert to der for the response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); - // Where to write the signature in the response - uint8_t *resp_sig = resp->keyHandleCertSig + - resp->keyHandleLen + sizeof(U2F_ATT_CERT); - // Convert to der for the response - const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); + // Append success bytes + memcpy(resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + + sig_len, + "\x90\x00", 2); - // Append success bytes - memcpy(resp->keyHandleCertSig + resp->keyHandleLen + - sizeof(U2F_ATT_CERT) + sig_len, - "\x90\x00", 2); + int l = 1 /* registerId */ + U2F_PUBKEY_LEN + 1 /* keyhandleLen */ + + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2; - int l = 1 /* registerId */ + U2F_PUBKEY_LEN + - 1 /* keyhandleLen */ + resp->keyHandleLen + - sizeof(U2F_ATT_CERT) + sig_len + 2; + last_req_state = INIT; + dialog_timeout = 0; + send_u2f_msg(data, l); + return; + } - last_req_state = INIT; - dialog_timeout = 0; - send_u2f_msg(data, l); - return; - } - - // Didnt expect to get here - dialog_timeout = 0; + // Didnt expect to get here + dialog_timeout = 0; } -void u2f_authenticate(const APDU *a) -{ - const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; - static U2F_AUTHENTICATE_REQ last_req; +void u2f_authenticate(const APDU *a) { + const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; + static U2F_AUTHENTICATE_REQ last_req; - if (!config_isInitialized()) { - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - return; - } + if (!config_isInitialized()) { + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } - if (APDU_LEN(*a) < 64) { /// FIXME: decent value - debugLog(0, "", "u2f authenticate - badlen"); - send_u2f_error(U2F_SW_WRONG_LENGTH); - return; - } + if (APDU_LEN(*a) < 64) { /// FIXME: decent value + debugLog(0, "", "u2f authenticate - badlen"); + send_u2f_error(U2F_SW_WRONG_LENGTH); + return; + } - if (req->keyHandleLen != KEY_HANDLE_LEN) { - debugLog(0, "", "u2f auth - bad keyhandle len"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } + if (req->keyHandleLen != KEY_HANDLE_LEN) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } - const HDNode *node = - validateKeyHandle(req->appId, req->keyHandle); + const HDNode *node = validateKeyHandle(req->appId, req->keyHandle); - if (!node) { - debugLog(0, "", "u2f auth - bad keyhandle len"); - send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle - return; - } + if (!node) { + debugLog(0, "", "u2f auth - bad keyhandle len"); + send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle + return; + } - if (a->p1 == U2F_AUTH_CHECK_ONLY) { - debugLog(0, "", "u2f authenticate check"); - // This is a success for a good keyhandle - // A failed check would have happened earlier - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - return; - } + if (a->p1 == U2F_AUTH_CHECK_ONLY) { + debugLog(0, "", "u2f authenticate check"); + // This is a success for a good keyhandle + // A failed check would have happened earlier + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + return; + } - if (a->p1 != U2F_AUTH_ENFORCE) { - debugLog(0, "", "u2f authenticate unknown"); - // error:bad key handle - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } + if (a->p1 != U2F_AUTH_ENFORCE) { + debugLog(0, "", "u2f authenticate unknown"); + // error:bad key handle + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } - debugLog(0, "", "u2f authenticate enforce"); + debugLog(0, "", "u2f authenticate enforce"); - if (memcmp(&last_req, req, sizeof(last_req)) != 0) { - memcpy(&last_req, req, sizeof(last_req)); - last_req_state = INIT; - } + if (memcmp(&last_req, req, sizeof(last_req)) != 0) { + memcpy(&last_req, req, sizeof(last_req)); + last_req_state = INIT; + } - if (last_req_state == INIT) { - // error: testof-user-presence is required - buttonUpdate(); // Clear button state - const char *appname; - getReadableAppId(req->appId, &appname); - layoutU2FDialog(_("Authenticate"), appname); - last_req_state = AUTH; - } + if (last_req_state == INIT) { + // error: testof-user-presence is required + buttonUpdate(); // Clear button state + const char *appname; + getReadableAppId(req->appId, &appname); + layoutU2FDialog(_("Authenticate"), appname); + last_req_state = AUTH; + } - // Awaiting Keypress - if (last_req_state == AUTH) { - // error: testof-user-presence is required - send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); - dialog_timeout = U2F_TIMEOUT; - return; - } + // Awaiting Keypress + if (last_req_state == AUTH) { + // error: testof-user-presence is required + send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + dialog_timeout = U2F_TIMEOUT; + return; + } - // Buttons said yes - if (last_req_state == AUTH_PASS) { - uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; - U2F_AUTHENTICATE_RESP *resp = - (U2F_AUTHENTICATE_RESP *)&buf; + // Buttons said yes + if (last_req_state == AUTH_PASS) { + uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; + U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf; - const uint32_t ctr = config_nextU2FCounter(); - resp->flags = U2F_AUTH_FLAG_TUP; - resp->ctr[0] = ctr >> 24 & 0xff; - resp->ctr[1] = ctr >> 16 & 0xff; - resp->ctr[2] = ctr >> 8 & 0xff; - resp->ctr[3] = ctr & 0xff; + const uint32_t ctr = config_nextU2FCounter(); + resp->flags = U2F_AUTH_FLAG_TUP; + resp->ctr[0] = ctr >> 24 & 0xff; + resp->ctr[1] = ctr >> 16 & 0xff; + resp->ctr[2] = ctr >> 8 & 0xff; + resp->ctr[3] = ctr & 0xff; - // Build and sign response - U2F_AUTHENTICATE_SIG_STR sig_base; - uint8_t sig[64]; - memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); - sig_base.flags = resp->flags; - memcpy(sig_base.ctr, resp->ctr, 4); - memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); - if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { - send_u2f_error(U2F_SW_WRONG_DATA); - return; - } + // Build and sign response + U2F_AUTHENTICATE_SIG_STR sig_base; + uint8_t sig[64]; + memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); + sig_base.flags = resp->flags; + memcpy(sig_base.ctr, resp->ctr, 4); + memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); + if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, + (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, + NULL) != 0) { + send_u2f_error(U2F_SW_WRONG_DATA); + return; + } - // Copy DER encoded signature into response - const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); + // Copy DER encoded signature into response + const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); - // Append OK - memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - - U2F_MAX_EC_SIG_SIZE + sig_len, - "\x90\x00", 2); - last_req_state = INIT; - dialog_timeout = 0; - send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - - U2F_MAX_EC_SIG_SIZE + sig_len + - 2); - } + // Append OK + memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len, + "\x90\x00", 2); + last_req_state = INIT; + dialog_timeout = 0; + send_u2f_msg( + buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); + } } -void send_u2f_error(const uint16_t err) -{ - uint8_t data[2]; - data[0] = err >> 8 & 0xFF; - data[1] = err & 0xFF; - send_u2f_msg(data, 2); +void send_u2f_error(const uint16_t err) { + uint8_t data[2]; + data[0] = err >> 8 & 0xFF; + data[1] = err & 0xFF; + send_u2f_msg(data, 2); } -void send_u2f_msg(const uint8_t *data, const uint32_t len) -{ - send_u2fhid_msg(U2FHID_MSG, data, len); +void send_u2f_msg(const uint8_t *data, const uint32_t len) { + send_u2fhid_msg(U2FHID_MSG, data, len); } diff --git a/firmware/u2f.h b/firmware/u2f.h index 9eb0cca620..e1e3a41975 100644 --- a/firmware/u2f.h +++ b/firmware/u2f.h @@ -20,17 +20,17 @@ #ifndef __U2F_H__ #define __U2F_H__ -#include #include -#include "u2f/u2f_hid.h" +#include #include "trezor.h" +#include "u2f/u2f_hid.h" #define U2F_KEY_PATH 0x80553246 typedef struct { - uint8_t cla, ins, p1, p2; - uint8_t lc1, lc2, lc3; - uint8_t data[]; + uint8_t cla, ins, p1, p2; + uint8_t lc1, lc2, lc3; + uint8_t data[]; } APDU; #define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3)) @@ -56,7 +56,7 @@ void send_u2f_msg(const uint8_t *data, uint32_t len); void send_u2f_error(uint16_t err); void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, - const uint32_t len); + const uint32_t len); void send_u2fhid_error(uint32_t fcid, uint8_t err); #endif diff --git a/firmware/u2f/u2f_keys.h b/firmware/u2f/u2f_keys.h index 680a730e20..578b435c08 100644 --- a/firmware/u2f/u2f_keys.h +++ b/firmware/u2f/u2f_keys.h @@ -4,37 +4,35 @@ #include const uint8_t U2F_ATT_PRIV_KEY[] = { - 0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, - 0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, - 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, - 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b -}; + 0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, 0x86, 0xad, 0x83, + 0xef, 0x1f, 0xcd, 0xf1, 0x2a, 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, + 0x8a, 0xd0, 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b}; const uint8_t U2F_ATT_CERT[] = { - 0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9, - 0x8f, 0x42, 0x64, 0x72, 0xd3, 0x2c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, - 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, - 0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, - 0x34, 0x32, 0x39, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x5a, 0x17, 0x0d, - 0x32, 0x36, 0x30, 0x34, 0x32, 0x37, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, - 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, - 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x55, 0x32, 0x46, - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, - 0x42, 0x00, 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9, - 0x0d, 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36, - 0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, 0x52, - 0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, 0xdb, 0x8a, - 0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, 0x43, 0xa5, 0x26, - 0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1, 0x30, 0x0a, 0x06, 0x08, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, - 0x02, 0x20, 0x24, 0x1e, 0x81, 0xff, 0xd2, 0xe5, 0xe6, 0x15, 0x36, 0x94, - 0xc3, 0x55, 0x2e, 0x8f, 0xeb, 0xd7, 0x1e, 0x89, 0x35, 0x92, 0x1c, 0xb4, - 0x83, 0x41, 0x43, 0x71, 0x1c, 0x76, 0xea, 0xee, 0xf3, 0x95, 0x02, 0x20, - 0x5f, 0x80, 0xeb, 0x10, 0xf2, 0x5c, 0xcc, 0x39, 0x8b, 0x3c, 0xa8, 0xa9, - 0xad, 0xa4, 0x02, 0x7f, 0x93, 0x13, 0x20, 0x77, 0xb7, 0xab, 0xce, 0x77, - 0x46, 0x5a, 0x27, 0xf5, 0x3d, 0x33, 0xa1, 0x1d, + 0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9, + 0x8f, 0x42, 0x64, 0x72, 0xd3, 0x2c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, + 0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, + 0x34, 0x32, 0x39, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x5a, 0x17, 0x0d, + 0x32, 0x36, 0x30, 0x34, 0x32, 0x37, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, + 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x55, 0x32, 0x46, + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9, + 0x0d, 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36, + 0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, 0x52, + 0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, 0xdb, 0x8a, + 0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, 0x43, 0xa5, 0x26, + 0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1, 0x30, 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, + 0x02, 0x20, 0x24, 0x1e, 0x81, 0xff, 0xd2, 0xe5, 0xe6, 0x15, 0x36, 0x94, + 0xc3, 0x55, 0x2e, 0x8f, 0xeb, 0xd7, 0x1e, 0x89, 0x35, 0x92, 0x1c, 0xb4, + 0x83, 0x41, 0x43, 0x71, 0x1c, 0x76, 0xea, 0xee, 0xf3, 0x95, 0x02, 0x20, + 0x5f, 0x80, 0xeb, 0x10, 0xf2, 0x5c, 0xcc, 0x39, 0x8b, 0x3c, 0xa8, 0xa9, + 0xad, 0xa4, 0x02, 0x7f, 0x93, 0x13, 0x20, 0x77, 0xb7, 0xab, 0xce, 0x77, + 0x46, 0x5a, 0x27, 0xf5, 0x3d, 0x33, 0xa1, 0x1d, }; -#endif // __U2F_KEYS_H_INCLUDED__ +#endif // __U2F_KEYS_H_INCLUDED__ diff --git a/firmware/u2f_knownapps.h b/firmware/u2f_knownapps.h index 2f945e9373..f01a03510d 100644 --- a/firmware/u2f_knownapps.h +++ b/firmware/u2f_knownapps.h @@ -24,14 +24,15 @@ #include "u2f/u2f.h" typedef struct { - const uint8_t appid[U2F_APPID_SIZE]; - const char *appname; + const uint8_t appid[U2F_APPID_SIZE]; + const char *appname; } U2FWellKnown; // contents generated via script in // trezor-common/defs/webauthn/gen.py // do not edit manually +// clang-format off static const U2FWellKnown u2f_well_known[] = { { // U2F: https://bitbucket.org @@ -144,5 +145,6 @@ static const U2FWellKnown u2f_well_known[] = { "demo.yubico.com" }, }; +// clang-format on -#endif // U2F_KNOWNAPPS_INCLUDED +#endif // U2F_KNOWNAPPS_INCLUDED diff --git a/firmware/udp.c b/firmware/udp.c index 75c3e08a35..e9161261de 100644 --- a/firmware/udp.c +++ b/firmware/udp.c @@ -21,15 +21,13 @@ #include "usb.h" +#include "debug.h" #include "messages.h" #include "timer.h" -#include "debug.h" static volatile char tiny = 0; -void usbInit(void) { - emulatorSocketInit(); -} +void usbInit(void) { emulatorSocketInit(); } #if DEBUG_LINK #define _ISDBG (((iface == 1) ? 'd' : 'n')) @@ -38,42 +36,42 @@ void usbInit(void) { #endif void usbPoll(void) { - emulatorPoll(); + emulatorPoll(); - static uint8_t buffer[64]; + static uint8_t buffer[64]; - int iface = 0; - if (emulatorSocketRead(&iface, buffer, sizeof(buffer)) > 0) { - if (!tiny) { - msg_read_common(_ISDBG, buffer, sizeof(buffer)); - } else { - msg_read_tiny(buffer, sizeof(buffer)); - } - } + int iface = 0; + if (emulatorSocketRead(&iface, buffer, sizeof(buffer)) > 0) { + if (!tiny) { + msg_read_common(_ISDBG, buffer, sizeof(buffer)); + } else { + msg_read_tiny(buffer, sizeof(buffer)); + } + } - const uint8_t *data = msg_out_data(); - if (data != NULL) { - emulatorSocketWrite(0, data, 64); - } + const uint8_t *data = msg_out_data(); + if (data != NULL) { + emulatorSocketWrite(0, data, 64); + } #if DEBUG_LINK - data = msg_debug_out_data(); - if (data != NULL) { - emulatorSocketWrite(1, data, 64); - } + data = msg_debug_out_data(); + if (data != NULL) { + emulatorSocketWrite(1, data, 64); + } #endif } char usbTiny(char set) { - char old = tiny; - tiny = set; - return old; + char old = tiny; + tiny = set; + return old; } void usbSleep(uint32_t millis) { - uint32_t start = timer_ms(); + uint32_t start = timer_ms(); - while ((timer_ms() - start) < millis) { - usbPoll(); - } + while ((timer_ms() - start) < millis) { + usbPoll(); + } } diff --git a/firmware/usb.c b/firmware/usb.c index 4830da6628..09fb45a565 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -17,23 +17,22 @@ * along with this library. If not, see . */ -#include #include +#include -#include "trezor.h" -#include "usb.h" +#include "config.h" #include "debug.h" #include "messages.h" -#include "u2f.h" -#include "config.h" -#include "util.h" #include "timer.h" +#include "trezor.h" +#include "u2f.h" +#include "usb.h" +#include "util.h" #include "usb21_standard.h" #include "webusb.h" #include "winusb.h" - #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK #define USB_INTERFACE_INDEX_DEBUG 1 @@ -44,370 +43,381 @@ #define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_MAIN_IN (0x81) -#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) +#define ENDPOINT_ADDRESS_MAIN_IN (0x81) +#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) #if DEBUG_LINK -#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) -#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) +#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) #endif -#define ENDPOINT_ADDRESS_U2F_IN (0x83) -#define ENDPOINT_ADDRESS_U2F_OUT (0x03) +#define ENDPOINT_ADDRESS_U2F_IN (0x83) +#define ENDPOINT_ADDRESS_U2F_OUT (0x03) -#define USB_STRINGS \ - X(MANUFACTURER, "SatoshiLabs") \ - X(PRODUCT, "TREZOR") \ - X(SERIAL_NUMBER, config_uuid_str) \ - X(INTERFACE_MAIN, "TREZOR Interface") \ - X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ - X(INTERFACE_U2F, "TREZOR U2F Interface") \ +#define USB_STRINGS \ + X(MANUFACTURER, "SatoshiLabs") \ + X(PRODUCT, "TREZOR") \ + X(SERIAL_NUMBER, config_uuid_str) \ + X(INTERFACE_MAIN, "TREZOR Interface") \ + X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ + X(INTERFACE_U2F, "TREZOR U2F Interface") #define X(name, value) USB_STRING_##name, enum { - USB_STRING_LANGID_CODES, // LANGID code array - USB_STRINGS + USB_STRING_LANGID_CODES, // LANGID code array + USB_STRINGS }; #undef X #define X(name, value) value, -static const char *usb_strings[] = { - USB_STRINGS -}; +static const char *usb_strings[] = {USB_STRINGS}; #undef X static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x1209, - .idProduct = 0x53c1, - .bcdDevice = 0x0100, - .iManufacturer = USB_STRING_MANUFACTURER, - .iProduct = USB_STRING_PRODUCT, - .iSerialNumber = USB_STRING_SERIAL_NUMBER, - .bNumConfigurations = 1, + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0210, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x53c1, + .bcdDevice = 0x0100, + .iManufacturer = USB_STRING_MANUFACTURER, + .iProduct = USB_STRING_PRODUCT, + .iSerialNumber = USB_STRING_SERIAL_NUMBER, + .bNumConfigurations = 1, }; static const uint8_t hid_report_descriptor_u2f[] = { - 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) - 0x09, 0x01, // USAGE (U2F HID Authenticator Device) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION + 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) + 0x09, 0x01, // USAGE (U2F HID Authenticator Device) + 0xa1, 0x01, // COLLECTION (Application) + 0x09, 0x20, // USAGE (Input Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x09, 0x21, // USAGE (Output Report Data) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x40, // REPORT_COUNT (64) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0xc0 // END_COLLECTION }; static const struct { - struct usb_hid_descriptor hid_descriptor_u2f; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report_u2f; -} __attribute__((packed)) hid_function_u2f = { - .hid_descriptor_u2f = { - .bLength = sizeof(hid_function_u2f), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report_u2f = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor_u2f), - } -}; + struct usb_hid_descriptor hid_descriptor_u2f; + struct { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__((packed)) hid_report_u2f; +} __attribute__((packed)) +hid_function_u2f = {.hid_descriptor_u2f = + { + .bLength = sizeof(hid_function_u2f), + .bDescriptorType = USB_DT_HID, + .bcdHID = 0x0111, + .bCountryCode = 0, + .bNumDescriptors = 1, + }, + .hid_report_u2f = { + .bReportDescriptorType = USB_DT_REPORT, + .wDescriptorLength = sizeof(hid_report_descriptor_u2f), + }}; -static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_U2F, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_U2F, - .endpoint = hid_endpoints_u2f, - .extra = &hid_function_u2f, - .extralen = sizeof(hid_function_u2f), + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_U2F, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_U2F, + .endpoint = hid_endpoints_u2f, + .extra = &hid_function_u2f, + .extralen = sizeof(hid_function_u2f), }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor webusb_iface_debug[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = webusb_endpoints_debug, - .extra = NULL, - .extralen = 0, + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_DEBUG, + .endpoint = webusb_endpoints_debug, + .extra = NULL, + .extralen = 0, }}; #endif -static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; +static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; static const struct usb_interface_descriptor webusb_iface_main[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = webusb_endpoints_main, - .extra = NULL, - .extralen = 0, + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = webusb_endpoints_main, + .extra = NULL, + .extralen = 0, }}; - // Windows are strict about interfaces appearing // in correct order -static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = webusb_iface_main, +static const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = webusb_iface_main, #if DEBUG_LINK -}, { - .num_altsetting = 1, - .altsetting = webusb_iface_debug, + }, + { + .num_altsetting = 1, + .altsetting = webusb_iface_debug, #endif -}, { - .num_altsetting = 1, - .altsetting = hid_iface_u2f, -}}; + }, + { + .num_altsetting = 1, + .altsetting = hid_iface_u2f, + }}; static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = USB_INTERFACE_COUNT, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = USB_INTERFACE_COUNT, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) -{ - (void)complete; - (void)dev; +static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) { + (void)complete; + (void)dev; - wait_random(); + wait_random(); - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200)) + return 0; - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = MIN_8bits(*len, sizeof(hid_report_descriptor_u2f)); - return 1; + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = MIN_8bits(*len, sizeof(hid_report_descriptor_u2f)); + return 1; } static volatile char tiny = 0; -static void main_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; - debugLog(0, "", "main_rx_callback"); - if (!tiny) { - msg_read(buf, 64); - } else { - msg_read_tiny(buf, 64); - } +static void main_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) + return; + debugLog(0, "", "main_rx_callback"); + if (!tiny) { + msg_read(buf, 64); + } else { + msg_read_tiny(buf, 64); + } } -static void u2f_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); +static void u2f_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); - debugLog(0, "", "u2f_rx_callback"); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; - u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); + debugLog(0, "", "u2f_rx_callback"); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; + u2fhid_read(tiny, (const U2FHID_FRAME *)(void *)buf); } #if DEBUG_LINK -static void debug_rx_callback(usbd_device *dev, uint8_t ep) -{ - (void)ep; - static uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "debug_rx_callback"); - if (!tiny) { - msg_debug_read(buf, 64); - } else { - msg_read_tiny(buf, 64); - } +static void debug_rx_callback(usbd_device *dev, uint8_t ep) { + (void)ep; + static uint8_t buf[64] __attribute__((aligned(4))); + if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) + return; + debugLog(0, "", "debug_rx_callback"); + if (!tiny) { + msg_debug_read(buf, 64); + } else { + msg_read_tiny(buf, 64); + } } #endif -static void set_config(usbd_device *dev, uint16_t wValue) -{ - (void)wValue; +static void set_config(usbd_device *dev, uint16_t wValue) { + (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, + main_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, + u2f_rx_callback); #if DEBUG_LINK - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, + 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, + 64, debug_rx_callback); #endif - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request); + usbd_register_control_callback( + dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request); } static usbd_device *usbd_dev = NULL; -static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); +static uint8_t usbd_control_buffer[256] __attribute__((aligned(2))); -static const struct usb_device_capability_descriptor* capabilities[] = { - (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor_no_landing_page, +static const struct usb_device_capability_descriptor *capabilities[] = { + (const struct usb_device_capability_descriptor + *)&webusb_platform_capability_descriptor_no_landing_page, }; static const struct usb_bos_descriptor bos_descriptor = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), - .capabilities = capabilities -}; + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]), + .capabilities = capabilities}; -void usbInit(void) -{ - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, set_config); - usb21_setup(usbd_dev, &bos_descriptor); - static const char* origin_url = "trezor.io/start"; - webusb_setup(usbd_dev, origin_url); - // Debug link interface does not have WinUSB set; - // if you really need debug link on windows, edit the descriptor in winusb.c - winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); +void usbInit(void) { + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, + sizeof(usb_strings) / sizeof(*usb_strings), + usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char *origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + // Debug link interface does not have WinUSB set; + // if you really need debug link on windows, edit the descriptor in winusb.c + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } -void usbPoll(void) -{ - if (usbd_dev == NULL) { - return; - } +void usbPoll(void) { + if (usbd_dev == NULL) { + return; + } - static const uint8_t *data; - // poll read buffer - usbd_poll(usbd_dev); - // write pending data - data = msg_out_data(); - if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} - } - data = u2f_out_data(); - if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) != 64 ) {} - } + static const uint8_t *data; + // poll read buffer + usbd_poll(usbd_dev); + // write pending data + data = msg_out_data(); + if (data) { + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != + 64) { + } + } + data = u2f_out_data(); + if (data) { + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) != + 64) { + } + } #if DEBUG_LINK - // write pending debug data - data = msg_debug_out_data(); - if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data, 64) != 64 ) {} - } + // write pending debug data + data = msg_debug_out_data(); + if (data) { + while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data, + 64) != 64) { + } + } #endif } -void usbReconnect(void) -{ - if (usbd_dev != NULL) { - usbd_disconnect(usbd_dev, 1); - delay(1000); - usbd_disconnect(usbd_dev, 0); - } +void usbReconnect(void) { + if (usbd_dev != NULL) { + usbd_disconnect(usbd_dev, 1); + delay(1000); + usbd_disconnect(usbd_dev, 0); + } } -char usbTiny(char set) -{ - char old = tiny; - tiny = set; - return old; +char usbTiny(char set) { + char old = tiny; + tiny = set; + return old; } -void usbSleep(uint32_t millis) -{ - uint32_t start = timer_ms(); +void usbSleep(uint32_t millis) { + uint32_t start = timer_ms(); - while ((timer_ms() - start) < millis) { - if (usbd_dev != NULL) { - usbd_poll(usbd_dev); - } - } + while ((timer_ms() - start) < millis) { + if (usbd_dev != NULL) { + usbd_poll(usbd_dev); + } + } } diff --git a/flash.c b/flash.c index 1501b6aa2a..fc5bbafa29 100644 --- a/flash.c +++ b/flash.c @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#include #include +#include #include "common.h" #include "flash.h" @@ -26,112 +26,105 @@ #include "supervise.h" static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { - [ 0] = 0x08000000, // - 0x08003FFF | 16 KiB - [ 1] = 0x08004000, // - 0x08007FFF | 16 KiB - [ 2] = 0x08008000, // - 0x0800BFFF | 16 KiB - [ 3] = 0x0800C000, // - 0x0800FFFF | 16 KiB - [ 4] = 0x08010000, // - 0x0801FFFF | 64 KiB - [ 5] = 0x08020000, // - 0x0803FFFF | 128 KiB - [ 6] = 0x08040000, // - 0x0805FFFF | 128 KiB - [ 7] = 0x08060000, // - 0x0807FFFF | 128 KiB - [ 8] = 0x08080000, // - 0x0809FFFF | 128 KiB - [ 9] = 0x080A0000, // - 0x080BFFFF | 128 KiB - [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB - [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB - [12] = 0x08100000, // last element - not a valid sector + [0] = 0x08000000, // - 0x08003FFF | 16 KiB + [1] = 0x08004000, // - 0x08007FFF | 16 KiB + [2] = 0x08008000, // - 0x0800BFFF | 16 KiB + [3] = 0x0800C000, // - 0x0800FFFF | 16 KiB + [4] = 0x08010000, // - 0x0801FFFF | 64 KiB + [5] = 0x08020000, // - 0x0803FFFF | 128 KiB + [6] = 0x08040000, // - 0x0805FFFF | 128 KiB + [7] = 0x08060000, // - 0x0807FFFF | 128 KiB + [8] = 0x08080000, // - 0x0809FFFF | 128 KiB + [9] = 0x080A0000, // - 0x080BFFFF | 128 KiB + [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB + [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB + [12] = 0x08100000, // last element - not a valid sector }; -static secbool flash_check_success(uint32_t status) -{ - return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; +static secbool flash_check_success(uint32_t status) { + return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | + FLASH_SR_WRPERR)) + ? secfalse + : sectrue; } -void flash_init(void) -{ +void flash_init(void) {} + +secbool flash_unlock_write(void) { + svc_flash_unlock(); + return sectrue; } -secbool flash_unlock_write(void) -{ - svc_flash_unlock(); - return sectrue; +secbool flash_lock_write(void) { return flash_check_success(svc_flash_lock()); } + +const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) { + if (sector >= FLASH_SECTOR_COUNT) { + return NULL; + } + const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset; + const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; + if (addr + size > next) { + return NULL; + } + return (const void *)FLASH_PTR(addr); } -secbool flash_lock_write(void) -{ - return flash_check_success(svc_flash_lock()); +secbool flash_erase(uint8_t sector) { + ensure(flash_unlock_write(), NULL); + svc_flash_erase_sector(sector); + ensure(flash_lock_write(), NULL); + + // Check whether the sector was really deleted (contains only 0xFF). + const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], + addr_end = FLASH_SECTOR_TABLE[sector + 1]; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { + return secfalse; + } + } + return sectrue; } -const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) -{ - if (sector >= FLASH_SECTOR_COUNT) { - return NULL; - } - const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset; - const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; - if (addr + size > next) { - return NULL; - } - return (const void *) FLASH_PTR(addr); +secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) { + uint8_t *address = (uint8_t *)flash_get_address(sector, offset, 1); + if (address == NULL) { + return secfalse; + } + + if ((*address & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X8); + *(volatile uint8_t *)address = data; + + if (*address != data) { + return secfalse; + } + + return sectrue; } -secbool flash_erase(uint8_t sector) -{ - ensure(flash_unlock_write(), NULL); - svc_flash_erase_sector(sector); - ensure(flash_lock_write(), NULL); +secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) { + uint32_t *address = (uint32_t *)flash_get_address(sector, offset, 4); + if (address == NULL) { + return secfalse; + } - // Check whether the sector was really deleted (contains only 0xFF). - const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; - for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { - return secfalse; - } - } - return sectrue; -} - -secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) -{ - uint8_t *address = (uint8_t *) flash_get_address(sector, offset, 1); - if (address == NULL) { - return secfalse; - } - - if ((*address & data) != data) { - return secfalse; - } - - svc_flash_program(FLASH_CR_PROGRAM_X8); - *(volatile uint8_t *) address = data; - - if (*address != data) { - return secfalse; - } - - return sectrue; -} - -secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) -{ - uint32_t *address = (uint32_t *) flash_get_address(sector, offset, 4); - if (address == NULL) { - return secfalse; - } - - if (offset % 4 != 0) { - return secfalse; - } - - if ((*address & data) != data) { - return secfalse; - } - - svc_flash_program(FLASH_CR_PROGRAM_X32); - *(volatile uint32_t *) address = data; - - if (*address != data) { - return secfalse; - } - - return sectrue; + if (offset % 4 != 0) { + return secfalse; + } + + if ((*address & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X32); + *(volatile uint32_t *)address = data; + + if (*address != data) { + return secfalse; + } + + return sectrue; } diff --git a/flash.h b/flash.h index 24e1a3ad64..c0c7289d16 100644 --- a/flash.h +++ b/flash.h @@ -26,12 +26,15 @@ #define FLASH_SECTOR_COUNT 24 -// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) +// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) +// (reference RM0090 section 3.7.5) #ifndef STM32F427xx #define FLASH_SR_RDERR 0 #endif -#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) +#define FLASH_STATUS_ALL_FLAGS \ + (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \ + FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) void flash_init(void); @@ -44,4 +47,4 @@ secbool __wur flash_erase(uint8_t sector); secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); -#endif // FLASH_H +#endif // FLASH_H diff --git a/layout.c b/layout.c index 6b3e5538a5..b2a37e177b 100644 --- a/layout.c +++ b/layout.c @@ -22,95 +22,102 @@ #include "layout.h" #include "oled.h" -void layoutButtonNo(const char *btnNo) -{ - oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); - oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); - oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); +void layoutButtonNo(const char *btnNo) { + oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); + oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, + btnNo, FONT_STANDARD); + oledInvert(0, OLED_HEIGHT - 9, + fontCharWidth(FONT_STANDARD, '\x15') + + oledStringWidth(btnNo, FONT_STANDARD) + 2, + OLED_HEIGHT - 1); } -void layoutButtonYes(const char *btnYes) -{ - oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); - oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); - oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); +void layoutButtonYes(const char *btnYes) { + oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, + OLED_HEIGHT - 8, "\x06", FONT_STANDARD); + oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, + OLED_HEIGHT - 8, btnYes, FONT_STANDARD); + oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - + fontCharWidth(FONT_STANDARD, '\x06') - 4, + OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); } -void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) -{ - int left = 0; - oledClear(); - if (icon) { - oledDrawBitmap(0, 0, icon); - left = icon->width + 4; - } - if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD); - if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD); - if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); - if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); - if (desc) { - oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); - if (btnYes || btnNo) { - oledHLine(OLED_HEIGHT - 21); - } - } else { - if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD); - if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD); - if (btnYes || btnNo) { - oledHLine(OLED_HEIGHT - 13); - } - } - if (btnNo) { - layoutButtonNo(btnNo); - } - if (btnYes) { - layoutButtonYes(btnYes); - } - oledRefresh(); +void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, + const char *desc, const char *line1, const char *line2, + const char *line3, const char *line4, const char *line5, + const char *line6) { + int left = 0; + oledClear(); + if (icon) { + oledDrawBitmap(0, 0, icon); + left = icon->width + 4; + } + if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD); + if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD); + if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); + if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); + if (desc) { + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc, + FONT_STANDARD); + if (btnYes || btnNo) { + oledHLine(OLED_HEIGHT - 21); + } + } else { + if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD); + if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD); + if (btnYes || btnNo) { + oledHLine(OLED_HEIGHT - 13); + } + } + if (btnNo) { + layoutButtonNo(btnNo); + } + if (btnYes) { + layoutButtonYes(btnYes); + } + oledRefresh(); } -void layoutProgressUpdate(bool refresh) -{ - static uint8_t step = 0; - switch (step) { - case 0: - oledDrawBitmap(40, 0, &bmp_gears0); - break; - case 1: - oledDrawBitmap(40, 0, &bmp_gears1); - break; - case 2: - oledDrawBitmap(40, 0, &bmp_gears2); - break; - case 3: - oledDrawBitmap(40, 0, &bmp_gears3); - break; - } - step = (step + 1) % 4; - if (refresh) { - oledRefresh(); - } +void layoutProgressUpdate(bool refresh) { + static uint8_t step = 0; + switch (step) { + case 0: + oledDrawBitmap(40, 0, &bmp_gears0); + break; + case 1: + oledDrawBitmap(40, 0, &bmp_gears1); + break; + case 2: + oledDrawBitmap(40, 0, &bmp_gears2); + break; + case 3: + oledDrawBitmap(40, 0, &bmp_gears3); + break; + } + step = (step + 1) % 4; + if (refresh) { + oledRefresh(); + } } -void layoutProgress(const char *desc, int permil) -{ - oledClear(); - layoutProgressUpdate(false); - // progressbar - oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); - oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); - permil = permil * (OLED_WIDTH - 4) / 1000; - if (permil < 0) { - permil = 0; - } - if (permil > OLED_WIDTH - 4) { - permil = OLED_WIDTH - 4; - } - oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); - // text - oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); - if (desc) { - oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 16, desc, FONT_STANDARD); - } - oledRefresh(); +void layoutProgress(const char *desc, int permil) { + oledClear(); + layoutProgressUpdate(false); + // progressbar + oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); + oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); + permil = permil * (OLED_WIDTH - 4) / 1000; + if (permil < 0) { + permil = 0; + } + if (permil > OLED_WIDTH - 4) { + permil = OLED_WIDTH - 4; + } + oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); + // text + oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); + if (desc) { + oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 16, desc, FONT_STANDARD); + } + oledRefresh(); } diff --git a/layout.h b/layout.h index eea0432777..2f662c657f 100644 --- a/layout.h +++ b/layout.h @@ -20,13 +20,16 @@ #ifndef __LAYOUT_H__ #define __LAYOUT_H__ -#include #include +#include #include "bitmaps.h" void layoutButtonNo(const char *btnNo); void layoutButtonYes(const char *btnYes); -void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); +void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, + const char *desc, const char *line1, const char *line2, + const char *line3, const char *line4, const char *line5, + const char *line6); void layoutProgressUpdate(bool refresh); void layoutProgress(const char *desc, int permil); diff --git a/memory.c b/memory.c index b11e046b20..2eaa4368f6 100644 --- a/memory.c +++ b/memory.c @@ -17,38 +17,43 @@ * along with this library. If not, see . */ +#include "memory.h" #include #include -#include "memory.h" #include "sha2.h" #define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000) #define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008) -void memory_protect(void) -{ +void memory_protect(void) { #if MEMORY_PROTECT - // Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf - // Section 2.6 Option bytes - // set RDP level 2 WRP for sectors 0 and 1 flash option control register matches - if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { - return; // already set up correctly - bail out - } - for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_unlock_option_bytes(); - // Section 2.8.6 Flash option control register (FLASH_OPTCR) - // Bits 31:28 Reserved, must be kept cleared. - // Bits 27:16 nWRP: Not write protect: write protect bootloader code in flash main memory sectors 0 and 1 (Section 2.3; table 2) - // Bits 15:8 RDP: Read protect: level 2 chip read protection active - // Bits 7:5 USER: User option bytes: no reset on standby, no reset on stop, software watchdog - // Bit 4 Reserved, must be kept cleared. - // Bits 3:2 BOR_LEV: BOR reset Level: BOR off - // Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes - // Bit 0 OPTLOCK: Option lock: ignored by flash_program_option_bytes - flash_program_option_bytes(0x0FFCCCEC); - flash_lock_option_bytes(); + // Reference STM32F205 Flash programming manual revision 5 + // http://www.st.com/resource/en/programming_manual/cd00233952.pdf Section 2.6 + // Option bytes + // set RDP level 2 WRP for sectors 0 and + // 1 flash option control register matches + if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && + ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && + (FLASH_OPTCR == 0x0FFCCCED)) { + return; // already set up correctly - bail out + } + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; + i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_unlock_option_bytes(); + // Section 2.8.6 Flash option control register (FLASH_OPTCR) + // Bits 31:28 Reserved, must be kept cleared. + // Bits 27:16 nWRP: Not write protect: write protect bootloader code in + // flash main memory sectors 0 and 1 (Section 2.3; table 2) Bits 15:8 RDP: + // Read protect: level 2 chip read protection active Bits 7:5 USER: User + // option bytes: no reset on standby, no reset on stop, software watchdog + // Bit 4 Reserved, must be kept cleared. + // Bits 3:2 BOR_LEV: BOR reset Level: BOR off + // Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes + // Bit 0 OPTLOCK: Option lock: ignored by flash_program_option_bytes + flash_program_option_bytes(0x0FFCCCEC); + flash_lock_option_bytes(); #endif } @@ -62,16 +67,14 @@ void memory_protect(void) // from OPTION_BYTES and not form FLASH_OPCTR register. // // Read protection is unaffected and always stays locked to the desired value. -void memory_write_unlock(void) -{ - flash_unlock_option_bytes(); - flash_program_option_bytes(0x0FFFCCEC); - flash_lock_option_bytes(); +void memory_write_unlock(void) { + flash_unlock_option_bytes(); + flash_program_option_bytes(0x0FFFCCEC); + flash_lock_option_bytes(); } -int memory_bootloader_hash(uint8_t *hash) -{ - sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash); - sha256_Raw(hash, 32, hash); - return 32; +int memory_bootloader_hash(uint8_t *hash) { + sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash); + sha256_Raw(hash, 32, hash); + return 32; } diff --git a/memory.h b/memory.h index e47fc29172..2494eff765 100644 --- a/memory.h +++ b/memory.h @@ -58,47 +58,47 @@ */ -#define FLASH_ORIGIN (0x08000000) +#define FLASH_ORIGIN (0x08000000) #if EMULATOR extern uint8_t *emulator_flash_base; -#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) +#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) #else -#define FLASH_PTR(x) (const uint8_t*) (x) +#define FLASH_PTR(x) (const uint8_t *)(x) #endif -#define FLASH_TOTAL_SIZE (1024 * 1024) +#define FLASH_TOTAL_SIZE (1024 * 1024) -#define FLASH_BOOT_START (FLASH_ORIGIN) -#define FLASH_BOOT_LEN (0x8000) +#define FLASH_BOOT_START (FLASH_ORIGIN) +#define FLASH_BOOT_LEN (0x8000) -#define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN) -#define FLASH_STORAGE_LEN (0x8000) +#define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN) +#define FLASH_STORAGE_LEN (0x8000) #define FLASH_FWHEADER_START (FLASH_STORAGE_START + FLASH_STORAGE_LEN) -#define FLASH_FWHEADER_LEN (0x400) +#define FLASH_FWHEADER_LEN (0x400) -#define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN) -#define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) +#define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN) +#define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) -#define FLASH_BOOT_SECTOR_FIRST 0 -#define FLASH_BOOT_SECTOR_LAST 1 +#define FLASH_BOOT_SECTOR_FIRST 0 +#define FLASH_BOOT_SECTOR_LAST 1 -#define FLASH_STORAGE_SECTOR_FIRST 2 -#define FLASH_STORAGE_SECTOR_LAST 3 +#define FLASH_STORAGE_SECTOR_FIRST 2 +#define FLASH_STORAGE_SECTOR_LAST 3 -#define FLASH_CODE_SECTOR_FIRST 4 -#define FLASH_CODE_SECTOR_LAST 11 +#define FLASH_CODE_SECTOR_FIRST 4 +#define FLASH_CODE_SECTOR_LAST 11 void memory_protect(void); void memory_write_unlock(void); int memory_bootloader_hash(uint8_t *hash); static inline void flash_write32(uint32_t addr, uint32_t word) { - *(volatile uint32_t *) FLASH_PTR(addr) = word; + *(volatile uint32_t *)FLASH_PTR(addr) = word; } static inline void flash_write8(uint32_t addr, uint8_t byte) { - *(volatile uint8_t *) FLASH_PTR(addr) = byte; + *(volatile uint8_t *)FLASH_PTR(addr) = byte; } #endif diff --git a/norcow_config.h b/norcow_config.h index 1ea894c2b5..14fc3d6667 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -23,11 +23,13 @@ #include "flash.h" #define NORCOW_SECTOR_COUNT 2 -#define NORCOW_SECTOR_SIZE (16*1024) -#define NORCOW_SECTORS {2, 3} +#define NORCOW_SECTOR_SIZE (16 * 1024) +#define NORCOW_SECTORS \ + { 2, 3 } /* - * The length of the sector header in bytes. The header is preserved between sector erasures. + * The length of the sector header in bytes. The header is preserved between + * sector erasures. */ #define NORCOW_HEADER_LEN (0) diff --git a/oled.c b/oled.c index 00a03a27e6..d59d880ac5 100644 --- a/oled.c +++ b/oled.c @@ -22,39 +22,39 @@ #include +#include "memzero.h" #include "oled.h" #include "util.h" -#include "memzero.h" -#define OLED_SETCONTRAST 0x81 -#define OLED_DISPLAYALLON_RESUME 0xA4 -#define OLED_DISPLAYALLON 0xA5 -#define OLED_NORMALDISPLAY 0xA6 -#define OLED_INVERTDISPLAY 0xA7 -#define OLED_DISPLAYOFF 0xAE -#define OLED_DISPLAYON 0xAF -#define OLED_SETDISPLAYOFFSET 0xD3 -#define OLED_SETCOMPINS 0xDA -#define OLED_SETVCOMDETECT 0xDB -#define OLED_SETDISPLAYCLOCKDIV 0xD5 -#define OLED_SETPRECHARGE 0xD9 -#define OLED_SETMULTIPLEX 0xA8 -#define OLED_SETLOWCOLUMN 0x00 -#define OLED_SETHIGHCOLUMN 0x10 -#define OLED_SETSTARTLINE 0x40 -#define OLED_MEMORYMODE 0x20 -#define OLED_COMSCANINC 0xC0 -#define OLED_COMSCANDEC 0xC8 -#define OLED_SEGREMAP 0xA0 -#define OLED_CHARGEPUMP 0x8D +#define OLED_SETCONTRAST 0x81 +#define OLED_DISPLAYALLON_RESUME 0xA4 +#define OLED_DISPLAYALLON 0xA5 +#define OLED_NORMALDISPLAY 0xA6 +#define OLED_INVERTDISPLAY 0xA7 +#define OLED_DISPLAYOFF 0xAE +#define OLED_DISPLAYON 0xAF +#define OLED_SETDISPLAYOFFSET 0xD3 +#define OLED_SETCOMPINS 0xDA +#define OLED_SETVCOMDETECT 0xDB +#define OLED_SETDISPLAYCLOCKDIV 0xD5 +#define OLED_SETPRECHARGE 0xD9 +#define OLED_SETMULTIPLEX 0xA8 +#define OLED_SETLOWCOLUMN 0x00 +#define OLED_SETHIGHCOLUMN 0x10 +#define OLED_SETSTARTLINE 0x40 +#define OLED_MEMORYMODE 0x20 +#define OLED_COMSCANINC 0xC0 +#define OLED_COMSCANDEC 0xC8 +#define OLED_SEGREMAP 0xA0 +#define OLED_CHARGEPUMP 0x8D -#define SPI_BASE SPI1 -#define OLED_DC_PORT GPIOB -#define OLED_DC_PIN GPIO0 // PB0 | Data/Command -#define OLED_CS_PORT GPIOA -#define OLED_CS_PIN GPIO4 // PA4 | SPI Select -#define OLED_RST_PORT GPIOB -#define OLED_RST_PIN GPIO1 // PB1 | Reset display +#define SPI_BASE SPI1 +#define OLED_DC_PORT GPIOB +#define OLED_DC_PIN GPIO0 // PB0 | Data/Command +#define OLED_CS_PORT GPIOA +#define OLED_CS_PIN GPIO4 // PA4 | SPI Select +#define OLED_RST_PORT GPIOB +#define OLED_RST_PIN GPIO1 // PB1 | Reset display /* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64). * The contents of this display are buffered in _oledbuffer. This is @@ -70,126 +70,127 @@ static bool is_debug_link = 0; /* * macros to convert coordinate to bit position */ -#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y)/8)*OLED_WIDTH) -#define OLED_MASK(x, y) (1 << (7 - (y) % 8)) +#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y) / 8) * OLED_WIDTH) +#define OLED_MASK(x, y) (1 << (7 - (y) % 8)) /* * Draws a white pixel at x, y */ -void oledDrawPixel(int x, int y) -{ - if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { - return; - } - _oledbuffer[OLED_OFFSET(x, y)] |= OLED_MASK(x, y); +void oledDrawPixel(int x, int y) { + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] |= OLED_MASK(x, y); } /* * Clears pixel at x, y */ -void oledClearPixel(int x, int y) -{ - if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { - return; - } - _oledbuffer[OLED_OFFSET(x, y)] &= ~OLED_MASK(x, y); +void oledClearPixel(int x, int y) { + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] &= ~OLED_MASK(x, y); } /* * Inverts pixel at x, y */ -void oledInvertPixel(int x, int y) -{ - if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { - return; - } - _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y); +void oledInvertPixel(int x, int y) { + if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { + return; + } + _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y); } #if !EMULATOR /* * Send a block of data via the SPI bus. */ -static inline void SPISend(uint32_t base, const uint8_t *data, int len) -{ - delay(1); - for (int i = 0; i < len; i++) { - spi_send(base, data[i]); - } - while (!(SPI_SR(base) & SPI_SR_TXE)); - while ((SPI_SR(base) & SPI_SR_BSY)); +static inline void SPISend(uint32_t base, const uint8_t *data, int len) { + delay(1); + for (int i = 0; i < len; i++) { + spi_send(base, data[i]); + } + while (!(SPI_SR(base) & SPI_SR_TXE)) + ; + while ((SPI_SR(base) & SPI_SR_BSY)) + ; } /* * Initialize the display. */ -void oledInit() -{ - static const uint8_t s[25] = { - OLED_DISPLAYOFF, - OLED_SETDISPLAYCLOCKDIV, - 0x80, - OLED_SETMULTIPLEX, - 0x3F, // 128x64 - OLED_SETDISPLAYOFFSET, - 0x00, - OLED_SETSTARTLINE | 0x00, - OLED_CHARGEPUMP, - 0x14, - OLED_MEMORYMODE, - 0x00, - OLED_SEGREMAP | 0x01, - OLED_COMSCANDEC, - OLED_SETCOMPINS, - 0x12, // 128x64 - OLED_SETCONTRAST, - 0xCF, - OLED_SETPRECHARGE, - 0xF1, - OLED_SETVCOMDETECT, - 0x40, - OLED_DISPLAYALLON_RESUME, - OLED_NORMALDISPLAY, - OLED_DISPLAYON - }; +void oledInit() { + static const uint8_t s[25] = {OLED_DISPLAYOFF, + OLED_SETDISPLAYCLOCKDIV, + 0x80, + OLED_SETMULTIPLEX, + 0x3F, // 128x64 + OLED_SETDISPLAYOFFSET, + 0x00, + OLED_SETSTARTLINE | 0x00, + OLED_CHARGEPUMP, + 0x14, + OLED_MEMORYMODE, + 0x00, + OLED_SEGREMAP | 0x01, + OLED_COMSCANDEC, + OLED_SETCOMPINS, + 0x12, // 128x64 + OLED_SETCONTRAST, + 0xCF, + OLED_SETPRECHARGE, + 0xF1, + OLED_SETVCOMDETECT, + 0x40, + OLED_DISPLAYALLON_RESUME, + OLED_NORMALDISPLAY, + OLED_DISPLAYON}; - gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD - gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect - // Reset the LCD - gpio_set(OLED_RST_PORT, OLED_RST_PIN); - delay(40); - gpio_clear(OLED_RST_PORT, OLED_RST_PIN); - delay(400); - gpio_set(OLED_RST_PORT, OLED_RST_PIN); + // Reset the LCD + gpio_set(OLED_RST_PORT, OLED_RST_PIN); + delay(40); + gpio_clear(OLED_RST_PORT, OLED_RST_PIN); + delay(400); + gpio_set(OLED_RST_PORT, OLED_RST_PIN); - // init - gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select - SPISend(SPI_BASE, s, 25); - gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + // init + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, s, 25); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect - oledClear(); - oledRefresh(); + oledClear(); + oledRefresh(); } #endif /* * Clears the display buffer (sets all pixels to black) */ -void oledClear() -{ - memzero(_oledbuffer, sizeof(_oledbuffer)); -} +void oledClear() { memzero(_oledbuffer, sizeof(_oledbuffer)); } -void oledInvertDebugLink() -{ - if (is_debug_link) { - oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); - oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); - oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); - oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); - oledInvertPixel(OLED_WIDTH - 1, 4); - } +void oledInvertDebugLink() { + if (is_debug_link) { + oledInvertPixel(OLED_WIDTH - 5, 0); + oledInvertPixel(OLED_WIDTH - 4, 0); + oledInvertPixel(OLED_WIDTH - 3, 0); + oledInvertPixel(OLED_WIDTH - 2, 0); + oledInvertPixel(OLED_WIDTH - 1, 0); + oledInvertPixel(OLED_WIDTH - 4, 1); + oledInvertPixel(OLED_WIDTH - 3, 1); + oledInvertPixel(OLED_WIDTH - 2, 1); + oledInvertPixel(OLED_WIDTH - 1, 1); + oledInvertPixel(OLED_WIDTH - 3, 2); + oledInvertPixel(OLED_WIDTH - 2, 2); + oledInvertPixel(OLED_WIDTH - 1, 2); + oledInvertPixel(OLED_WIDTH - 2, 3); + oledInvertPixel(OLED_WIDTH - 1, 3); + oledInvertPixel(OLED_WIDTH - 1, 4); + } } /* @@ -199,225 +200,216 @@ void oledInvertDebugLink() * not the content of the display. */ #if !EMULATOR -void oledRefresh() -{ - static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; +void oledRefresh() { + static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, + OLED_SETHIGHCOLUMN | 0x00, + OLED_SETSTARTLINE | 0x00}; - // draw triangle in upper right corner - oledInvertDebugLink(); + // draw triangle in upper right corner + oledInvertDebugLink(); - gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select - SPISend(SPI_BASE, s, 3); - gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, s, 3); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect - gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA - gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select - SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer)); - gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect - gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD + gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA + gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select + SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer)); + gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect + gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD - // return it back - oledInvertDebugLink(); + // return it back + oledInvertDebugLink(); } #endif -const uint8_t *oledGetBuffer() -{ - return _oledbuffer; +const uint8_t *oledGetBuffer() { return _oledbuffer; } + +void oledSetDebugLink(bool set) { + is_debug_link = set; + oledRefresh(); } -void oledSetDebugLink(bool set) -{ - is_debug_link = set; - oledRefresh(); +void oledSetBuffer(uint8_t *buf) { + memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); } -void oledSetBuffer(uint8_t *buf) -{ - memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); -} +void oledDrawChar(int x, int y, char c, int font) { + if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { + return; + } -void oledDrawChar(int x, int y, char c, int font) -{ - if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { - return; - } + int zoom = (font & FONT_DOUBLE ? 2 : 1); + int char_width = fontCharWidth(font & 0x7f, c); + const uint8_t *char_data = fontCharData(font & 0x7f, c); - int zoom = (font & FONT_DOUBLE ? 2 : 1); - int char_width = fontCharWidth(font & 0x7f, c); - const uint8_t *char_data = fontCharData(font & 0x7f, c); + if (x <= -char_width * zoom) { + return; + } - if (x <= -char_width * zoom) { - return; - } - - for (int xo = 0; xo < char_width; xo++) { - for (int yo = 0; yo < FONT_HEIGHT; yo++) { - if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { - if (zoom <= 1) { - oledDrawPixel(x + xo, y + yo); - } else { - oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true); - } - } - } - } + for (int xo = 0; xo < char_width; xo++) { + for (int yo = 0; yo < FONT_HEIGHT; yo++) { + if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { + if (zoom <= 1) { + oledDrawPixel(x + xo, y + yo); + } else { + oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, + y + (yo + 1) * zoom - 1, true); + } + } + } + } } char oledConvertChar(const char c) { - uint8_t a = c; - if (a < 0x80) return c; - // UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description - // bytes 11xxxxxx are first byte of UTF-8 characters - // bytes 10xxxxxx are successive UTF-8 characters - if (a >= 0xC0) return '_'; - return 0; + uint8_t a = c; + if (a < 0x80) return c; + // UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description + // bytes 11xxxxxx are first byte of UTF-8 characters + // bytes 10xxxxxx are successive UTF-8 characters + if (a >= 0xC0) return '_'; + return 0; } int oledStringWidth(const char *text, int font) { - if (!text) return 0; - int size = (font & FONT_DOUBLE ? 2 : 1); - int l = 0; - for (; *text; text++) { - char c = oledConvertChar(*text); - if (c) { - l += size * (fontCharWidth(font & 0x7f, c) + 1); - } - } - return l; + if (!text) return 0; + int size = (font & FONT_DOUBLE ? 2 : 1); + int l = 0; + for (; *text; text++) { + char c = oledConvertChar(*text); + if (c) { + l += size * (fontCharWidth(font & 0x7f, c) + 1); + } + } + return l; } -void oledDrawString(int x, int y, const char* text, int font) -{ - if (!text) return; - int l = 0; - int size = (font & FONT_DOUBLE ? 2 : 1); - for (; *text; text++) { - char c = oledConvertChar(*text); - if (c) { - oledDrawChar(x + l, y, c, font); - l += size * (fontCharWidth(font & 0x7f, c) + 1); - } - } +void oledDrawString(int x, int y, const char *text, int font) { + if (!text) return; + int l = 0; + int size = (font & FONT_DOUBLE ? 2 : 1); + for (; *text; text++) { + char c = oledConvertChar(*text); + if (c) { + oledDrawChar(x + l, y, c, font); + l += size * (fontCharWidth(font & 0x7f, c) + 1); + } + } } -void oledDrawStringCenter(int x, int y, const char* text, int font) -{ - x = x - oledStringWidth(text, font) / 2; - oledDrawString(x, y, text, font); +void oledDrawStringCenter(int x, int y, const char *text, int font) { + x = x - oledStringWidth(text, font) / 2; + oledDrawString(x, y, text, font); } -void oledDrawStringRight(int x, int y, const char* text, int font) -{ - x -= oledStringWidth(text, font); - oledDrawString(x, y, text, font); +void oledDrawStringRight(int x, int y, const char *text, int font) { + x -= oledStringWidth(text, font); + oledDrawString(x, y, text, font); } -void oledDrawBitmap(int x, int y, const BITMAP *bmp) -{ - for (int i = 0; i < bmp->width; i++) { - for (int j = 0; j < bmp->height; j++) { - if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { - oledDrawPixel(x + i, y + j); - } else { - oledClearPixel(x + i, y + j); - } - } - } +void oledDrawBitmap(int x, int y, const BITMAP *bmp) { + for (int i = 0; i < bmp->width; i++) { + for (int j = 0; j < bmp->height; j++) { + if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { + oledDrawPixel(x + i, y + j); + } else { + oledClearPixel(x + i, y + j); + } + } + } } /* * Inverts box between (x1,y1) and (x2,y2) inclusive. */ -void oledInvert(int x1, int y1, int x2, int y2) -{ - x1 = MAX(x1, 0); - y1 = MAX(y1, 0); - x2 = MIN(x2, OLED_WIDTH - 1); - y2 = MIN(y2, OLED_HEIGHT - 1); - for (int x = x1; x <= x2; x++) { - for (int y = y1; y <= y2; y++) { - oledInvertPixel(x,y); - } - } +void oledInvert(int x1, int y1, int x2, int y2) { + x1 = MAX(x1, 0); + y1 = MAX(y1, 0); + x2 = MIN(x2, OLED_WIDTH - 1); + y2 = MIN(y2, OLED_HEIGHT - 1); + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + oledInvertPixel(x, y); + } + } } /* * Draw a filled rectangle. */ -void oledBox(int x1, int y1, int x2, int y2, bool set) -{ - x1 = MAX(x1, 0); - y1 = MAX(y1, 0); - x2 = MIN(x2, OLED_WIDTH - 1); - y2 = MIN(y2, OLED_HEIGHT - 1); - for (int x = x1; x <= x2; x++) { - for (int y = y1; y <= y2; y++) { - set ? oledDrawPixel(x, y) : oledClearPixel(x, y); - } - } +void oledBox(int x1, int y1, int x2, int y2, bool set) { + x1 = MAX(x1, 0); + y1 = MAX(y1, 0); + x2 = MIN(x2, OLED_WIDTH - 1); + y2 = MIN(y2, OLED_HEIGHT - 1); + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + set ? oledDrawPixel(x, y) : oledClearPixel(x, y); + } + } } void oledHLine(int y) { - if (y < 0 || y >= OLED_HEIGHT) { - return; - } - for (int x = 0; x < OLED_WIDTH; x++) { - oledDrawPixel(x, y); - } + if (y < 0 || y >= OLED_HEIGHT) { + return; + } + for (int x = 0; x < OLED_WIDTH; x++) { + oledDrawPixel(x, y); + } } /* * Draw a rectangle frame. */ -void oledFrame(int x1, int y1, int x2, int y2) -{ - for (int x = x1; x <= x2; x++) { - oledDrawPixel(x, y1); - oledDrawPixel(x, y2); - } - for (int y = y1 + 1; y < y2; y++) { - oledDrawPixel(x1, y); - oledDrawPixel(x2, y); - } +void oledFrame(int x1, int y1, int x2, int y2) { + for (int x = x1; x <= x2; x++) { + oledDrawPixel(x, y1); + oledDrawPixel(x, y2); + } + for (int y = y1 + 1; y < y2; y++) { + oledDrawPixel(x1, y); + oledDrawPixel(x2, y); + } } /* * Animates the display, swiping the current contents out to the left. * This clears the display. */ -void oledSwipeLeft(void) -{ - for (int i = 0; i < OLED_WIDTH; i++) { - for (int j = 0; j < OLED_HEIGHT / 8; j++) { - for (int k = OLED_WIDTH-1; k > 0; k--) { - _oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1]; - } - _oledbuffer[j * OLED_WIDTH] = 0; - } - oledRefresh(); - } +void oledSwipeLeft(void) { + for (int i = 0; i < OLED_WIDTH; i++) { + for (int j = 0; j < OLED_HEIGHT / 8; j++) { + for (int k = OLED_WIDTH - 1; k > 0; k--) { + _oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1]; + } + _oledbuffer[j * OLED_WIDTH] = 0; + } + oledRefresh(); + } } /* * Animates the display, swiping the current contents out to the right. * This clears the display. */ -void oledSwipeRight(void) -{ - for (int i = 0; i < OLED_WIDTH / 4; i++) { - for (int j = 0; j < OLED_HEIGHT / 8; j++) { - for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) { - _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 5 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; - _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 7 + j * OLED_WIDTH]; - } - _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0; - _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0; - _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0; - _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0; - } - oledRefresh(); - } +void oledSwipeRight(void) { + for (int i = 0; i < OLED_WIDTH / 4; i++) { + for (int j = 0; j < OLED_HEIGHT / 8; j++) { + for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) { + _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = + _oledbuffer[k * 4 + 4 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = + _oledbuffer[k * 4 + 5 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = + _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; + _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = + _oledbuffer[k * 4 + 7 + j * OLED_WIDTH]; + } + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0; + _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0; + } + oledRefresh(); + } } diff --git a/oled.h b/oled.h index afc09829bf..a4c9c91ac4 100644 --- a/oled.h +++ b/oled.h @@ -20,14 +20,14 @@ #ifndef __OLED_H__ #define __OLED_H__ -#include #include +#include #include "bitmaps.h" #include "fonts.h" -#define OLED_WIDTH 128 -#define OLED_HEIGHT 64 +#define OLED_WIDTH 128 +#define OLED_HEIGHT 64 #define OLED_BUFSIZE (OLED_WIDTH * OLED_HEIGHT / 8) void oledInit(void); @@ -45,9 +45,9 @@ void oledInvertPixel(int x, int y); void oledDrawChar(int x, int y, char c, int zoom); int oledStringWidth(const char *text, int font); -void oledDrawString(int x, int y, const char* text, int font); -void oledDrawStringCenter(int x, int y, const char* text, int font); -void oledDrawStringRight(int x, int y, const char* text, int font); +void oledDrawString(int x, int y, const char *text, int font); +void oledDrawStringCenter(int x, int y, const char *text, int font); +void oledDrawStringRight(int x, int y, const char *text, int font); void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledInvert(int x1, int y1, int x2, int y2); void oledBox(int x1, int y1, int x2, int y2, bool set); diff --git a/rng.c b/rng.c index 6576d8bb47..6266a82eaa 100644 --- a/rng.c +++ b/rng.c @@ -18,21 +18,20 @@ */ #include -#include #include +#include #include "rng.h" #if !EMULATOR -uint32_t random32(void) -{ - static uint32_t last = 0, new = 0; - while (new == last) { - if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) { - new = RNG_DR; - } - } - last = new; - return new; +uint32_t random32(void) { + static uint32_t last = 0, new = 0; + while (new == last) { + if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) { + new = RNG_DR; + } + } + last = new; + return new; } #endif diff --git a/secbool.h b/secbool.h index 76dfb38dc1..65860dd76f 100644 --- a/secbool.h +++ b/secbool.h @@ -23,11 +23,11 @@ #include typedef uint32_t secbool; -#define sectrue 0xAAAAAAAAU +#define sectrue 0xAAAAAAAAU #define secfalse 0x00000000U #ifndef __wur -#define __wur __attribute__ ((warn_unused_result)) +#define __wur __attribute__((warn_unused_result)) #endif #endif diff --git a/setup.c b/setup.c index 1353013007..62cedf7ef9 100644 --- a/setup.c +++ b/setup.c @@ -20,249 +20,264 @@ #include #include #include -#include #include -#include +#include #include +#include -#include "rng.h" #include "layout.h" +#include "rng.h" #include "util.h" uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); - shutdown(); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, + "Please unplug", "the device.", NULL); + shutdown(); } void __attribute__((noreturn)) __stack_chk_fail(void) { - fault_handler("Stack smashing"); + fault_handler("Stack smashing"); } -void nmi_handler(void) -{ - // Clock Security System triggered NMI - if ((RCC_CIR & RCC_CIR_CSSF) != 0) { - fault_handler("Clock instability"); - } +void nmi_handler(void) { + // Clock Security System triggered NMI + if ((RCC_CIR & RCC_CIR_CSSF) != 0) { + fault_handler("Clock instability"); + } } -void hard_fault_handler(void) { - fault_handler("Hard fault"); +void hard_fault_handler(void) { fault_handler("Hard fault"); } + +void mem_manage_handler(void) { fault_handler("Memory fault"); } + +void setup(void) { + // set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception + // entry is in effect. This is not strictly necessary for the current TREZOR + // system. This is here to comply with guidance from section 3.3.3 "Binary + // compatibility with other Cortex processors" of the ARM Cortex-M3 Processor + // Technical Reference Manual. According to section 4.4.2 and 4.4.7 of the + // "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", STM32F2 + // series MCUs are r2p0 and always have this bit set on reset already. + SCB_CCR |= SCB_CCR_STKALIGN; + + // setup clock + struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; + rcc_clock_setup_hse_3v3(&clock); + + // enable GPIO clock - A (oled), B(oled), C (buttons) + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOC); + + // enable SPI clock + rcc_periph_clock_enable(RCC_SPI1); + + // enable RNG + rcc_periph_clock_enable(RCC_RNG); + RNG_CR |= RNG_CR_RNGEN; + // to be extra careful and heed the STM32F205xx Reference manual, + // Section 20.3.1 we don't use the first random number generated after setting + // the RNGEN bit in setup + random32(); + + // enable CSS (Clock Security System) + RCC_CR |= RCC_CR_CSSON; + + // set GPIO for buttons + gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5); + + // set GPIO for OLED display + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); + gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1); + + // enable SPI 1 for OLED display + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); + gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); + + // spi_disable_crc(SPI1); + spi_init_master( + SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); + spi_enable_ss_output(SPI1); + // spi_enable_software_slave_management(SPI1); + // spi_set_nss_high(SPI1); + // spi_clear_mode_fault(SPI1); + spi_enable(SPI1); + + // enable OTG_FS + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO10 | GPIO11 | GPIO12); + + // enable OTG FS clock + rcc_periph_clock_enable(RCC_OTGFS); + // clear USB OTG_FS peripheral dedicated RAM + memset_reg((void *)0x50020000, (void *)0x50020500, 0); } -void mem_manage_handler(void) { - fault_handler("Memory fault"); +void setupApp(void) { + // for completeness, disable RNG peripheral interrupts for old bootloaders + // that had enabled them in RNG control register (the RNG interrupt was never + // enabled in the NVIC) + RNG_CR &= ~RNG_CR_IE; + // the static variables in random32 are separate between the bootloader and + // firmware. therefore, they need to be initialized here so that we can be + // sure to avoid dupes. this is to try to comply with STM32F205xx Reference + // manual - Section 20.3.1: "Each subsequent generated random number has to be + // compared with the previously generated number. The test fails if any two + // compared numbers are equal (continuous random number generator test)." + random32(); + + // enable CSS (Clock Security System) + RCC_CR |= RCC_CR_CSSON; + + // hotfix for old bootloader + gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); + spi_init_master( + SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, + SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); + gpio_set_af(GPIOA, GPIO_AF10, GPIO10); } -void setup(void) -{ - // set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect. - // This is not strictly necessary for the current TREZOR system. - // This is here to comply with guidance from section 3.3.3 "Binary compatibility with other Cortex processors" - // of the ARM Cortex-M3 Processor Technical Reference Manual. - // According to section 4.4.2 and 4.4.7 of the "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", - // STM32F2 series MCUs are r2p0 and always have this bit set on reset already. - SCB_CCR |= SCB_CCR_STKALIGN; - - // setup clock - struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ]; - rcc_clock_setup_hse_3v3(&clock); - - // enable GPIO clock - A (oled), B(oled), C (buttons) - rcc_periph_clock_enable(RCC_GPIOA); - rcc_periph_clock_enable(RCC_GPIOB); - rcc_periph_clock_enable(RCC_GPIOC); - - // enable SPI clock - rcc_periph_clock_enable(RCC_SPI1); - - // enable RNG - rcc_periph_clock_enable(RCC_RNG); - RNG_CR |= RNG_CR_RNGEN; - // to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1 - // we don't use the first random number generated after setting the RNGEN bit in setup - random32(); - - // enable CSS (Clock Security System) - RCC_CR |= RCC_CR_CSSON; - - // set GPIO for buttons - gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5); - - // set GPIO for OLED display - gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4); - gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1); - - // enable SPI 1 for OLED display - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7); - gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); - -// spi_disable_crc(SPI1); - spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); - spi_enable_ss_output(SPI1); -// spi_enable_software_slave_management(SPI1); -// spi_set_nss_high(SPI1); -// spi_clear_mode_fault(SPI1); - spi_enable(SPI1); - - // enable OTG_FS - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12); - gpio_set_af(GPIOA, GPIO_AF10, GPIO10 | GPIO11 | GPIO12); - - // enable OTG FS clock - rcc_periph_clock_enable(RCC_OTGFS); - // clear USB OTG_FS peripheral dedicated RAM - memset_reg((void *) 0x50020000, (void *) 0x50020500, 0); -} - -void setupApp(void) -{ - // for completeness, disable RNG peripheral interrupts for old bootloaders that had - // enabled them in RNG control register (the RNG interrupt was never enabled in the NVIC) - RNG_CR &= ~RNG_CR_IE; - // the static variables in random32 are separate between the bootloader and firmware. - // therefore, they need to be initialized here so that we can be sure to avoid dupes. - // this is to try to comply with STM32F205xx Reference manual - Section 20.3.1: - // "Each subsequent generated random number has to be compared with the previously generated - // number. The test fails if any two compared numbers are equal (continuous random number generator test)." - random32(); - - // enable CSS (Clock Security System) - RCC_CR |= RCC_CR_CSSON; - - // hotfix for old bootloader - gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); - spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); - - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); - gpio_set_af(GPIOA, GPIO_AF10, GPIO10); -} - -#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) -#define MPU_RASR_SIZE_4GB (0x1FUL << MPU_RASR_SIZE_LSB) +#define MPU_RASR_SIZE_4GB (0x1FUL << MPU_RASR_SIZE_LSB) // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html -#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) -#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) +#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) +#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) #define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_B | MPU_RASR_ATTR_S) -#define FLASH_BASE (0x08000000U) -#define SRAM_BASE (0x20000000U) +#define FLASH_BASE (0x08000000U) +#define SRAM_BASE (0x20000000U) -void mpu_config_off(void) -{ - // Disable MPU - MPU_CTRL = 0; +void mpu_config_off(void) { + // Disable MPU + MPU_CTRL = 0; - __asm__ volatile("dsb"); - __asm__ volatile("isb"); + __asm__ volatile("dsb"); + __asm__ volatile("isb"); } -void mpu_config_bootloader(void) -{ - // Disable MPU - MPU_CTRL = 0; +void mpu_config_bootloader(void) { + // Disable MPU + MPU_CTRL = 0; - // Note: later entries overwrite previous ones + // Note: later entries overwrite previous ones - // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) - MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB | MPU_RASR_ATTR_AP_PRW_URW; + // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) + MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB | + MPU_RASR_ATTR_AP_PRW_URW; - // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) - MPU_RBAR = (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B | MPU_RASR_ATTR_AP_PNO_UNO; + // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) + MPU_RBAR = + (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B | + MPU_RASR_ATTR_AP_PNO_UNO; - // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) - MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) - MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) - MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Don't enable DMA controller access - // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) - MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) + MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) + MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Don't enable DMA controller access + // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) + MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Enable MPU - MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; + // Enable MPU + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; - // Enable memory fault handler - SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; - __asm__ volatile("dsb"); - __asm__ volatile("isb"); + __asm__ volatile("dsb"); + __asm__ volatile("isb"); } // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) -void mpu_config_firmware(void) -{ +void mpu_config_firmware(void) { #if MEMORY_PROTECT - // Disable MPU - MPU_CTRL = 0; + // Disable MPU + MPU_CTRL = 0; - // Note: later entries overwrite previous ones + // Note: later entries overwrite previous ones - // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) - MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRO_URO; + // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) + MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | + MPU_RASR_ATTR_AP_PRO_URO; - // Metadata in Flash is read-write when unlocked - // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) - MPU_RBAR = (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Metadata in Flash is read-write when unlocked + // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) + MPU_RBAR = + (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) - MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) + MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) - MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) - MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // Flash controller is protected - // (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never) - MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; - // Don't enable DMA controller access - // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) - MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; - // SYSCFG_* registers are disabled - // (0x40013800 - 0x40013BFF, read-only, execute never) - MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); - MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; + // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) + MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) + MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // Flash controller is protected + // (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never) + MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; + // Don't enable DMA controller access + // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) + MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | + MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; + // SYSCFG_* registers are disabled + // (0x40013800 - 0x40013BFF, read-only, execute never) + MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); + MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | + MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; - // Enable MPU - MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; + // Enable MPU + MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; - // Enable memory fault handler - SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; + // Enable memory fault handler + SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; - __asm__ volatile("dsb"); - __asm__ volatile("isb"); + __asm__ volatile("dsb"); + __asm__ volatile("isb"); - // Switch to unprivileged software execution to prevent access to MPU - set_mode_unprivileged(); + // Switch to unprivileged software execution to prevent access to MPU + set_mode_unprivileged(); #endif } diff --git a/shell.nix b/shell.nix index 1404234d55..87f5ce3442 100644 --- a/shell.nix +++ b/shell.nix @@ -5,5 +5,5 @@ let in stdenv.mkDerivation { name = "trezor-mcu-dev"; - buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image ]; + buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image clang-tools ]; } diff --git a/supervise.c b/supervise.c index 5a86db884c..445881405b 100644 --- a/supervise.c +++ b/supervise.c @@ -17,77 +17,75 @@ * along with this library. If not, see . */ +#include "supervise.h" #include #include -#include "supervise.h" #include "memory.h" #if !EMULATOR static void svhandler_flash_unlock(void) { - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); } static void svhandler_flash_program(uint32_t psize) { - /* Wait for any write operation to complete. */ - flash_wait_for_last_operation(); - /* check program size argument */ - if (psize != FLASH_CR_PROGRAM_X8 - && psize != FLASH_CR_PROGRAM_X16 - && psize != FLASH_CR_PROGRAM_X32 - && psize != FLASH_CR_PROGRAM_X64) - return; - FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) - | (psize << FLASH_CR_PROGRAM_SHIFT); - FLASH_CR |= FLASH_CR_PG; + /* Wait for any write operation to complete. */ + flash_wait_for_last_operation(); + /* check program size argument */ + if (psize != FLASH_CR_PROGRAM_X8 && psize != FLASH_CR_PROGRAM_X16 && + psize != FLASH_CR_PROGRAM_X32 && psize != FLASH_CR_PROGRAM_X64) + return; + FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) | + (psize << FLASH_CR_PROGRAM_SHIFT); + FLASH_CR |= FLASH_CR_PG; } static void svhandler_flash_erase_sector(uint16_t sector) { - /* we only allow erasing storage sectors 2 and 3. */ - if (sector < FLASH_STORAGE_SECTOR_FIRST || - sector > FLASH_STORAGE_SECTOR_LAST) { - return; - } - flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); + /* we only allow erasing storage sectors 2 and 3. */ + if (sector < FLASH_STORAGE_SECTOR_FIRST || + sector > FLASH_STORAGE_SECTOR_LAST) { + return; + } + flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); } static uint32_t svhandler_flash_lock(void) { - /* Wait for any write operation to complete. */ - flash_wait_for_last_operation(); - /* Disable writes to flash. */ - FLASH_CR &= ~FLASH_CR_PG; - /* lock flash register */ - FLASH_CR |= FLASH_CR_LOCK; - /* return flash status register */ - return FLASH_SR; + /* Wait for any write operation to complete. */ + flash_wait_for_last_operation(); + /* Disable writes to flash. */ + FLASH_CR &= ~FLASH_CR_PG; + /* lock flash register */ + FLASH_CR |= FLASH_CR_LOCK; + /* return flash status register */ + return FLASH_SR; } extern volatile uint32_t system_millis; void svc_handler_main(uint32_t *stack) { - uint8_t svc_number = ((uint8_t*) stack[6])[-2]; - switch (svc_number) { - case SVC_FLASH_UNLOCK: - svhandler_flash_unlock(); - break; - case SVC_FLASH_PROGRAM: - svhandler_flash_program(stack[0]); - break; - case SVC_FLASH_ERASE: - svhandler_flash_erase_sector(stack[0]); - break; - case SVC_FLASH_LOCK: - stack[0] = svhandler_flash_lock(); - break; - case SVC_TIMER_MS: - stack[0] = system_millis; - break; - default: - stack[0] = 0xffffffff; - break; - } + uint8_t svc_number = ((uint8_t *)stack[6])[-2]; + switch (svc_number) { + case SVC_FLASH_UNLOCK: + svhandler_flash_unlock(); + break; + case SVC_FLASH_PROGRAM: + svhandler_flash_program(stack[0]); + break; + case SVC_FLASH_ERASE: + svhandler_flash_erase_sector(stack[0]); + break; + case SVC_FLASH_LOCK: + stack[0] = svhandler_flash_lock(); + break; + case SVC_TIMER_MS: + stack[0] = system_millis; + break; + default: + stack[0] = 0xffffffff; + break; + } } #endif diff --git a/supervise.h b/supervise.h index 1457568a6e..6b7bed1c8f 100644 --- a/supervise.h +++ b/supervise.h @@ -22,18 +22,20 @@ #if !EMULATOR -#define SVC_FLASH_UNLOCK 0 -#define SVC_FLASH_ERASE 1 +#include + +#define SVC_FLASH_UNLOCK 0 +#define SVC_FLASH_ERASE 1 #define SVC_FLASH_PROGRAM 2 -#define SVC_FLASH_LOCK 3 -#define SVC_TIMER_MS 4 +#define SVC_FLASH_LOCK 3 +#define SVC_TIMER_MS 4 /* Unlocks flash. This function needs to be called before programming * or erasing. Multiple calls of flash_program and flash_erase can * follow and should be completed with flash_lock(). */ inline void svc_flash_unlock(void) { - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_UNLOCK) : "memory"); + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_UNLOCK) : "memory"); } /* Enable flash write operations. @@ -41,32 +43,32 @@ inline void svc_flash_unlock(void) { * should be one of the FLASH_CR_PROGRAM_X.. constants */ inline void svc_flash_program(uint32_t program_size) { - register uint32_t r0 __asm__("r0") = program_size; - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_PROGRAM), "r" (r0) : "memory"); + register uint32_t r0 __asm__("r0") = program_size; + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_PROGRAM), "r"(r0) : "memory"); } /* Erase a flash sector. - * @param sector sector number 0..11 + * @param sector sector number 0..11 * (this only allows erasing meta sectors 2 and 3 though). */ inline void svc_flash_erase_sector(uint8_t sector) { - register uint32_t r0 __asm__("r0") = sector; - __asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_ERASE), "r" (r0) : "memory"); + register uint32_t r0 __asm__("r0") = sector; + __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_ERASE), "r"(r0) : "memory"); } /* Lock flash after programming or erasing. * @return flash status register (FLASH_SR) */ inline uint32_t svc_flash_lock(void) { - register uint32_t r0 __asm__("r0"); - __asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_FLASH_LOCK) : "memory"); - return r0; + register uint32_t r0 __asm__("r0"); + __asm__ __volatile__("svc %1" : "=r"(r0) : "i"(SVC_FLASH_LOCK) : "memory"); + return r0; } inline uint32_t svc_timer_ms(void) { - register uint32_t r0 __asm__("r0"); - __asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_TIMER_MS) : "memory"); - return r0; + register uint32_t r0 __asm__("r0"); + __asm__ __volatile__("svc %1" : "=r"(r0) : "i"(SVC_TIMER_MS) : "memory"); + return r0; } #else diff --git a/timer.c b/timer.c index 93f0eb0ca0..0fea37d82b 100644 --- a/timer.c +++ b/timer.c @@ -17,12 +17,11 @@ * along with this library. If not, see . */ - #include "timer.h" -#include #include #include +#include /* 1 tick = 1 ms */ extern volatile uint32_t system_millis; @@ -31,32 +30,30 @@ extern volatile uint32_t system_millis; * Initialise the Cortex-M3 SysTick timer */ void timer_init(void) { - system_millis = 0; + system_millis = 0; - /* - * MCU clock (120 MHz) as source - * - * (120 MHz / 8) = 15 clock pulses - * - */ - systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); - STK_CVR = 0; + /* + * MCU clock (120 MHz) as source + * + * (120 MHz / 8) = 15 clock pulses + * + */ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); + STK_CVR = 0; - /* - * 1 tick = 1 ms @ 120 MHz - * - * (15 clock pulses * 1000 ms) = 15000 clock pulses - * - * Send an interrupt every (N - 1) clock pulses - */ - systick_set_reload(14999); + /* + * 1 tick = 1 ms @ 120 MHz + * + * (15 clock pulses * 1000 ms) = 15000 clock pulses + * + * Send an interrupt every (N - 1) clock pulses + */ + systick_set_reload(14999); - /* SysTick as interrupt */ - systick_interrupt_enable(); + /* SysTick as interrupt */ + systick_interrupt_enable(); - systick_counter_enable(); + systick_counter_enable(); } -void sys_tick_handler(void) { - system_millis++; -} +void sys_tick_handler(void) { system_millis++; } diff --git a/usb21_standard.c b/usb21_standard.c index d6aab2bfd9..9538285aaf 100644 --- a/usb21_standard.c +++ b/usb21_standard.c @@ -16,82 +16,79 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "usb21_standard.h" #include #include #include "util.h" -#include "usb21_standard.h" static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, - uint8_t *buf, uint16_t len) -{ - uint8_t *tmpbuf = buf; - uint16_t count, total = 0, totallen = 0; - uint16_t i; + uint8_t *buf, uint16_t len) { + uint8_t *tmpbuf = buf; + uint16_t count, total = 0, totallen = 0; + uint16_t i; - memcpy(buf, bos, count = MIN(len, bos->bLength)); - buf += count; - len -= count; - total += count; - totallen += bos->bLength; + memcpy(buf, bos, count = MIN(len, bos->bLength)); + buf += count; + len -= count; + total += count; + totallen += bos->bLength; - /* For each device capability */ - for (i = 0; i < bos->bNumDeviceCaps; i++) { - /* Copy device capability descriptor. */ - const struct usb_device_capability_descriptor *cap = - bos->capabilities[i]; + /* For each device capability */ + for (i = 0; i < bos->bNumDeviceCaps; i++) { + /* Copy device capability descriptor. */ + const struct usb_device_capability_descriptor *cap = bos->capabilities[i]; - memcpy(buf, cap, count = MIN(len, cap->bLength)); - buf += count; - len -= count; - total += count; - totallen += cap->bLength; - } + memcpy(buf, cap, count = MIN(len, cap->bLength)); + buf += count; + len -= count; + total += count; + totallen += cap->bLength; + } - /* Fill in wTotalLength. */ - *(uint16_t *)(tmpbuf + 2) = totallen; + /* Fill in wTotalLength. */ + *(uint16_t *)(tmpbuf + 2) = totallen; - return total; + return total; } -static const struct usb_bos_descriptor* usb21_bos; +static const struct usb_bos_descriptor *usb21_bos; -static int usb21_standard_get_descriptor(usbd_device* usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; +static int usb21_standard_get_descriptor( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete) { + (void)complete; + (void)usbd_dev; - wait_random(); + wait_random(); - if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { - int descr_type = req->wValue >> 8; - if (descr_type == USB_DT_BOS) { - if (!usb21_bos) { - return USBD_REQ_NOTSUPP; - } - *len = MIN_8bits(*len, build_bos_descriptor(usb21_bos, *buf, *len)); - return USBD_REQ_HANDLED; - } - } + if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { + int descr_type = req->wValue >> 8; + if (descr_type == USB_DT_BOS) { + if (!usb21_bos) { + return USBD_REQ_NOTSUPP; + } + *len = MIN_8bits(*len, build_bos_descriptor(usb21_bos, *buf, *len)); + return USBD_REQ_HANDLED; + } + } - return USBD_REQ_NEXT_CALLBACK; + return USBD_REQ_NEXT_CALLBACK; } -static void usb21_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; +static void usb21_set_config(usbd_device *usbd_dev, uint16_t wValue) { + (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - &usb21_standard_get_descriptor); + usbd_register_control_callback( + usbd_dev, USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + &usb21_standard_get_descriptor); } -void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store) { - usb21_bos = binary_object_store; +void usb21_setup(usbd_device *usbd_dev, + const struct usb_bos_descriptor *binary_object_store) { + usb21_bos = binary_object_store; - /* Register the control request handler _before_ the config is set */ - usb21_set_config(usbd_dev, 0x0000); - usbd_register_set_config_callback(usbd_dev, usb21_set_config); + /* Register the control request handler _before_ the config is set */ + usb21_set_config(usbd_dev, 0x0000); + usbd_register_set_config_callback(usbd_dev, usb21_set_config); } diff --git a/usb21_standard.h b/usb21_standard.h index e5358bcd5f..41637db910 100644 --- a/usb21_standard.h +++ b/usb21_standard.h @@ -22,29 +22,30 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 -#define USB_DT_DEVICE_CAPABILITY 16 +#define USB_DT_BOS 15 +#define USB_DT_DEVICE_CAPABILITY 16 struct usb_device_capability_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; } __attribute__((packed)); struct usb_bos_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumDeviceCaps; - /* Descriptor ends here. The following are used internally: */ - const struct usb_device_capability_descriptor **capabilities; + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; + /* Descriptor ends here. The following are used internally: */ + const struct usb_device_capability_descriptor** capabilities; } __attribute__((packed)); #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_PLATFORM 5 +#define USB_DC_PLATFORM 5 -extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); +extern void usb21_setup(usbd_device* usbd_dev, + const struct usb_bos_descriptor* binary_object_store); #endif diff --git a/usb_private.h b/usb_private.h index bb553be32e..862e770675 100644 --- a/usb_private.h +++ b/usb_private.h @@ -1,3 +1,4 @@ +// clang-format off /** @defgroup usb_private_defines USB Private Structures @brief Defined Constants and Types for the USB Private Structures diff --git a/usb_standard.c b/usb_standard.c index 3576c289c0..8ac1792362 100644 --- a/usb_standard.c +++ b/usb_standard.c @@ -1,3 +1,4 @@ +// clang-format off /** @defgroup usb_standard_file Generic USB Standard Request Interface @ingroup USB diff --git a/util.c b/util.c index 7d32092a8f..5a96381de2 100644 --- a/util.c +++ b/util.c @@ -17,71 +17,66 @@ * along with this library. If not, see . */ -#include "rng.h" #include "util.h" +#include "rng.h" -inline void delay(uint32_t wait) -{ - while (--wait > 0) __asm__("nop"); +inline void delay(uint32_t wait) { + while (--wait > 0) __asm__("nop"); } -void wait_random(void) -{ - int wait = random32() & 0xff; - volatile int i = 0; - volatile int j = wait; - while (i < wait) { - if (i + j != wait) { - shutdown(); - } - ++i; - --j; - } - // Double-check loop completion. - if (i != wait || j != 0) { - shutdown(); +void wait_random(void) { + int wait = random32() & 0xff; + volatile int i = 0; + volatile int j = wait; + while (i < wait) { + if (i + j != wait) { + shutdown(); } + ++i; + --j; + } + // Double-check loop completion. + if (i != wait || j != 0) { + shutdown(); + } } static const char *hexdigits = "0123456789ABCDEF"; -void uint32hex(uint32_t num, char *str) -{ - for (uint32_t i = 0; i < 8; i++) { - str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; - } +void uint32hex(uint32_t num, char *str) { + for (uint32_t i = 0; i < 8; i++) { + str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; + } } // converts data to hexa -void data2hex(const void *data, uint32_t len, char *str) -{ - const uint8_t *cdata = (uint8_t *)data; - for (uint32_t i = 0; i < len; i++) { - str[i * 2 ] = hexdigits[(cdata[i] >> 4) & 0xF]; - str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; - } - str[len * 2] = 0; +void data2hex(const void *data, uint32_t len, char *str) { + const uint8_t *cdata = (uint8_t *)data; + for (uint32_t i = 0; i < len; i++) { + str[i * 2] = hexdigits[(cdata[i] >> 4) & 0xF]; + str[i * 2 + 1] = hexdigits[cdata[i] & 0xF]; + } + str[len * 2] = 0; } -uint32_t readprotobufint(const uint8_t **ptr) -{ - uint32_t result = (**ptr & 0x7F); - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128 * 128; - if (**ptr & 0x80) { - (*ptr)++; - result += (**ptr & 0x7F) * 128 * 128 * 128 * 128; - } - } - } - } - (*ptr)++; - return result; +uint32_t readprotobufint(const uint8_t **ptr) { + uint32_t result = (**ptr & 0x7F); + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128; + if (**ptr & 0x80) { + (*ptr)++; + result += (**ptr & 0x7F) * 128 * 128 * 128 * 128; + } + } + } + } + (*ptr)++; + return result; } diff --git a/util.h b/util.h index c96a79b6e5..75db5a866e 100644 --- a/util.h +++ b/util.h @@ -20,9 +20,9 @@ #ifndef __UTIL_H_ #define __UTIL_H_ -#include -#include #include +#include +#include #if !EMULATOR #include @@ -31,9 +31,24 @@ #endif // Statement expressions make these macros side-effect safe -#define MIN_8bits(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? (_a & 0xFF) : (_b & 0xFF); }) -#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) -#define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#define MIN_8bits(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a < _b ? (_a & 0xFF) : (_b & 0xFF); \ + }) +#define MIN(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) +#define MAX(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) void delay(uint32_t wait); @@ -59,47 +74,44 @@ extern uint8_t _stack[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); -#define FW_SIGNED 0x5A3CA5C3 -#define FW_UNTRUSTED 0x00000000 +#define FW_SIGNED 0x5A3CA5C3 +#define FW_UNTRUSTED 0x00000000 -static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table_t *vector_table, int trust) -{ - if (FW_SIGNED == trust) { // trusted signed firmware - SCB_VTOR = (uint32_t)vector_table; // * relocate vector table - // Set stack pointer - __asm__ volatile("msr msp, %0" :: "r" (vector_table->initial_sp_value)); - } else { // untrusted firmware - timer_init(); - mpu_config_firmware(); // * configure MPU for the firmware - __asm__ volatile("msr msp, %0" :: "r" (_stack)); - } +static inline void __attribute__((noreturn)) +jump_to_firmware(const vector_table_t *vector_table, int trust) { + if (FW_SIGNED == trust) { // trusted signed firmware + SCB_VTOR = (uint32_t)vector_table; // * relocate vector table + // Set stack pointer + __asm__ volatile("msr msp, %0" ::"r"(vector_table->initial_sp_value)); + } else { // untrusted firmware + timer_init(); + mpu_config_firmware(); // * configure MPU for the firmware + __asm__ volatile("msr msp, %0" ::"r"(_stack)); + } - // Jump to address - vector_table->reset(); + // Jump to address + vector_table->reset(); - // Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) - for (;;); + // Prevent compiler from generating stack protector code (which causes CPU + // fault because the stack is moved) + for (;;) + ; } -static inline void set_mode_unprivileged(void) -{ - // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html - __asm__ volatile("msr control, %0" :: "r" (0x1)); +static inline void set_mode_unprivileged(void) { + // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html + __asm__ volatile("msr control, %0" ::"r"(0x1)); } -static inline bool is_mode_unprivileged(void) -{ - uint32_t r0; - __asm__ volatile("mrs %0, control" : "=r" (r0)); - return r0 & 1; +static inline bool is_mode_unprivileged(void) { + uint32_t r0; + __asm__ volatile("mrs %0, control" : "=r"(r0)); + return r0 & 1; } #else /* EMULATOR */ -static inline bool is_mode_unprivileged(void) -{ - return true; -} +static inline bool is_mode_unprivileged(void) { return true; } #endif #endif diff --git a/webusb.c b/webusb.c index 21c6d3b5e7..24ca5ee192 100644 --- a/webusb.c +++ b/webusb.c @@ -18,90 +18,87 @@ #include +#include "usb21_standard.h" #include "util.h" #include "webusb.h" -#include "usb21_standard.h" -const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { - .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DC_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = WEBUSB_UUID, - .bcdVersion = 0x0100, - .bVendorCode = WEBUSB_VENDOR_CODE, - .iLandingPage = 1 -}; +const struct webusb_platform_descriptor webusb_platform_capability_descriptor = + {.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 1}; -const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page = { - .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_DC_PLATFORM, - .bReserved = 0, - .platformCapabilityUUID = WEBUSB_UUID, - .bcdVersion = 0x0100, - .bVendorCode = WEBUSB_VENDOR_CODE, - .iLandingPage = 0 -}; +const struct webusb_platform_descriptor + webusb_platform_capability_descriptor_no_landing_page = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 0}; static const char* webusb_https_url; -static int webusb_control_vendor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; +static int webusb_control_vendor_request( + usbd_device* usbd_dev, struct usb_setup_data* req, uint8_t** buf, + uint16_t* len, usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; - wait_random(); + wait_random(); - if (req->bRequest != WEBUSB_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } + if (req->bRequest != WEBUSB_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } - int status = USBD_REQ_NOTSUPP; - switch (req->wIndex) { - case WEBUSB_REQ_GET_URL: { - struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); - uint16_t index = req->wValue; - if (index == 0) { - return USBD_REQ_NOTSUPP; - } + int status = USBD_REQ_NOTSUPP; + switch (req->wIndex) { + case WEBUSB_REQ_GET_URL: { + struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); + uint16_t index = req->wValue; + if (index == 0) { + return USBD_REQ_NOTSUPP; + } - if (index == 1) { - size_t url_len = strlen(webusb_https_url); - url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; - url->bDescriptorType = WEBUSB_DT_URL; - url->bScheme = WEBUSB_URL_SCHEME_HTTPS; - memcpy(&url->URL, webusb_https_url, url_len); - *len = MIN_8bits(*len, url->bLength); - status = USBD_REQ_HANDLED; - } else { - // TODO: stall instead? - status = USBD_REQ_NOTSUPP; - } - break; - } - default: { - status = USBD_REQ_NOTSUPP; - break; - } - } + if (index == 1) { + size_t url_len = strlen(webusb_https_url); + url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; + url->bDescriptorType = WEBUSB_DT_URL; + url->bScheme = WEBUSB_URL_SCHEME_HTTPS; + memcpy(&url->URL, webusb_https_url, url_len); + *len = MIN_8bits(*len, url->bLength); + status = USBD_REQ_HANDLED; + } else { + // TODO: stall instead? + status = USBD_REQ_NOTSUPP; + } + break; + } + default: { + status = USBD_REQ_NOTSUPP; + break; + } + } - return status; + return status; } static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - webusb_control_vendor_request); + (void)wValue; + usbd_register_control_callback(usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + webusb_control_vendor_request); } void webusb_setup(usbd_device* usbd_dev, const char* https_url) { - webusb_https_url = https_url; + webusb_https_url = https_url; - usbd_register_set_config_callback(usbd_dev, webusb_set_config); + usbd_register_set_config_callback(usbd_dev, webusb_set_config); } diff --git a/webusb.h b/webusb.h index c7f5dc78fa..01feda4e5b 100644 --- a/webusb.h +++ b/webusb.h @@ -25,8 +25,10 @@ // Arbitrary #define WEBUSB_VENDOR_CODE 0x01 -extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; -extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page; +extern const struct webusb_platform_descriptor + webusb_platform_capability_descriptor; +extern const struct webusb_platform_descriptor + webusb_platform_capability_descriptor_no_landing_page; extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); diff --git a/webusb_defs.h b/webusb_defs.h index 45b5f2478d..b8566f12c8 100644 --- a/webusb_defs.h +++ b/webusb_defs.h @@ -21,7 +21,7 @@ #include -#define WEBUSB_REQ_GET_URL 0x02 +#define WEBUSB_REQ_GET_URL 0x02 #define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 #define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 @@ -32,28 +32,33 @@ #define WEBUSB_URL_SCHEME_HTTPS 1 struct webusb_platform_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDevCapabilityType; - uint8_t bReserved; - uint8_t platformCapabilityUUID[16]; - uint16_t bcdVersion; - uint8_t bVendorCode; - uint8_t iLandingPage; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t platformCapabilityUUID[16]; + uint16_t bcdVersion; + uint8_t bVendorCode; + uint8_t iLandingPage; } __attribute__((packed)); -#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) +#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE \ + sizeof(struct webusb_platform_descriptor) // from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor // see also this (for endianness explanation) // https://github.com/WICG/webusb/issues/115#issuecomment-352206549 -#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} +#define WEBUSB_UUID \ + { \ + 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, \ + 0x88, 0x15, 0xB6, 0x65 \ + } struct webusb_url_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bScheme; - char URL[]; + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char URL[]; } __attribute__((packed)); #define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 diff --git a/winusb.c b/winusb.c index 06321fd3dd..ebd8072466 100644 --- a/winusb.c +++ b/winusb.c @@ -16,150 +16,143 @@ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "winusb.h" #include #include "util.h" -#include "winusb.h" -static int usb_descriptor_type(uint16_t wValue) { - return wValue >> 8; -} +static int usb_descriptor_type(uint16_t wValue) { return wValue >> 8; } -static int usb_descriptor_index(uint16_t wValue) { - return wValue & 0xFF; -} +static int usb_descriptor_index(uint16_t wValue) { return wValue & 0xFF; } static struct winusb_compatible_id_descriptor winusb_wcid = { - .header = { - .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + - 1 * sizeof(struct winusb_compatible_id_function_section), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, - .bNumSections = 1, - .reserved = { 0, 0, 0, 0, 0, 0, 0 }, - }, - .functions = { - { - // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number - .bInterfaceNumber = 0, - .reserved0 = { 1 }, - .compatibleId = "WINUSB", - .subCompatibleId = "", - .reserved1 = { 0, 0, 0, 0, 0, 0} - }, - } -}; + .header = + { + .dwLength = + sizeof(struct winusb_compatible_id_descriptor_header) + + 1 * sizeof(struct winusb_compatible_id_function_section), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, + .bNumSections = 1, + .reserved = {0, 0, 0, 0, 0, 0, 0}, + }, + .functions = { + {// note - bInterfaceNumber is rewritten in winusb_setup with the + // correct interface number + .bInterfaceNumber = 0, + .reserved0 = {1}, + .compatibleId = "WINUSB", + .subCompatibleId = "", + .reserved1 = {0, 0, 0, 0, 0, 0}}, + }}; static const struct usb_string_descriptor winusb_string_descriptor = { - .bLength = 0x12, - .bDescriptorType = USB_DT_STRING, - .wData = WINUSB_EXTRA_STRING -}; + .bLength = 0x12, + .bDescriptorType = USB_DT_STRING, + .wData = WINUSB_EXTRA_STRING}; static const struct winusb_extended_properties_descriptor guid = { - .header = { - .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) - + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), - .bcdVersion = WINUSB_BCD_VERSION, - .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, - .wNumFeatures = 1, - }, - .features = { - { - .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), - .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, - .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, - .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, - .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, - .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, - }, - } -}; + .header = + { + .dwLength = + sizeof(struct winusb_extended_properties_descriptor_header) + + 1 * sizeof( + struct winusb_extended_properties_feature_descriptor), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, + .wNumFeatures = 1, + }, + .features = { + { + .dwLength = + sizeof(struct winusb_extended_properties_feature_descriptor), + .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, + .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, + .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, + .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, + .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, + }, + }}; static int winusb_descriptor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, + usbd_control_complete_callback *complete) { + (void)complete; + (void)usbd_dev; - wait_random(); + wait_random(); - if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { - return USBD_REQ_NEXT_CALLBACK; - } + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return USBD_REQ_NEXT_CALLBACK; + } - if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { - if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { - *buf = (uint8_t*)(&winusb_string_descriptor); - *len = MIN_8bits(*len, winusb_string_descriptor.bLength); - return USBD_REQ_HANDLED; - } - } - return USBD_REQ_NEXT_CALLBACK; + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && + usb_descriptor_type(req->wValue) == USB_DT_STRING) { + if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { + *buf = (uint8_t *)(&winusb_string_descriptor); + *len = MIN_8bits(*len, winusb_string_descriptor.bLength); + return USBD_REQ_HANDLED; + } + } + return USBD_REQ_NEXT_CALLBACK; } -static int winusb_control_vendor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback* complete) { - (void)complete; - (void)usbd_dev; +static int winusb_control_vendor_request( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete) { + (void)complete; + (void)usbd_dev; - wait_random(); + wait_random(); - if (req->bRequest != WINUSB_MS_VENDOR_CODE) { - return USBD_REQ_NEXT_CALLBACK; - } + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } - int status = USBD_REQ_NOTSUPP; - if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && - (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { - *buf = (uint8_t*)(&winusb_wcid); - *len = MIN_8bits(*len, winusb_wcid.header.dwLength); - status = USBD_REQ_HANDLED; + int status = USBD_REQ_NOTSUPP; + if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && + (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { + *buf = (uint8_t *)(&winusb_wcid); + *len = MIN_8bits(*len, winusb_wcid.header.dwLength); + status = USBD_REQ_HANDLED; - } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && - (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && - (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { + } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == + USB_REQ_TYPE_INTERFACE) && + (req->wIndex == + WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && + (usb_descriptor_index(req->wValue) == + winusb_wcid.functions[0].bInterfaceNumber)) { + *buf = (uint8_t *)(&guid); + *len = MIN_8bits(*len, guid.header.dwLength); + status = USBD_REQ_HANDLED; - *buf = (uint8_t*)(&guid); - *len = MIN_8bits(*len, guid.header.dwLength); - status = USBD_REQ_HANDLED; + } else { + status = USBD_REQ_NOTSUPP; + } - } else { - status = USBD_REQ_NOTSUPP; - } - - return status; + return status; } -static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { - (void)wValue; - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); +static void winusb_set_config(usbd_device *usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); } -void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { - winusb_wcid.functions[0].bInterfaceNumber = interface; +void winusb_setup(usbd_device *usbd_dev, uint8_t interface) { + winusb_wcid.functions[0].bInterfaceNumber = interface; - usbd_register_set_config_callback(usbd_dev, winusb_set_config); + usbd_register_set_config_callback(usbd_dev, winusb_set_config); - /* Windows probes the compatible ID before setting the configuration, - so also register the callback now */ + /* Windows probes the compatible ID before setting the configuration, + so also register the callback now */ - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_VENDOR, - USB_REQ_TYPE_TYPE, - winusb_control_vendor_request); + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); - usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_DEVICE, - USB_REQ_TYPE_RECIPIENT, - winusb_descriptor_request); + usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_RECIPIENT, + winusb_descriptor_request); } - diff --git a/winusb.h b/winusb.h index 16a6df1153..071f262fc8 100644 --- a/winusb.h +++ b/winusb.h @@ -19,11 +19,13 @@ #ifndef WINUSB_H_INCLUDED #define WINUSB_H_INCLUDED +#include #include "winusb_defs.h" // Arbitrary, but must be equivalent to the last character in extra string #define WINUSB_MS_VENDOR_CODE '!' -#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} +#define WINUSB_EXTRA_STRING \ + { 'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE } extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); diff --git a/winusb_defs.h b/winusb_defs.h index 830e6b1545..dd779b8577 100644 --- a/winusb_defs.h +++ b/winusb_defs.h @@ -30,60 +30,65 @@ // Apparently using DeviceInterfaceGUID does not always work on Windows 7. // DeviceInterfaceGUIDs does seem to work. -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) -#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C \ + sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U \ + (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) // extra null is intentional - it's an array of GUIDs with 1 item -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) -#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) -#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA \ + u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C \ + sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U \ + (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 #define WINUSB_EXTRA_STRING_INDEX 0xee /* Table 2. Function Section */ struct winusb_compatible_id_function_section { - uint8_t bInterfaceNumber; - uint8_t reserved0[1]; - char compatibleId[8]; - char subCompatibleId[8]; - uint8_t reserved1[6]; + uint8_t bInterfaceNumber; + uint8_t reserved0[1]; + char compatibleId[8]; + char subCompatibleId[8]; + uint8_t reserved1[6]; } __attribute__((packed)); /* Table 1. Header Section */ struct winusb_compatible_id_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint8_t bNumSections; - uint8_t reserved[7]; + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bNumSections; + uint8_t reserved[7]; } __attribute__((packed)); struct winusb_compatible_id_descriptor { - struct winusb_compatible_id_descriptor_header header; - struct winusb_compatible_id_function_section functions[]; + struct winusb_compatible_id_descriptor_header header; + struct winusb_compatible_id_function_section functions[]; } __attribute__((packed)); struct winusb_extended_properties_feature_descriptor { - uint32_t dwLength; - uint32_t dwPropertyDataType; - uint16_t wNameLength; - uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; - uint32_t dwPropertyDataLength; - uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint16_t wNameLength; + uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; + uint32_t dwPropertyDataLength; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; } __attribute__((packed)); struct winusb_extended_properties_descriptor_header { - uint32_t dwLength; - uint16_t bcdVersion; - uint16_t wIndex; - uint16_t wNumFeatures; + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wNumFeatures; } __attribute__((packed)); struct winusb_extended_properties_descriptor { - struct winusb_extended_properties_descriptor_header header; - struct winusb_extended_properties_feature_descriptor features[]; + struct winusb_extended_properties_descriptor_header header; + struct winusb_extended_properties_feature_descriptor features[]; } __attribute__((packed)); #endif From 3d37dd850d5188048df0f02dd4e6a1f4435f3687 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 29 Mar 2019 17:20:01 +0100 Subject: [PATCH 1148/1154] supervise: fix last commit --- supervise.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supervise.h b/supervise.h index 6b7bed1c8f..db889a58ad 100644 --- a/supervise.h +++ b/supervise.h @@ -20,10 +20,10 @@ #ifndef __SUPERVISE_H__ #define __SUPERVISE_H__ -#if !EMULATOR - #include +#if !EMULATOR + #define SVC_FLASH_UNLOCK 0 #define SVC_FLASH_ERASE 1 #define SVC_FLASH_PROGRAM 2 From ac5e3268f7591d48f0c5631898b04e136dc81e8a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 1 Apr 2019 15:31:45 +0200 Subject: [PATCH 1149/1154] firmware: fix unaligned access --- firmware/layout2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 234d27b50b..993c05b1ab 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -374,7 +374,8 @@ void layoutConfirmOmni(const uint8_t *data, uint32_t size) { suffix = "USDT"; break; } - const uint64_t amount = *(const uint64_t *)(data + 12); + uint64_t amount; + memcpy(&amount, data + 12, sizeof(uint64_t)); bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); } else { From 622966383c3394209219d350c95c17dfa0dd2d61 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 1 Apr 2019 16:41:51 +0200 Subject: [PATCH 1150/1154] vendor/nanopb: update to 0.3.9.3 --- vendor/nanopb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/nanopb b/vendor/nanopb index cdb6161219..3c69a905b1 160000 --- a/vendor/nanopb +++ b/vendor/nanopb @@ -1 +1 @@ -Subproject commit cdb61612197feca5391593d051c8d4892e940228 +Subproject commit 3c69a905b16df149e1bda12f25e0522073a24678 From fc73e54d443b296290968b41177274028022d670 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 1 Apr 2019 17:02:32 +0200 Subject: [PATCH 1151/1154] vendor/libopencm3: update to latest snapshot --- demo/demo.c | 6 +- firmware/usb.c | 6 +- memory.ld | 2 +- memory_app_0.0.0.ld | 2 +- memory_app_1.0.0.ld | 2 +- memory_app_1.8.0.ld | 2 +- memory_app_fastflash.ld | 2 +- usb21_standard.c | 2 +- usb_private.h | 10 +-- usb_standard.c | 154 +++++++++++++++++++++++----------------- util.h | 11 ++- vendor/libopencm3 | 2 +- webusb.c | 2 +- winusb.c | 9 ++- 14 files changed, 116 insertions(+), 96 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index 4ece26d9bf..bad797012e 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -213,9 +213,9 @@ static const char *usb_strings[] = { "01234567", }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback *complete) { +static enum usbd_request_return_codes hid_control_request( + usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) { (void)complete; (void)dev; diff --git a/firmware/usb.c b/firmware/usb.c index 09fb45a565..8d80dbed92 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -259,9 +259,9 @@ static const struct usb_config_descriptor config = { .interface = ifaces, }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len, - usbd_control_complete_callback *complete) { +static enum usbd_request_return_codes hid_control_request( + usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) { (void)complete; (void)dev; diff --git a/memory.ld b/memory.ld index 12855c2c8b..2f94613e49 100644 --- a/memory.ld +++ b/memory.ld @@ -14,7 +14,7 @@ SECTIONS } >ram } -INCLUDE libopencm3_stm32f2.ld +INCLUDE cortex-m-generic.ld _ram_start = ORIGIN(ram); _ram_end = ORIGIN(ram) + LENGTH(ram); diff --git a/memory_app_0.0.0.ld b/memory_app_0.0.0.ld index 210e1c32d7..8f322e4e8b 100644 --- a/memory_app_0.0.0.ld +++ b/memory_app_0.0.0.ld @@ -6,4 +6,4 @@ MEMORY ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K } -INCLUDE libopencm3_stm32f2.ld +INCLUDE cortex-m-generic.ld diff --git a/memory_app_1.0.0.ld b/memory_app_1.0.0.ld index 897f6603ff..688e775627 100644 --- a/memory_app_1.0.0.ld +++ b/memory_app_1.0.0.ld @@ -14,7 +14,7 @@ SECTIONS } >ram } -INCLUDE libopencm3_stm32f2.ld +INCLUDE cortex-m-generic.ld _ram_start = ORIGIN(ram); _ram_end = ORIGIN(ram) + LENGTH(ram); diff --git a/memory_app_1.8.0.ld b/memory_app_1.8.0.ld index 8767a33e29..b11b8bf1e7 100644 --- a/memory_app_1.8.0.ld +++ b/memory_app_1.8.0.ld @@ -18,7 +18,7 @@ SECTIONS } >rom AT>rom } -INCLUDE libopencm3_stm32f2.ld +INCLUDE cortex-m-generic.ld _codelen = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.exidx); diff --git a/memory_app_fastflash.ld b/memory_app_fastflash.ld index a5d554e23a..7bba7443ea 100644 --- a/memory_app_fastflash.ld +++ b/memory_app_fastflash.ld @@ -15,7 +15,7 @@ SECTIONS } >ram } -INCLUDE libopencm3_stm32f2.ld +INCLUDE cortex-m-generic.ld _ram_start = ORIGIN(ram); _ram_end = ORIGIN(ram) + LENGTH(ram); diff --git a/usb21_standard.c b/usb21_standard.c index 9538285aaf..f5ca3546d8 100644 --- a/usb21_standard.c +++ b/usb21_standard.c @@ -53,7 +53,7 @@ static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, static const struct usb_bos_descriptor *usb21_bos; -static int usb21_standard_get_descriptor( +static enum usbd_request_return_codes usb21_standard_get_descriptor( usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; diff --git a/usb_private.h b/usb_private.h index 862e770675..00d4086d45 100644 --- a/usb_private.h +++ b/usb_private.h @@ -46,7 +46,7 @@ LGPL License Terms @ref lgpl_license struct _usbd_device { const struct usb_device_descriptor *desc; const struct usb_config_descriptor *config; - const char **strings; + const char * const *strings; int num_strings; uint8_t *ctrl_buf; /**< Internal buffer used for control transfers */ @@ -122,16 +122,16 @@ void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea); void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea); void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea); -int _usbd_standard_request_device(usbd_device *usbd_dev, +enum usbd_request_return_codes _usbd_standard_request_device(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len); -int _usbd_standard_request_interface(usbd_device *usbd_dev, +enum usbd_request_return_codes _usbd_standard_request_interface(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len); -int _usbd_standard_request_endpoint(usbd_device *usbd_dev, +enum usbd_request_return_codes _usbd_standard_request_endpoint(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len); -int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, +enum usbd_request_return_codes _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len); void _usbd_reset(usbd_device *usbd_dev); diff --git a/usb_standard.c b/usb_standard.c index 8ac1792362..26f5925a24 100644 --- a/usb_standard.c +++ b/usb_standard.c @@ -48,6 +48,9 @@ int usbd_register_set_config_callback(usbd_device *usbd_dev, for (i = 0; i < MAX_USER_SET_CONFIG_CALLBACK; i++) { if (usbd_dev->user_callback_set_config[i]) { + if (usbd_dev->user_callback_set_config[i] == callback) { + return 0; + } continue; } @@ -131,8 +134,9 @@ static uint16_t build_config_descriptor(usbd_device *usbd_dev, } } - /* Fill in wTotalLength. */ - *(uint16_t *)(tmpbuf + 2) = totallen; + /* Fill in wTotalLength. + * Note that tmpbuf is sometimes not halfword-aligned */ + memcpy((tmpbuf + 2), &totallen, sizeof(uint16_t)); return total; } @@ -147,9 +151,10 @@ static int usb_descriptor_index(uint16_t wValue) return wValue & 0xFF; } -static int usb_standard_get_descriptor(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_get_descriptor(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { wait_random(); @@ -221,9 +226,10 @@ static int usb_standard_get_descriptor(usbd_device *usbd_dev, return USBD_REQ_NOTSUPP; } -static int usb_standard_set_address(usbd_device *usbd_dev, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len) +static enum usbd_request_return_codes +usb_standard_set_address(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) { (void)req; (void)buf; @@ -231,7 +237,7 @@ static int usb_standard_set_address(usbd_device *usbd_dev, /* The actual address is only latched at the STATUS IN stage. */ if ((req->bmRequestType != 0) || (req->wValue >= 128)) { - return 0; + return USBD_REQ_NOTSUPP; } usbd_dev->current_address = req->wValue; @@ -244,12 +250,13 @@ static int usb_standard_set_address(usbd_device *usbd_dev, usbd_dev->driver->set_address(usbd_dev, req->wValue); } - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_set_configuration(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_set_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { unsigned i; int found_index = -1; @@ -305,12 +312,13 @@ static int usb_standard_set_configuration(usbd_device *usbd_dev, } } - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_get_configuration(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_get_configuration(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)req; @@ -325,12 +333,13 @@ static int usb_standard_get_configuration(usbd_device *usbd_dev, (*buf)[0] = 0; } - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_set_interface(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_set_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { const struct usb_config_descriptor *cfx = &usbd_dev->config[usbd_dev->current_config - 1]; @@ -365,9 +374,10 @@ static int usb_standard_set_interface(usbd_device *usbd_dev, return USBD_REQ_HANDLED; } -static int usb_standard_get_interface(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_get_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { uint8_t *cur_altsetting; const struct usb_config_descriptor *cfx = @@ -384,9 +394,10 @@ static int usb_standard_get_interface(usbd_device *usbd_dev, return USBD_REQ_HANDLED; } -static int usb_standard_device_get_status(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_device_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)usbd_dev; (void)req; @@ -399,12 +410,13 @@ static int usb_standard_device_get_status(usbd_device *usbd_dev, (*buf)[0] = 0; (*buf)[1] = 0; - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_interface_get_status(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_interface_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)usbd_dev; (void)req; @@ -416,12 +428,13 @@ static int usb_standard_interface_get_status(usbd_device *usbd_dev, (*buf)[0] = 0; (*buf)[1] = 0; - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_endpoint_get_status(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_endpoint_get_status(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)req; @@ -431,42 +444,46 @@ static int usb_standard_endpoint_get_status(usbd_device *usbd_dev, (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0; (*buf)[1] = 0; - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_endpoint_stall(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_endpoint_stall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)buf; (void)len; usbd_ep_stall_set(usbd_dev, req->wIndex, 1); - return 1; + return USBD_REQ_HANDLED; } -static int usb_standard_endpoint_unstall(usbd_device *usbd_dev, - struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +static enum usbd_request_return_codes +usb_standard_endpoint_unstall(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { (void)buf; (void)len; usbd_ep_stall_set(usbd_dev, req->wIndex, 0); - return 1; + return USBD_REQ_HANDLED; } /* Do not appear to belong to the API, so are omitted from docs */ /**@}*/ -int _usbd_standard_request_device(usbd_device *usbd_dev, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len) +enum usbd_request_return_codes +_usbd_standard_request_device(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) { - int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) = NULL; + enum usbd_request_return_codes (*command)(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; switch (req->bRequest) { case USB_REQ_CLEAR_FEATURE: @@ -509,18 +526,20 @@ int _usbd_standard_request_device(usbd_device *usbd_dev, } if (!command) { - return 0; + return USBD_REQ_NOTSUPP; } return command(usbd_dev, req, buf, len); } -int _usbd_standard_request_interface(usbd_device *usbd_dev, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len) +enum usbd_request_return_codes +_usbd_standard_request_interface(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) { - int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) = NULL; + enum usbd_request_return_codes (*command)(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; switch (req->bRequest) { case USB_REQ_CLEAR_FEATURE: @@ -539,18 +558,20 @@ int _usbd_standard_request_interface(usbd_device *usbd_dev, } if (!command) { - return 0; + return USBD_REQ_NOTSUPP; } return command(usbd_dev, req, buf, len); } -int _usbd_standard_request_endpoint(usbd_device *usbd_dev, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len) +enum usbd_request_return_codes +_usbd_standard_request_endpoint(usbd_device *usbd_dev, + struct usb_setup_data *req, uint8_t **buf, + uint16_t *len) { - int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) = NULL; + enum usbd_request_return_codes (*command) (usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) = NULL; switch (req->bRequest) { case USB_REQ_CLEAR_FEATURE: @@ -576,18 +597,19 @@ int _usbd_standard_request_endpoint(usbd_device *usbd_dev, } if (!command) { - return 0; + return USBD_REQ_NOTSUPP; } return command(usbd_dev, req, buf, len); } -int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, - uint8_t **buf, uint16_t *len) +enum usbd_request_return_codes +_usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len) { /* FIXME: Have class/vendor requests as well. */ if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { - return 0; + return USBD_REQ_NOTSUPP; } switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) { @@ -599,7 +621,7 @@ int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, case USB_REQ_TYPE_ENDPOINT: return _usbd_standard_request_endpoint(usbd_dev, req, buf, len); default: - return 0; + return USBD_REQ_NOTSUPP; } } diff --git a/util.h b/util.h index 75db5a866e..54c610430e 100644 --- a/util.h +++ b/util.h @@ -69,7 +69,6 @@ extern void __attribute__((noreturn)) shutdown(void); #if !EMULATOR // defined in memory.ld extern uint8_t _ram_start[], _ram_end[]; -extern uint8_t _stack[]; // defined in startup.s extern void memset_reg(void *start, void *stop, uint32_t val); @@ -78,11 +77,11 @@ extern void memset_reg(void *start, void *stop, uint32_t val); #define FW_UNTRUSTED 0x00000000 static inline void __attribute__((noreturn)) -jump_to_firmware(const vector_table_t *vector_table, int trust) { - if (FW_SIGNED == trust) { // trusted signed firmware - SCB_VTOR = (uint32_t)vector_table; // * relocate vector table +jump_to_firmware(const vector_table_t *ivt, int trust) { + if (FW_SIGNED == trust) { // trusted signed firmware + SCB_VTOR = (uint32_t)ivt; // * relocate vector table // Set stack pointer - __asm__ volatile("msr msp, %0" ::"r"(vector_table->initial_sp_value)); + __asm__ volatile("msr msp, %0" ::"r"(ivt->initial_sp_value)); } else { // untrusted firmware timer_init(); mpu_config_firmware(); // * configure MPU for the firmware @@ -90,7 +89,7 @@ jump_to_firmware(const vector_table_t *vector_table, int trust) { } // Jump to address - vector_table->reset(); + ivt->reset(); // Prevent compiler from generating stack protector code (which causes CPU // fault because the stack is moved) diff --git a/vendor/libopencm3 b/vendor/libopencm3 index b0e050d10d..0fd4f74ee3 160000 --- a/vendor/libopencm3 +++ b/vendor/libopencm3 @@ -1 +1 @@ -Subproject commit b0e050d10d12c42be031c34822117cfd3c5a0ea7 +Subproject commit 0fd4f74ee301af5de4e9b036f391bf17c5a52f02 diff --git a/webusb.c b/webusb.c index 24ca5ee192..24f28a4ca5 100644 --- a/webusb.c +++ b/webusb.c @@ -45,7 +45,7 @@ const struct webusb_platform_descriptor static const char* webusb_https_url; -static int webusb_control_vendor_request( +static enum usbd_request_return_codes webusb_control_vendor_request( usbd_device* usbd_dev, struct usb_setup_data* req, uint8_t** buf, uint16_t* len, usbd_control_complete_callback* complete) { (void)complete; diff --git a/winusb.c b/winusb.c index ebd8072466..e18f9d0e07 100644 --- a/winusb.c +++ b/winusb.c @@ -73,10 +73,9 @@ static const struct winusb_extended_properties_descriptor guid = { }, }}; -static int winusb_descriptor_request(usbd_device *usbd_dev, - struct usb_setup_data *req, uint8_t **buf, - uint16_t *len, - usbd_control_complete_callback *complete) { +static enum usbd_request_return_codes winusb_descriptor_request( + usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; (void)usbd_dev; @@ -97,7 +96,7 @@ static int winusb_descriptor_request(usbd_device *usbd_dev, return USBD_REQ_NEXT_CALLBACK; } -static int winusb_control_vendor_request( +static enum usbd_request_return_codes winusb_control_vendor_request( usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) { (void)complete; From fa7095add98bb1dafa2c41059508063e6e0733eb Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 9 Apr 2019 14:24:26 +0200 Subject: [PATCH 1152/1154] omni: parse data as big-endian --- firmware/layout2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 993c05b1ab..197b4edac3 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -355,10 +355,11 @@ void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) { void layoutConfirmOmni(const uint8_t *data, uint32_t size) { const char *desc; char str_out[32]; - const uint32_t tx_type = *(const uint32_t *)(data + 4); + uint32_t tx_type, currency; + REVERSE32(*(const uint32_t *)(data + 4), tx_type); if (tx_type == 0x00000000 && size == 20) { // OMNI simple send desc = _("Simple send of "); - const uint32_t currency = *(const uint32_t *)(data + 8); + REVERSE32(*(const uint32_t *)(data + 8), currency); const char *suffix = "UNKN"; switch (currency) { case 1: @@ -374,8 +375,9 @@ void layoutConfirmOmni(const uint8_t *data, uint32_t size) { suffix = "USDT"; break; } - uint64_t amount; - memcpy(&amount, data + 12, sizeof(uint64_t)); + uint64_t amount_be, amount; + memcpy(&amount_be, data + 12, sizeof(uint64_t)); + REVERSE64(amount_be, amount); bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); } else { From da95537e345b806b2ef6e811c6dd7ecfb94bad86 Mon Sep 17 00:00:00 2001 From: matejcik Date: Tue, 9 Apr 2019 14:26:55 +0200 Subject: [PATCH 1153/1154] omni: add space before symbol --- firmware/layout2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/firmware/layout2.c b/firmware/layout2.c index 197b4edac3..61510249e8 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -360,19 +360,19 @@ void layoutConfirmOmni(const uint8_t *data, uint32_t size) { if (tx_type == 0x00000000 && size == 20) { // OMNI simple send desc = _("Simple send of "); REVERSE32(*(const uint32_t *)(data + 8), currency); - const char *suffix = "UNKN"; + const char *suffix = " UNKN"; switch (currency) { case 1: - suffix = "OMNI"; + suffix = " OMNI"; break; case 2: - suffix = "tOMNI"; + suffix = " tOMNI"; break; case 3: - suffix = "MAID"; + suffix = " MAID"; break; case 31: - suffix = "USDT"; + suffix = " USDT"; break; } uint64_t amount_be, amount; From 8af1f3643651e1cbee6b6196401f9c63e7cfc0f9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Wed, 10 Apr 2019 16:58:04 +0200 Subject: [PATCH 1154/1154] vendor: update trezor-common --- vendor/trezor-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-common b/vendor/trezor-common index c5e54d7535..90bd68f55a 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit c5e54d7535c8772b9a75ff90c506a28526f94267 +Subproject commit 90bd68f55adeebacfca05c0f54aa29283aa0d760