import v1.0.0

This commit is contained in:
Pavol Rusnak 2014-04-29 14:26:51 +02:00
commit 0d0a1ab5f2
111 changed files with 10758 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
*.a
*.d
*.o
*.bin
*.elf
*.hex
*.list
*.srec
usb.pb*
bootloader

6
.gitmodules vendored Normal file
View File

@ -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

165
COPYING Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.

15
Makefile Normal file
View File

@ -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

123
Makefile.include Normal file
View File

@ -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

3
README Normal file
View File

@ -0,0 +1,3 @@
Embedded software for TREZOR
http://bitcointrezor.com/

68
buttons.c Normal file
View File

@ -0,0 +1,68 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}

40
buttons.h Normal file
View File

@ -0,0 +1,40 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BUTTONS_H__
#define __BUTTONS_H__
#include <libopencm3/stm32/f2/gpio.h>
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

17
demo/Makefile Normal file
View File

@ -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

285
demo/demo.c Normal file
View File

@ -0,0 +1,285 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h>
#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;
}

48
firmware/Makefile Normal file
View File

@ -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

61
firmware/coins.c Normal file
View File

@ -0,0 +1,61 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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;
}

33
firmware/coins.h Normal file
View File

@ -0,0 +1,33 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

53
firmware/debug.c Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trezor.h"
#include "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

35
firmware/debug.h Normal file
View File

@ -0,0 +1,35 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

672
firmware/fsm.c Normal file
View File

@ -0,0 +1,672 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trezor.h"
#include "fsm.h"
#include "messages.h"
#include "bip32.h"
#include "storage.h"
#include "coins.h"
#include "debug.h"
#include "transaction.h"
#include "rng.h"
#include "storage.h"
#include "oled.h"
#include "protect.h"
#include "pinmatrix.h"
#include "layout2.h"
#include "ecdsa.h"
#include "reset.h"
#include "recovery.h"
#include "memory.h"
#include "usb.h"
#include "util.h"
#include "signing.h"
// 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

63
firmware/fsm.h Normal file
View File

@ -0,0 +1,63 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

191
firmware/layout2.c Normal file
View File

@ -0,0 +1,191 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#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);
}

35
firmware/layout2.h Normal file
View File

@ -0,0 +1,35 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

414
firmware/messages.c Normal file
View File

@ -0,0 +1,414 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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;
}
}

53
firmware/messages.h Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MESSAGES_H__
#define __MESSAGES_H__
#include <stdint.h>
#include <stdbool.h>
#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

87
firmware/pinmatrix.c Normal file
View File

@ -0,0 +1,87 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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;
}

27
firmware/pinmatrix.h Normal file
View File

@ -0,0 +1,27 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PINMATRIX_H__
#define __PINMATRIX_H__
void pinmatrix_start(const char *text);
void pinmatrix_done(char *pin);
const char *pinmatrix_get(void);
#endif

222
firmware/protect.c Normal file
View File

@ -0,0 +1,222 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}

31
firmware/protect.h Normal file
View File

@ -0,0 +1,31 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PROTECT_H__
#define __PROTECT_H__
#include <stdbool.h>
#include "types.pb.h"
bool protectButton(ButtonRequestType type, bool confirm_only);
bool protectPin(bool use_cached);
bool protectChangePin(void);
bool protectPassphrase(void);
#endif

1
firmware/protob/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.pb

10
firmware/protob/Makefile Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
../../trezor-common/protob/messages.proto

519
firmware/protob/pb.h Normal file
View File

@ -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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#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

1178
firmware/protob/pb_decode.c Normal file

File diff suppressed because it is too large Load Diff

149
firmware/protob/pb_decode.h Normal file
View File

@ -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

667
firmware/protob/pb_encode.c Normal file
View File

@ -0,0 +1,667 @@
/* pb_encode.c -- encode a protobuf using minimal resources
*
* 2011 Petteri Aimonen <jpa@kapsi.fi>
*/
#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);
}

154
firmware/protob/pb_encode.h Normal file
View File

@ -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

View File

@ -0,0 +1,4 @@
Storage.mnemonic max_size:241
Storage.pin max_size:10
Storage.language max_size:17
Storage.label max_size:33

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
../../trezor-common/protob/storage.proto

View File

@ -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

144
firmware/protob/types.pb.c Normal file
View File

@ -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

262
firmware/protob/types.pb.h Normal file
View File

@ -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

1
firmware/protob/types.proto Symbolic link
View File

@ -0,0 +1 @@
../../trezor-common/protob/types.proto

179
firmware/recovery.c Normal file
View File

@ -0,0 +1,179 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}

32
firmware/recovery.h Normal file
View File

@ -0,0 +1,32 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RECOVERY_H__
#define __RECOVERY_H__
#include <stdint.h>
#include <stdbool.h>
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

151
firmware/reset.c Normal file
View File

@ -0,0 +1,151 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}

31
firmware/reset.h Normal file
View File

@ -0,0 +1,31 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RESET_H__
#define __RESET_H__
#include <stdint.h>
#include <stdbool.h>
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

426
firmware/signing.c Normal file
View File

@ -0,0 +1,426 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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;
}
}

32
firmware/signing.h Normal file
View File

@ -0,0 +1,32 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SIGNING_H__
#define __SIGNING_H__
#include <stdint.h>
#include <stdbool.h>
#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

40
firmware/ssp.c Normal file
View File

@ -0,0 +1,40 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "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
}

26
firmware/ssp.h Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSP_H_
#define __SSP_H_
void __stack_chk_guard_setup(void);
void __attribute__((noreturn)) __stack_chk_fail(void);
#endif

327
firmware/storage.c Normal file
View File

@ -0,0 +1,327 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdint.h>
#include <libopencm3/stm32/f2/flash.h>
#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;
}

61
firmware/storage.h Normal file
View File

@ -0,0 +1,61 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

459
firmware/transaction.c Normal file
View File

@ -0,0 +1,459 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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;
}

67
firmware/transaction.h Normal file
View File

@ -0,0 +1,67 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TRANSACTION_H__
#define __TRANSACTION_H__
#include <stdbool.h>
#include <stdint.h>
#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

53
firmware/trezor.c Normal file
View File

@ -0,0 +1,53 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trezor.h"
#include "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;
}

38
firmware/trezor.h Normal file
View File

@ -0,0 +1,38 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

334
firmware/usb.c Normal file
View File

@ -0,0 +1,334 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h>
#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;
}

28
firmware/usb.h Normal file
View File

@ -0,0 +1,28 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __USB_H__
#define __USB_H__
void usbInit(void);
void usbPoll(void);
void usbReconnect(void);
void usbTiny(char set);
#endif

49
gen/bitmaps.c Normal file
View File

@ -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};

35
gen/bitmaps.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __BITMAPS_H__
#define __BITMAPS_H__
#include <stdint.h>
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

2
gen/bitmaps/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.c
*.h

BIN
gen/bitmaps/digit0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

BIN
gen/bitmaps/digit1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

BIN
gen/bitmaps/digit2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

BIN
gen/bitmaps/digit3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
gen/bitmaps/digit4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

BIN
gen/bitmaps/digit5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 B

BIN
gen/bitmaps/digit6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

BIN
gen/bitmaps/digit7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

BIN
gen/bitmaps/digit8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
gen/bitmaps/digit9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

BIN
gen/bitmaps/gears0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

BIN
gen/bitmaps/gears1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

BIN
gen/bitmaps/gears2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

BIN
gen/bitmaps/gears3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

59
gen/bitmaps/generate.py Executable file
View File

@ -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 <stdint.h>
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()

BIN
gen/bitmaps/icon_error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

BIN
gen/bitmaps/icon_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
gen/bitmaps/icon_ok.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

BIN
gen/bitmaps/logo48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
gen/bitmaps/logo64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

118
gen/fonts.c Normal file
View File

@ -0,0 +1,118 @@
#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\x3c\x7e\x81",
(uint8_t *)"\x03\x81\x7e\x3c",
(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\xff\xff\x81",
(uint8_t *)"\x03\xe0\x38\x0e",
(uint8_t *)"\x03\x81\xff\xff",
(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 *)"\x07\x44\xee\x7c\x38\x7c\xee\x44",
(uint8_t *)"\x02\xff\xff",
(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",
};
int fontCharWidth(char c) {
if ((c < FONT_START) || (c > 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;
}

15
gen/fonts.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef __FONTS_H__
#define __FONTS_H__
#include <stdint.h>
#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

BIN
gen/fonts/font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

31
gen/fonts/generate.py Executable file
View File

@ -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)

99
gen/handlers/handlers.py Executable file
View File

@ -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')

105
layout.c Normal file
View File

@ -0,0 +1,105 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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();
}

37
layout.h Normal file
View File

@ -0,0 +1,37 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LAYOUT_H__
#define __LAYOUT_H__
#include <stdlib.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 layoutProgress(const char *desc, int permil, int gearstep);
#endif

45
memory.c Normal file
View File

@ -0,0 +1,45 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f2/flash.h>
#include <stdint.h>
#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;
}

104
memory.h Normal file
View File

@ -0,0 +1,104 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#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

9
memory.ld Normal file
View File

@ -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

9
memory_app_0.0.0.ld Normal file
View File

@ -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

9
memory_app_1.0.0.ld Normal file
View File

@ -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

331
oled.c Normal file
View File

@ -0,0 +1,331 @@
/*
* This file is part of the TREZOR project.
*
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f2/gpio.h>
#include <libopencm3/stm32/f2/spi.h>
#include <string.h>
#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();
}
}

Some files were not shown because too many files have changed in this diff Show More