1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 07:28:10 +00:00

core+legacy: rework code styling checks

This commit is contained in:
Pavol Rusnak 2019-04-18 16:27:27 +02:00
parent 9f8ebcf183
commit 8b06598474
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
51 changed files with 1998 additions and 1826 deletions

1
.gitmodules vendored
View File

@ -23,6 +23,7 @@
[submodule "legacy/vendor/nanopb"] [submodule "legacy/vendor/nanopb"]
path = legacy/vendor/nanopb path = legacy/vendor/nanopb
url = https://github.com/nanopb/nanopb.git url = https://github.com/nanopb/nanopb.git
ignore = untracked
[submodule "legacy/vendor/QR-Code-generator"] [submodule "legacy/vendor/QR-Code-generator"]
path = legacy/vendor/QR-Code-generator path = legacy/vendor/QR-Code-generator
url = https://github.com/nayuki/QR-Code-generator.git url = https://github.com/nayuki/QR-Code-generator.git

24
Makefile Normal file
View File

@ -0,0 +1,24 @@
## help commands:
help: ## show this help
@awk -f ./tools/help.awk $(MAKEFILE_LIST)
## style commands:
style_check: ## run code style check on application sources and tests
flake8 --version
isort --version | awk '/VERSION/{print $$2}'
black --version
flake8 $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
isort --check-only $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
black --check $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
style: ## apply code style on application sources and tests
isort $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
black $(shell find -type f -name '*.py' | grep -f ./tools/style.py.include | grep -v -f ./tools/style.py.exclude )
cstyle_check: ## run code style check on low-level C code
./tools/clang-format-check $(shell find -type f -name '*.c' -o -name '*.h' | grep -f ./tools/style.c.include | grep -v -f ./tools/style.c.exclude )
cstyle: ## apply code style on low-level C code
clang-format -i $(shell find -type f -name '*.c' -o -name '*.h' | grep -f ./tools/style.c.include | grep -v -f ./tools/style.c.exclude )

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import json
import sys import sys
from glob import glob from glob import glob
import json
from hashlib import sha256 from hashlib import sha256
try: try:
opt = sys.argv[1] opt = sys.argv[1]
except: except IndexError:
print("Usage: gen.py [core|mcu|check])") print("Usage: gen.py [core|mcu|check])")
sys.exit(1) sys.exit(1)
@ -22,12 +21,12 @@ def gen_core(data):
for d in data: for d in data:
if "u2f" in d: if "u2f" in d:
url, label = d["u2f"], d["label"] url, label = d["u2f"], d["label"]
print(" \"%s\": \"%s\"," % (url, label)) print(' "%s": "%s",' % (url, label))
print(" # WebAuthn") print(" # WebAuthn")
for d in data: for d in data:
if "webauthn" in d: if "webauthn" in d:
origin, label = d["webauthn"], d["label"] origin, label = d["webauthn"], d["label"]
print(" \"%s\": \"%s\"," % (origin, label)) print(' "%s": "%s",' % (origin, label))
print("}") print("}")
@ -36,12 +35,17 @@ def gen_mcu(data):
if "u2f" in d: if "u2f" in d:
url, label = d["u2f"], d["label"] url, label = d["u2f"], d["label"]
h = sha256(url.encode()).digest() h = sha256(url.encode()).digest()
print("\t{\n\t\t// U2F: %s\n\t\t%s,\n\t\t\"%s\"\n\t}," % (url, c_bytes(h), label)) print(
'\t{\n\t\t// U2F: %s\n\t\t%s,\n\t\t"%s"\n\t},'
% (url, c_bytes(h), label)
)
if "webauthn" in d: if "webauthn" in d:
origin, label = d["webauthn"], d["label"] origin, label = d["webauthn"], d["label"]
h = sha256(origin.encode()).digest() h = sha256(origin.encode()).digest()
print("\t{\n\t\t// WebAuthn: %s\n\t\t%s,\n\t\t\"%s\"\n\t}," % (origin, c_bytes(h), label)) print(
'\t{\n\t\t// WebAuthn: %s\n\t\t%s,\n\t\t"%s"\n\t},'
% (origin, c_bytes(h), label)
)
data = [] data = []

View File

@ -1,3 +1,4 @@
// clang-format off
// TREZORv1 production public keys // TREZORv1 production public keys
"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58", "\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58",
"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1", "\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1",

View File

@ -1,2 +1,3 @@
// clang-format off
// sample public key "correct horse battery staple" // sample public key "correct horse battery staple"
"\x04\x78\xd4\x30\x27\x4f\x8c\x5e\xc1\x32\x13\x38\x15\x1e\x9f\x27\xf4\xc6\x76\xa0\x08\xbd\xf8\x63\x8d\x07\xc0\xb6\xbe\x9a\xb3\x5c\x71\xa1\x51\x80\x63\x24\x3a\xcd\x4d\xfe\x96\xb6\x6e\x3f\x2e\xc8\x01\x3c\x8e\x07\x2c\xd0\x9b\x38\x34\xa1\x9f\x81\xf6\x59\xcc\x34\x55" "\x04\x78\xd4\x30\x27\x4f\x8c\x5e\xc1\x32\x13\x38\x15\x1e\x9f\x27\xf4\xc6\x76\xa0\x08\xbd\xf8\x63\x8d\x07\xc0\xb6\xbe\x9a\xb3\x5c\x71\xa1\x51\x80\x63\x24\x3a\xcd\x4d\xfe\x96\xb6\x6e\x3f\x2e\xc8\x01\x3c\x8e\x07\x2c\xd0\x9b\x38\x34\xa1\x9f\x81\xf6\x59\xcc\x34\x55"

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from glob import glob
import os import os
import re import re
import sys import sys
from glob import glob
error = False error = False
@ -21,7 +21,9 @@ for fn in sorted(glob(os.path.join(MYDIR, "messages-*.proto"))):
line = line.strip().split(" ") line = line.strip().split(" ")
if line[0] not in ["enum", "message"]: if line[0] not in ["enum", "message"]:
continue continue
if not line[1].startswith(prefix) and not line[1].startswith("Debug" + prefix): if not line[1].startswith(prefix) and not line[1].startswith(
"Debug" + prefix
):
print("ERROR:", fn, line[1]) print("ERROR:", fn, line[1])
error = True error = True

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from collections import defaultdict, OrderedDict
import re
import os
import json
import glob import glob
import json
import logging import logging
import os
import re
from collections import OrderedDict, defaultdict
try: try:
import requests import requests

View File

@ -3,38 +3,38 @@ from trezorlib import protobuf as p
class CoinDef(p.MessageType): class CoinDef(p.MessageType):
FIELDS = { FIELDS = {
1: ('coin_name', p.UnicodeType, 0), 1: ("coin_name", p.UnicodeType, 0),
2: ('coin_shortcut', p.UnicodeType, 0), 2: ("coin_shortcut", p.UnicodeType, 0),
3: ('coin_label', p.UnicodeType, 0), 3: ("coin_label", p.UnicodeType, 0),
4: ('curve_name', p.UnicodeType, 0), 4: ("curve_name", p.UnicodeType, 0),
5: ('address_type', p.UVarintType, 0), 5: ("address_type", p.UVarintType, 0),
6: ('address_type_p2sh', p.UVarintType, 0), 6: ("address_type_p2sh", p.UVarintType, 0),
7: ('maxfee_kb', p.UVarintType, 0), 7: ("maxfee_kb", p.UVarintType, 0),
8: ('minfee_kb', p.UVarintType, 0), 8: ("minfee_kb", p.UVarintType, 0),
9: ('signed_message_header', p.BytesType, 0), 9: ("signed_message_header", p.BytesType, 0),
10: ('hash_genesis_block', p.BytesType, 0), 10: ("hash_genesis_block", p.BytesType, 0),
11: ('xprv_magic', p.UVarintType, 0), 11: ("xprv_magic", p.UVarintType, 0),
12: ('xpub_magic', p.UVarintType, 0), 12: ("xpub_magic", p.UVarintType, 0),
13: ('xpub_magic_segwit_p2sh', p.UVarintType, 0), 13: ("xpub_magic_segwit_p2sh", p.UVarintType, 0),
14: ('xpub_magic_segwit_native', p.UVarintType, 0), 14: ("xpub_magic_segwit_native", p.UVarintType, 0),
15: ('bech32_prefix', p.UnicodeType, 0), 15: ("bech32_prefix", p.UnicodeType, 0),
16: ('cashaddr_prefix', p.UnicodeType, 0), 16: ("cashaddr_prefix", p.UnicodeType, 0),
17: ('slip44', p.UVarintType, 0), 17: ("slip44", p.UVarintType, 0),
18: ('segwit', p.BoolType, 0), 18: ("segwit", p.BoolType, 0),
19: ('decred', p.BoolType, 0), 19: ("decred", p.BoolType, 0),
20: ('fork_id', p.UVarintType, 0), 20: ("fork_id", p.UVarintType, 0),
21: ('force_bip143', p.BoolType, 0), 21: ("force_bip143", p.BoolType, 0),
22: ('dust_limit', p.UVarintType, 0), 22: ("dust_limit", p.UVarintType, 0),
23: ('uri_prefix', p.UnicodeType, 0), 23: ("uri_prefix", p.UnicodeType, 0),
24: ('min_address_length', p.UVarintType, 0), 24: ("min_address_length", p.UVarintType, 0),
25: ('max_address_length', p.UVarintType, 0), 25: ("max_address_length", p.UVarintType, 0),
26: ('icon', p.BytesType, 0), 26: ("icon", p.BytesType, 0),
28: ('website', p.UnicodeType, 0), 28: ("website", p.UnicodeType, 0),
29: ('github', p.UnicodeType, 0), 29: ("github", p.UnicodeType, 0),
30: ('maintainer', p.UnicodeType, 0), 30: ("maintainer", p.UnicodeType, 0),
31: ('blocktime_seconds', p.UVarintType, 0), 31: ("blocktime_seconds", p.UVarintType, 0),
32: ('bip115', p.BoolType, 0), 32: ("bip115", p.BoolType, 0),
33: ('cooldown', p.UVarintType, 0), 33: ("cooldown", p.UVarintType, 0),
} }
def __init__( def __init__(
@ -73,7 +73,7 @@ class CoinDef(p.MessageType):
default_fee_b: dict = None, default_fee_b: dict = None,
bitcore: dict = None, bitcore: dict = None,
blockbook: dict = None, blockbook: dict = None,
cooldown: int = None cooldown: int = None,
): ):
self.coin_name = coin_name self.coin_name = coin_name
self.coin_shortcut = coin_shortcut self.coin_shortcut = coin_shortcut

View File

@ -1,14 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Fetch information about coins and tokens supported by Trezor and update it in coins_details.json.""" """Fetch information about coins and tokens supported by Trezor and update it in coins_details.json."""
import os
import time
import json import json
import logging import logging
import requests import os
import sys import sys
import coin_info import time
import click import click
import requests
import coin_info
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -149,7 +150,7 @@ def summary(coins, api_key):
try: try:
ret = coinmarketcap_call("global-metrics/quotes/latest", api_key) ret = coinmarketcap_call("global-metrics/quotes/latest", api_key)
total_marketcap = int(ret["data"]["quote"]["USD"]["total_market_cap"]) total_marketcap = int(ret["data"]["quote"]["USD"]["total_market_cap"])
except: except Exception:
pass pass
return dict( return dict(

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import fnmatch import fnmatch
import glob
import io import io
import json import json
import logging import logging
import re
import sys
import os import os
import glob import re
import struct import struct
import sys
import zlib import zlib
from collections import defaultdict from collections import defaultdict
from hashlib import sha256 from hashlib import sha256
@ -524,8 +524,7 @@ def cli(colors):
# fmt: off # fmt: off
@click.option("--backend/--no-backend", "-b", default=False, help="Check blockbook/bitcore responses") @click.option("--backend/--no-backend", "-b", default=False, help="Check blockbook/bitcore responses")
@click.option("--icons/--no-icons", default=True, help="Check icon files") @click.option("--icons/--no-icons", default=True, help="Check icon files")
@click.option("-d", "--show-duplicates", type=click.Choice(("all", "nontoken", "errors")), @click.option("-d", "--show-duplicates", type=click.Choice(("all", "nontoken", "errors")), default="errors", help="How much information about duplicate shortcuts should be shown.")
default="errors", help="How much information about duplicate shortcuts should be shown.")
# fmt: on # fmt: on
def check(backend, icons, show_duplicates): def check(backend, icons, show_duplicates):
"""Validate coin definitions. """Validate coin definitions.

View File

@ -1,13 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import click
import json import json
import os import os
import requests
import tempfile
import subprocess import subprocess
import sys import tempfile
import click
import requests
LIVE_URL = "https://trezor.io/static/json/coins_details.json" LIVE_URL = "https://trezor.io/static/json/coins_details.json"
COINS_DETAILS = os.path.join( COINS_DETAILS = os.path.join(

View File

@ -1,11 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import re import json
import os import os
import re
import subprocess import subprocess
import sys import sys
import click import click
import coin_info import coin_info
import json
SUPPORT_INFO = coin_info.get_support_data() SUPPORT_INFO = coin_info.get_support_data()

View File

@ -39,7 +39,7 @@ CFLAGS += -DGITREV=$(GITREV)
## help commands: ## help commands:
help: ## show this help help: ## show this help
@awk -f help.awk $(MAKEFILE_LIST) @awk -f ../tools/help.awk $(MAKEFILE_LIST)
## dependencies commands: ## dependencies commands:
@ -71,27 +71,6 @@ test_emu_monero: ## run selected monero device tests from monero-agent
pylint: ## run pylint on application sources and tests pylint: ## run pylint on application sources and tests
pylint -E $(shell find src tests -name *.py) pylint -E $(shell find src tests -name *.py)
## style commands:
style_check: ## run code style check on application sources and tests
flake8 --version
isort --version | grep "VERSION"
black --version
flake8 $(shell find src -name *.py)
isort --check-only $(shell find src -name *.py ! -path 'src/trezor/messages/*')
black --check $(shell find src -name *.py ! -path 'src/trezor/messages/*')
style: ## apply code style on application sources and tests
isort $(shell find src -name *.py ! -path 'src/trezor/messages/*')
black $(shell find src -name *.py ! -path 'src/trezor/messages/*')
cstyle_check: ## run code style check on low-level C code
./tools/clang-format-check embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
cstyle: ## apply code style on low-level C code
clang-format -i embed/*/*.{c,h} embed/extmod/modtrezor*/*.{c,h}
## code generation: ## code generation:
templates: ## render Mako templates (for lists of coins, tokens, etc.) templates: ## render Mako templates (for lists of coins, tokens, etc.)

View File

@ -241,6 +241,4 @@ void display_refresh(void) {
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); // set to CMD
} }
const char *display_save(const char *prefix) { const char *display_save(const char *prefix) { return NULL; }
return NULL;
}

View File

@ -498,6 +498,4 @@ void display_refresh(void) {
} }
} }
const char *display_save(const char *prefix) { const char *display_save(const char *prefix) { return NULL; }
return NULL;
}

View File

@ -1,3 +1,5 @@
// clang-format off
/* /*
* This file is part of the MicroPython project, http://micropython.org/ * This file is part of the MicroPython project, http://micropython.org/
* *

View File

@ -31,6 +31,6 @@ def get_type(wire_type):
for msg_name in dir(MessageType): for msg_name in dir(MessageType):
# Modules contain internal variables that may cause exception here. # Modules contain internal variables that may cause exception here.
# No Message begins with underscore so it's safe to skip those. # No Message begins with underscore so it's safe to skip those.
if (msg_name[0] == '_'): if msg_name[0] == "_":
continue continue
type_to_name[getattr(MessageType, msg_name)] = msg_name type_to_name[getattr(MessageType, msg_name)] = msg_name

View File

@ -1,2 +0,0 @@
---
BasedOnStyle: Google

View File

@ -5,9 +5,7 @@ START_TEST(test_ed25519_cardano_sign_vectors) {
ed25519_secret_key secret_key_extension; ed25519_secret_key secret_key_extension;
ed25519_signature signature; ed25519_signature signature;
static const char static const char *vectors[] = {
*vectors[] =
{
"6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5" "6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5"
"3", // private key "3", // private key
"60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8" "60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8"

View File

@ -5,10 +5,11 @@ import hashlib
import os import os
import random import random
import curve25519
import ecdsa import ecdsa
import pytest import pytest
import curve25519
def bytes2num(s): def bytes2num(s):
res = 0 res = 0
@ -30,48 +31,48 @@ class Point:
points = [ points = [
Point( Point(
"secp256k1", "secp256k1",
0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
), ),
Point( Point(
"secp256k1", "secp256k1",
0x1, 0x1,
0x4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee, 0x4218F20AE6C646B363DB68605822FB14264CA8D2587FDD6FBC750D587E76A7EE,
), ),
Point( Point(
"secp256k1", "secp256k1",
0x2, 0x2,
0x66fbe727b2ba09e09f5a98d70a5efce8424c5fa425bbda1c511f860657b8535e, 0x66FBE727B2BA09E09F5A98D70A5EFCE8424C5FA425BBDA1C511F860657B8535E,
), ),
Point( Point(
"secp256k1", "secp256k1",
0x1b, 0x1B,
0x1adcea1cf831b0ad1653e769d1a229091d0cc68d4b0328691b9caacc76e37c90, 0x1ADCEA1CF831B0AD1653E769D1A229091D0CC68D4B0328691B9CAACC76E37C90,
), ),
Point( Point(
"nist256p1", "nist256p1",
0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296,
0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5,
), ),
Point( Point(
"nist256p1", "nist256p1",
0x0, 0x0,
0x66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4, 0x66485C780E2F83D72433BD5D84A06BB6541C2AF31DAE871728BF856A174F93F4,
), ),
Point( Point(
"nist256p1", "nist256p1",
0x0, 0x0,
0x99b7a386f1d07c29dbcc42a27b5f9449abe3d50de25178e8d7407a95e8b06c0b, 0x99B7A386F1D07C29DBCC42A27B5F9449ABE3D50DE25178E8D7407A95E8B06C0B,
), ),
Point( Point(
"nist256p1", "nist256p1",
0xaf8bbdfe8cdd5577acbf345b543d28cf402f4e94d3865b97ea0787f2d3aa5d22, 0xAF8BBDFE8CDD5577ACBF345B543D28CF402F4E94D3865B97EA0787F2D3AA5D22,
0x35802b8b376b995265918b078bc109c21a535176585c40f519aca52d6afc147c, 0x35802B8B376B995265918B078BC109C21A535176585C40F519ACA52D6AFC147C,
), ),
Point( Point(
"nist256p1", "nist256p1",
0x80000, 0x80000,
0x580610071f440f0dcc14a22e2d5d5afc1224c0cd11a3b4b51b8ecd2224ee1ce2, 0x580610071F440F0DCC14A22E2D5D5AFC1224C0CD11A3B4B51B8ECD2224EE1CE2,
), ),
] ]

View File

@ -102,7 +102,7 @@ def is_valid_der(data):
try: try:
structure, _ = der_decode(data) structure, _ = der_decode(data)
return data == der_encode(structure) return data == der_encode(structure)
except: except Exception:
return False return False
@ -140,7 +140,7 @@ def parse_ec_pubkey(public_key):
try: try:
public_key = bytes(public_key["public_key"].asOctets()) public_key = bytes(public_key["public_key"].asOctets())
except: except Exception:
raise ParseError("Not a BER encoded named elliptic curve public key") raise ParseError("Not a BER encoded named elliptic curve public key")
return curve_name, public_key return curve_name, public_key
@ -152,13 +152,13 @@ def parse_ecdsa256_signature(signature):
raise ParseError("Not a valid DER") raise ParseError("Not a valid DER")
try: try:
signature, _ = der_decode(signature, asn1Spec=EcSignature()) signature, _ = der_decode(signature, asn1Spec=EcSignature())
except: except Exception:
raise ParseError("Not a valid DER encoded ECDSA signature") raise ParseError("Not a valid DER encoded ECDSA signature")
try: try:
r = int(signature["r"]).to_bytes(32, byteorder="big") r = int(signature["r"]).to_bytes(32, byteorder="big")
s = int(signature["s"]).to_bytes(32, byteorder="big") s = int(signature["s"]).to_bytes(32, byteorder="big")
signature = r + s signature = r + s
except: except Exception:
raise ParseError("Not a valid DER encoded 256 bit ECDSA signature") raise ParseError("Not a valid DER encoded 256 bit ECDSA signature")
return signature return signature
@ -281,7 +281,7 @@ def aes_cbc_decrypt(key, iv, ciphertext):
def load_json_testvectors(filename): def load_json_testvectors(filename):
try: try:
result = json.loads(open(os.path.join(testvectors_directory, filename)).read()) result = json.loads(open(os.path.join(testvectors_directory, filename)).read())
except: except Exception:
raise DataError() raise DataError()
return result return result
@ -310,7 +310,7 @@ def generate_aes(filename):
plaintext = unhexlify(test["msg"]) plaintext = unhexlify(test["msg"])
ciphertext = unhexlify(test["ct"]) ciphertext = unhexlify(test["ct"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
if len(key) not in [128 / 8, 192 / 8, 256 / 8]: if len(key) not in [128 / 8, 192 / 8, 256 / 8]:
@ -359,7 +359,7 @@ def generate_chacha_poly(filename):
ciphertext = unhexlify(test["ct"]) ciphertext = unhexlify(test["ct"])
tag = unhexlify(test["tag"]) tag = unhexlify(test["tag"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
if result is None: if result is None:
@ -406,7 +406,7 @@ def generate_curve25519_dh(filename):
private_key = unhexlify(test["private"]) private_key = unhexlify(test["private"])
shared = unhexlify(test["shared"]) shared = unhexlify(test["shared"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
if curve_name != "curve25519": if curve_name != "curve25519":
@ -448,7 +448,7 @@ def generate_ecdh(filename):
private_key = parse_signed_hex(test["private"]) private_key = parse_signed_hex(test["private"])
shared = unhexlify(test["shared"]) shared = unhexlify(test["shared"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
try: try:
@ -498,7 +498,7 @@ def generate_ecdsa(filename):
try: try:
public_key = unhexlify(test_group["keyDer"]) public_key = unhexlify(test_group["keyDer"])
except: except Exception:
raise DataError() raise DataError()
try: try:
@ -521,7 +521,7 @@ def generate_ecdsa(filename):
signature = unhexlify(test["sig"]) signature = unhexlify(test["sig"])
message = unhexlify(test["msg"]) message = unhexlify(test["msg"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
if result is None: if result is None:
@ -563,7 +563,7 @@ def generate_eddsa(filename):
try: try:
public_key = unhexlify(test_group["keyDer"]) public_key = unhexlify(test_group["keyDer"])
except: except Exception:
raise DataError() raise DataError()
try: try:
@ -579,7 +579,7 @@ def generate_eddsa(filename):
signature = unhexlify(test["sig"]) signature = unhexlify(test["sig"])
message = unhexlify(test["msg"]) message = unhexlify(test["msg"])
result = parse_result(test["result"]) result = parse_result(test["result"])
except: except Exception:
raise DataError() raise DataError()
if result is None: if result is None:

View File

@ -1,2 +0,0 @@
---
BasedOnStyle: Google

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import print_function from __future__ import print_function
bl = open('bl.bin').read() bl = open("bl.bin").read()
fw = open('fw.bin').read() fw = open("fw.bin").read()
combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:] combined = bl + fw[:256] + (32768 - 256) * "\x00" + fw[256:]
open('combined.bin', 'w').write(combined) open("combined.bin", "w").write(combined)
print('bootloader : %d bytes' % len(bl)) print("bootloader : %d bytes" % len(bl))
print('firmware : %d bytes' % len(fw)) print("firmware : %d bytes" % len(fw))
print('combined : %d bytes' % len(combined)) print("combined : %d bytes" % len(combined))

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys
import os import os
import sys
TOTALSIZE = 32768 TOTALSIZE = 32768
MAXSIZE = TOTALSIZE - 32 MAXSIZE = TOTALSIZE - 32
@ -8,7 +8,10 @@ MAXSIZE = TOTALSIZE - 32
fn = sys.argv[1] fn = sys.argv[1]
fs = os.stat(fn).st_size fs = os.stat(fn).st_size
if fs > MAXSIZE: if fs > MAXSIZE:
raise Exception('bootloader has to be smaller than %d bytes (current size is %d)' % (MAXSIZE, fs)) raise Exception(
with open(fn, 'ab') as f: "bootloader has to be smaller than %d bytes (current size is %d)"
f.write(b'\x00' * (TOTALSIZE - fs)) % (MAXSIZE, fs)
)
with open(fn, "ab") as f:
f.write(b"\x00" * (TOTALSIZE - fs))
f.close() f.close()

View File

@ -7,7 +7,6 @@ import struct
import ecdsa import ecdsa
SLOTS = 3 SLOTS = 3
pubkeys = { pubkeys = {
@ -94,7 +93,7 @@ def update_hashes_in_header(data):
data = bytearray(data) data = bytearray(data)
o = 0 o = 0
for h in prepare_hashes(data[FWHEADER_SIZE:]): for h in prepare_hashes(data[FWHEADER_SIZE:]):
data[0x20 + o:0x20 + o + 32] = h data[0x20 + o : 0x20 + o + 32] = h
o += 32 o += 32
return bytes(data) return bytes(data)
@ -112,6 +111,7 @@ def check_size(data):
size = struct.unpack("<L", data[12:16])[0] size = struct.unpack("<L", data[12:16])[0]
assert size == len(data) - 1024 assert size == len(data) - 1024
def check_signatures(data): def check_signatures(data):
# Analyses given firmware and prints out # Analyses given firmware and prints out
# status of included signatures # status of included signatures
@ -146,7 +146,7 @@ def check_signatures(data):
used.append(indexes[x]) used.append(indexes[x])
print("Slot #%d signature: VALID" % (x + 1), signature.hex()) print("Slot #%d signature: VALID" % (x + 1), signature.hex())
except: except Exception:
print("Slot #%d signature: INVALID" % (x + 1), signature.hex()) print("Slot #%d signature: INVALID" % (x + 1), signature.hex())
@ -202,7 +202,7 @@ def sign(data, is_pem):
index = i index = i
break break
if index == None: if index is None:
raise Exception("Unable to find private key index. Unknown private key?") raise Exception("Unable to find private key index. Unknown private key?")
signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256) signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256)

View File

@ -2,29 +2,37 @@
import hashlib import hashlib
import os import os
import subprocess import subprocess
import ecdsa
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
print('master secret:', end='') import ecdsa
print("master secret:", end="")
h = input() h = input()
if h: if h:
h = unhexlify(h).encode('ascii') h = unhexlify(h).encode("ascii")
else: else:
h = hashlib.sha256(os.urandom(1024)).digest() h = hashlib.sha256(os.urandom(1024)).digest()
print() print()
print('master secret:', hexlify(h)) print("master secret:", hexlify(h))
print() print()
for i in range(1, 6): for i in range(1, 6):
se = hashlib.sha256(h + chr(i).encode('ascii')).hexdigest() se = hashlib.sha256(h + chr(i).encode("ascii")).hexdigest()
print('seckey', i, ':', se) print("seckey", i, ":", se)
sk = ecdsa.SigningKey.from_secret_exponent(secexp = int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256) sk = ecdsa.SigningKey.from_secret_exponent(
print('pubkey', i, ':', (b'04' + hexlify(sk.get_verifying_key().to_string())).decode('ascii')) secexp=int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256
print(sk.to_pem().decode('ascii')) )
print(
"pubkey",
i,
":",
(b"04" + hexlify(sk.get_verifying_key().to_string())).decode("ascii"),
)
print(sk.to_pem().decode("ascii"))
p = subprocess.Popen('ssss-split -t 3 -n 5 -x'.split(' '), stdin = subprocess.PIPE) p = subprocess.Popen("ssss-split -t 3 -n 5 -x".split(" "), stdin=subprocess.PIPE)
p.communicate(input = hexlify(h) + '\n') p.communicate(input=hexlify(h) + "\n")
# to recover use: # to recover use:
# $ ssss-combine -t 3 -x # $ ssss-combine -t 3 -x

View File

@ -1,19 +1,19 @@
#!/usr/bin/env python #!/usr/bin/env python
from hashlib import sha256 from hashlib import sha256
fn = '../bootloader/bootloader.bin' fn = "../bootloader/bootloader.bin"
data = open(fn, 'rb').read() data = open(fn, "rb").read()
if len(data) > 32768: if len(data) > 32768:
raise Exception('bootloader has to be smaller than 32768 bytes') raise Exception("bootloader has to be smaller than 32768 bytes")
data += b'\x00' * (32768 - len(data)) data += b"\x00" * (32768 - len(data))
h = sha256(sha256(data).digest()).digest() h = sha256(sha256(data).digest()).digest()
bl_hash = ', '.join('0x%02x' % x for x in bytearray(h)) bl_hash = ", ".join("0x%02x" % x for x in bytearray(h))
bl_data = ', '.join('0x%02x' % x for x in bytearray(data)) bl_data = ", ".join("0x%02x" % x for x in bytearray(data))
with open('bl_data.h', 'wt') as f: with open("bl_data.h", "wt") as f:
f.write('static const uint8_t bl_hash[32] = {%s};\n' % bl_hash) f.write("static const uint8_t bl_hash[32] = {%s};\n" % bl_hash)
f.write('static const uint8_t bl_data[32768] = {%s};\n' % bl_data) f.write("static const uint8_t bl_data[32768] = {%s};\n" % bl_data)

View File

@ -256,12 +256,12 @@ void fsm_msgEntropyAck(const EntropyAck *msg) {
} }
void fsm_msgBackupDevice(const BackupDevice *msg) { void fsm_msgBackupDevice(const BackupDevice *msg) {
(void)msg;
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN_UNCACHED CHECK_PIN_UNCACHED
(void)
msg;
char mnemonic[MAX_MNEMONIC_LEN + 1]; char mnemonic[MAX_MNEMONIC_LEN + 1];
if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { if (config_getMnemonic(mnemonic, sizeof(mnemonic))) {
reset_backup(true, mnemonic); reset_backup(true, mnemonic);

View File

@ -1,11 +1,16 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys import sys
from collections import defaultdict from collections import defaultdict
from messages_pb2 import MessageType
from messages_pb2 import wire_in, wire_out from messages_pb2 import (
from messages_pb2 import wire_debug_in, wire_debug_out MessageType,
from messages_pb2 import wire_bootloader, wire_no_fsm wire_bootloader,
wire_debug_in,
wire_debug_out,
wire_in,
wire_no_fsm,
wire_out,
)
fh = open("messages_map.h", "wt") fh = open("messages_map.h", "wt")
fl = open("messages_map_limits.h", "wt") fl = open("messages_map_limits.h", "wt")
@ -24,7 +29,7 @@ LABELS = {
def handle_message(fh, fl, skipped, message, extension): def handle_message(fh, fl, skipped, message, extension):
name = message.name name = message.name
short_name = name.split("MessageType_", 1).pop() short_name = name.split("MessageType_", 1).pop()
assert(short_name != name) assert short_name != name
for s in skipped: for s in skipped:
if short_name.startswith(s): if short_name.startswith(s):
@ -37,14 +42,14 @@ def handle_message(fh, fl, skipped, message, extension):
bootloader = options.Extensions[wire_bootloader] bootloader = options.Extensions[wire_bootloader]
no_fsm = options.Extensions[wire_no_fsm] no_fsm = options.Extensions[wire_no_fsm]
if getattr(options, 'deprecated', None): if getattr(options, "deprecated", None):
fh.write('\t// Message %s is deprecated\n' % short_name) fh.write("\t// Message %s is deprecated\n" % short_name)
return return
if bootloader: if bootloader:
fh.write('\t// Message %s is used in bootloader mode only\n' % short_name) fh.write("\t// Message %s is used in bootloader mode only\n" % short_name)
return return
if no_fsm: if no_fsm:
fh.write('\t// Message %s is not used in FSM\n' % short_name) fh.write("\t// Message %s is not used in FSM\n" % short_name)
return return
if direction == "i": if direction == "i":
@ -52,13 +57,15 @@ def handle_message(fh, fl, skipped, message, extension):
else: else:
process_func = "0" process_func = "0"
fh.write(TEMPLATE.format( fh.write(
TEMPLATE.format(
type="'%c'," % interface, type="'%c'," % interface,
dir="'%c'," % direction, dir="'%c'," % direction,
msg_id="MessageType_%s," % name, msg_id="MessageType_%s," % name,
fields="%s_fields," % short_name, fields="%s_fields," % short_name,
process_func=process_func, process_func=process_func,
)) )
)
bufsize = None bufsize = None
t = interface + direction t = interface + direction
@ -69,13 +76,20 @@ def handle_message(fh, fl, skipped, message, extension):
elif t == "do": elif t == "do":
bufsize = "MSG_DEBUG_OUT_SIZE" bufsize = "MSG_DEBUG_OUT_SIZE"
if bufsize: if bufsize:
fl.write("_Static_assert(%s >= sizeof(%s), \"msg buffer too small\");\n" % (bufsize, short_name)) fl.write(
'_Static_assert(%s >= sizeof(%s), "msg buffer too small");\n'
% (bufsize, short_name)
)
skipped = sys.argv[1:] skipped = sys.argv[1:]
fh.write("\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n") fh.write(
fl.write("// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n\n") "\t// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n"
)
fl.write(
"// This file is automatically generated by messages_map.py -- DO NOT EDIT!\n\n"
)
messages = defaultdict(list) messages = defaultdict(list)

View File

@ -1,3 +1,4 @@
// clang-format off
/** /**
* Copyright FIDO Alliance, 2017 * Copyright FIDO Alliance, 2017
* *

View File

@ -1,3 +1,4 @@
// clang-format off
/** /**
* Copyright FIDO Alliance, 2017 * Copyright FIDO Alliance, 2017
* *

View File

@ -1,3 +1,4 @@
// clang-format off
#include "bitmaps.h" #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_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, };

View File

@ -1,45 +1,50 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import glob import glob
import os import os
from PIL import Image from PIL import Image
hdrs = [] hdrs = []
data = [] data = []
imgs = [] imgs = []
def encode_pixels(img): def encode_pixels(img):
r = '' r = ""
img = [ (x[0] + x[1] + x[2] > 384 and '1' or '0') for x in img] img = [(x[0] + x[1] + x[2] > 384 and "1" or "0") for x in img]
for i in range(len(img) // 8): for i in range(len(img) // 8):
c = ''.join(img[i * 8 : i * 8 + 8]) c = "".join(img[i * 8 : i * 8 + 8])
r += '0x%02x, ' % int(c, 2) r += "0x%02x, " % int(c, 2)
return r return r
cnt = 0 cnt = 0
for fn in sorted(glob.glob('*.png')): for fn in sorted(glob.glob("*.png")):
print('Processing:', fn) print("Processing:", fn)
im = Image.open(fn) im = Image.open(fn)
name = os.path.splitext(fn)[0] name = os.path.splitext(fn)[0]
w, h = im.size w, h = im.size
if w % 8 != 0: if w % 8 != 0:
raise Exception('Width must be divisable by 8! (%s is %dx%d)' % (fn, w, h)) raise Exception("Width must be divisable by 8! (%s is %dx%d)" % (fn, w, h))
img = list(im.getdata()) img = list(im.getdata())
hdrs.append('extern const BITMAP bmp_%s;\n' % name) 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)) 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))) data.append("const uint8_t bmp_%s_data[] = { %s};\n" % (name, encode_pixels(img)))
cnt += 1 cnt += 1
with open('../bitmaps.c', 'wt') as f: with open("../bitmaps.c", "wt") as f:
f.write("// clang-format off\n")
f.write('#include "bitmaps.h"\n\n') f.write('#include "bitmaps.h"\n\n')
for i in range(cnt): for i in range(cnt):
f.write(data[i]) f.write(data[i])
f.write('\n') f.write("\n")
for i in range(cnt): for i in range(cnt):
f.write(imgs[i]) f.write(imgs[i])
f.close() f.close()
with open('../bitmaps.h', 'wt') as f: with open("../bitmaps.h", "wt") as f:
f.write('''#ifndef __BITMAPS_H__ f.write(
"""#ifndef __BITMAPS_H__
#define __BITMAPS_H__ #define __BITMAPS_H__
#include <stdint.h> #include <stdint.h>
@ -49,10 +54,11 @@ typedef struct {
const uint8_t *data; const uint8_t *data;
} BITMAP; } BITMAP;
''') """
)
for i in range(cnt): for i in range(cnt):
f.write(hdrs[i]) f.write(hdrs[i])
f.write('\n#endif\n') f.write("\n#endif\n")
f.close() f.close()

View File

@ -1,17 +1,15 @@
#include "fonts.h" #include "fonts.h"
const uint8_t * const font_data[2][128] = { const uint8_t *const font_data[2][128] = {
{ {
#include"font.inc" #include "font.inc"
}, },
{ {
#include"fontfixed.inc" #include "fontfixed.inc"
}, },
}; };
int fontCharWidth(int font, char c) { int fontCharWidth(int font, char c) { return font_data[font][c & 0x7f][0]; }
return font_data[font][c & 0x7f][0];
}
const uint8_t *fontCharData(int font, char c) { const uint8_t *fontCharData(int font, char c) {
return font_data[font][c & 0x7f] + 1; return font_data[font][c & 0x7f] + 1;

View File

@ -8,7 +8,7 @@
#define FONT_FIXED 1 #define FONT_FIXED 1
#define FONT_DOUBLE 0x80 #define FONT_DOUBLE 0x80
extern const uint8_t * const font_data[2][128]; extern const uint8_t *const font_data[2][128];
int fontCharWidth(int font, char c); int fontCharWidth(int font, char c);
const uint8_t *fontCharData(int font, char c); const uint8_t *fontCharData(int font, char c);

View File

@ -1,39 +1,40 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from PIL import Image from PIL import Image
class Img(object):
class Img(object):
def __init__(self, fn): def __init__(self, fn):
im = Image.open(fn) im = Image.open(fn)
self.w, self.h = im.size self.w, self.h = im.size
self.data = list(im.getdata()) self.data = list(im.getdata())
def pixel(self, r, c): def pixel(self, r, c):
p = self.data[ r + c * self.w ] p = self.data[r + c * self.w]
if p == (255, 255, 255): if p == (255, 255, 255):
return '0' return "0"
if p == (0, 0, 0): if p == (0, 0, 0):
return '1' return "1"
if p == (255, 0, 255): if p == (255, 0, 255):
return None return None
raise Exception('Unknown color', p) raise Exception("Unknown color", p)
def convert(imgfile, outfile): def convert(imgfile, outfile):
img = Img(imgfile) img = Img(imgfile)
cur = '' cur = ""
with open(outfile, 'w') as f: with open(outfile, "w") as f:
for i in range(128): for i in range(128):
x = (i % 16) * 10 x = (i % 16) * 10
y = (i // 16) * 10 y = (i // 16) * 10
cur = '' cur = ""
while img.pixel(x, y) != None: while img.pixel(x, y) is not None:
val = ''.join(img.pixel(x, y + j) for j in range(8)) val = "".join(img.pixel(x, y + j) for j in range(8))
x += 1 x += 1
cur += '\\x%02x' % int(val, 2) cur += "\\x%02x" % int(val, 2)
cur = '\\x%02x' % (len(cur) // 4) + cur cur = "\\x%02x" % (len(cur) // 4) + cur
ch = chr(i) if i >= 32 and i <= 126 else '_' ch = chr(i) if i >= 32 and i <= 126 else "_"
f.write('\t/* 0x%02x %c */ (uint8_t *)"%s",\n' % (i, ch , cur)) f.write('\t/* 0x%02x %c */ (uint8_t *)"%s",\n' % (i, ch, cur))
convert('fonts/fontfixed.png', 'fontfixed.inc')
convert('fonts/font.png', 'font.inc') convert("fonts/fontfixed.png", "fontfixed.inc")
convert("fonts/font.png", "font.inc")

View File

@ -2,99 +2,102 @@
from __future__ import print_function from __future__ import print_function
handlers = [ handlers = [
'hard_fault_handler', "hard_fault_handler",
'mem_manage_handler', "mem_manage_handler",
'bus_fault_handler', "bus_fault_handler",
'usage_fault_handler', "usage_fault_handler",
'nvic_wwdg_isr', "nvic_wwdg_isr",
'pvd_isr', "pvd_isr",
'tamp_stamp_isr', "tamp_stamp_isr",
'rtc_wkup_isr', "rtc_wkup_isr",
'flash_isr', "flash_isr",
'rcc_isr', "rcc_isr",
'exti0_isr', "exti0_isr",
'exti1_isr', "exti1_isr",
'exti2_isr', "exti2_isr",
'exti3_isr', "exti3_isr",
'exti4_isr', "exti4_isr",
'dma1_stream0_isr', "dma1_stream0_isr",
'dma1_stream1_isr', "dma1_stream1_isr",
'dma1_stream2_isr', "dma1_stream2_isr",
'dma1_stream3_isr', "dma1_stream3_isr",
'dma1_stream4_isr', "dma1_stream4_isr",
'dma1_stream5_isr', "dma1_stream5_isr",
'dma1_stream6_isr', "dma1_stream6_isr",
'adc_isr', "adc_isr",
'can1_tx_isr', "can1_tx_isr",
'can1_rx0_isr', "can1_rx0_isr",
'can1_rx1_isr', "can1_rx1_isr",
'can1_sce_isr', "can1_sce_isr",
'exti9_5_isr', "exti9_5_isr",
'tim1_brk_tim9_isr', "tim1_brk_tim9_isr",
'tim1_up_tim10_isr', "tim1_up_tim10_isr",
'tim1_trg_com_tim11_isr', "tim1_trg_com_tim11_isr",
'tim1_cc_isr', "tim1_cc_isr",
'tim2_isr', "tim2_isr",
'tim3_isr', "tim3_isr",
'tim4_isr', "tim4_isr",
'i2c1_ev_isr', "i2c1_ev_isr",
'i2c1_er_isr', "i2c1_er_isr",
'i2c2_ev_isr', "i2c2_ev_isr",
'i2c2_er_isr', "i2c2_er_isr",
'spi1_isr', "spi1_isr",
'spi2_isr', "spi2_isr",
'usart1_isr', "usart1_isr",
'usart2_isr', "usart2_isr",
'usart3_isr', "usart3_isr",
'exti15_10_isr', "exti15_10_isr",
'rtc_alarm_isr', "rtc_alarm_isr",
'usb_fs_wkup_isr', "usb_fs_wkup_isr",
'tim8_brk_tim12_isr', "tim8_brk_tim12_isr",
'tim8_up_tim13_isr', "tim8_up_tim13_isr",
'tim8_trg_com_tim14_isr', "tim8_trg_com_tim14_isr",
'tim8_cc_isr', "tim8_cc_isr",
'dma1_stream7_isr', "dma1_stream7_isr",
'fsmc_isr', "fsmc_isr",
'sdio_isr', "sdio_isr",
'tim5_isr', "tim5_isr",
'spi3_isr', "spi3_isr",
'uart4_isr', "uart4_isr",
'uart5_isr', "uart5_isr",
'tim6_dac_isr', "tim6_dac_isr",
'tim7_isr', "tim7_isr",
'dma2_stream0_isr', "dma2_stream0_isr",
'dma2_stream1_isr', "dma2_stream1_isr",
'dma2_stream2_isr', "dma2_stream2_isr",
'dma2_stream3_isr', "dma2_stream3_isr",
'dma2_stream4_isr', "dma2_stream4_isr",
'eth_isr', "eth_isr",
'eth_wkup_isr', "eth_wkup_isr",
'can2_tx_isr', "can2_tx_isr",
'can2_rx0_isr', "can2_rx0_isr",
'can2_rx1_isr', "can2_rx1_isr",
'can2_sce_isr', "can2_sce_isr",
'otg_fs_isr', "otg_fs_isr",
'dma2_stream5_isr', "dma2_stream5_isr",
'dma2_stream6_isr', "dma2_stream6_isr",
'dma2_stream7_isr', "dma2_stream7_isr",
'usart6_isr', "usart6_isr",
'i2c3_ev_isr', "i2c3_ev_isr",
'i2c3_er_isr', "i2c3_er_isr",
'otg_hs_ep1_out_isr', "otg_hs_ep1_out_isr",
'otg_hs_ep1_in_isr', "otg_hs_ep1_in_isr",
'otg_hs_wkup_isr', "otg_hs_wkup_isr",
'otg_hs_isr', "otg_hs_isr",
'dcmi_isr', "dcmi_isr",
'cryp_isr', "cryp_isr",
'hash_rng_isr', "hash_rng_isr",
] ]
with open('handlers.c', 'wt') as f: with open("handlers.c", "wt") as f:
f.write('#include "layout.h"\n') f.write('#include "layout.h"\n')
f.write('#include "oled.h"\n\n') f.write('#include "oled.h"\n\n')
for i in handlers: for i in handlers:
f.write('void __attribute__((noreturn)) %s(void)\n' % i) f.write("void __attribute__((noreturn)) %s(void)\n" % i)
f.write('{\n') 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(
f.write('\tfor (;;) {} // loop forever\n') '\tlayoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Encountered", NULL, "%s", NULL, "Please restart", "the device.");\n'
f.write('}\n\n') % i.upper()
)
f.write("\tfor (;;) {} // loop forever\n")
f.write("}\n\n")

View File

@ -1,7 +1,7 @@
#include <readline/history.h>
#include <readline/readline.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "fonts.h" #include "fonts.h"

35
setup.cfg Normal file
View File

@ -0,0 +1,35 @@
[flake8]
ignore =
# E203 whitespace before ':'
E203,
# E221: multiple spaces before operator
E221,
# E241: multiple spaces after ':'
E241,
# E402: module level import not at top of file
E402,
# E501: line too long
E501,
# E741 ambiguous variable name
E741,
# F403: star import used, unable to detect undefined names
F403,
# F405: name may be undefined, or defined from star imports
F405,
# W503: line break before binary operator
W503
[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
combine_as_imports = True
line_length = 88
not_skip=__init__.py
forced_separate = apps
known_standard_library = micropython,ubinascii,ustruct,uctypes,utime,utimeq,trezorio,trezorui,trezorutils,trezorconfig
[tool:pytest]
addopts = --pyargs trezorlib.tests.device_tests
xfail_strict = true
run_xfail =

View File

@ -19,9 +19,9 @@
#include <string.h> #include <string.h>
#include "norcow.h"
#include "flash.h"
#include "common.h" #include "common.h"
#include "flash.h"
#include "norcow.h"
// NRC2 = 4e524332 // NRC2 = 4e524332
#define NORCOW_MAGIC ((uint32_t)0x3243524e) #define NORCOW_MAGIC ((uint32_t)0x3243524e)
@ -40,12 +40,14 @@
#define NORCOW_KEY_DELETED (0x0000) #define NORCOW_KEY_DELETED (0x0000)
// The offset from the beginning of the sector where stored items start. // The offset from the beginning of the sector where stored items start.
#define NORCOW_STORAGE_START (NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN) #define NORCOW_STORAGE_START \
(NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN)
// Map from sector index to sector number. // Map from sector index to sector number.
static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS; static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS;
// The index of the active reading sector and writing sector. These should be equal except when storage version upgrade or compaction is in progress. // The index of the active reading sector and writing sector. These should be
// equal except when storage version upgrade or compaction is in progress.
static uint8_t norcow_active_sector = 0; static uint8_t norcow_active_sector = 0;
static uint8_t norcow_write_sector = 0; static uint8_t norcow_write_sector = 0;
@ -59,8 +61,7 @@ static uint32_t norcow_free_offset = 0;
* Returns pointer to sector, starting with offset * Returns pointer to sector, starting with offset
* Fails when there is not enough space for data of given size * Fails when there is not enough space for data of given size
*/ */
static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size) static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size) {
{
ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector"); ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector");
return flash_get_address(norcow_sectors[sector], offset, size); return flash_get_address(norcow_sectors[sector], offset, size);
} }
@ -68,8 +69,8 @@ static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size)
/* /*
* Writes data to given sector, starting from offset * Writes data to given sector, starting from offset
*/ */
static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, const uint8_t *data, uint16_t len) static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix,
{ const uint8_t *data, uint16_t len) {
if (sector >= NORCOW_SECTOR_COUNT) { if (sector >= NORCOW_SECTOR_COUNT) {
return secfalse; return secfalse;
} }
@ -105,11 +106,10 @@ static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, co
/* /*
* Erases sector (and sets a magic) * Erases sector (and sets a magic)
*/ */
static void erase_sector(uint8_t sector, secbool set_magic) static void erase_sector(uint8_t sector, secbool set_magic) {
{
#if NORCOW_HEADER_LEN > 0 #if NORCOW_HEADER_LEN > 0
// Backup the sector header. // Backup the sector header.
uint32_t header_backup[NORCOW_HEADER_LEN/sizeof(uint32_t)]; uint32_t header_backup[NORCOW_HEADER_LEN / sizeof(uint32_t)];
const void *sector_start = norcow_ptr(sector, 0, NORCOW_HEADER_LEN); const void *sector_start = norcow_ptr(sector, 0, NORCOW_HEADER_LEN);
memcpy(header_backup, sector_start, sizeof(header_backup)); memcpy(header_backup, sector_start, sizeof(header_backup));
#endif #endif
@ -119,15 +119,20 @@ static void erase_sector(uint8_t sector, secbool set_magic)
#if NORCOW_HEADER_LEN > 0 #if NORCOW_HEADER_LEN > 0
// Copy the sector header back. // Copy the sector header back.
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
for (uint32_t i = 0; i < NORCOW_HEADER_LEN/sizeof(uint32_t); ++i) { for (uint32_t i = 0; i < NORCOW_HEADER_LEN / sizeof(uint32_t); ++i) {
ensure(flash_write_word(norcow_sectors[sector], i*sizeof(uint32_t), header_backup[i]), NULL); ensure(flash_write_word(norcow_sectors[sector], i * sizeof(uint32_t),
header_backup[i]),
NULL);
} }
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
#endif #endif
if (sectrue == set_magic) { if (sectrue == set_magic) {
ensure(norcow_write(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC, NULL, 0), "set magic failed"); ensure(norcow_write(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC, NULL, 0),
ensure(norcow_write(sector, NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN, ~NORCOW_VERSION, NULL, 0), "set version failed"); "set magic failed");
ensure(norcow_write(sector, NORCOW_HEADER_LEN + NORCOW_MAGIC_LEN,
~NORCOW_VERSION, NULL, 0),
"set version failed");
} }
} }
@ -136,8 +141,8 @@ static void erase_sector(uint8_t sector, secbool set_magic)
/* /*
* Reads one item starting from offset * Reads one item starting from offset
*/ */
static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key, const void **val, uint16_t *len, uint32_t *pos) static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key,
{ const void **val, uint16_t *len, uint32_t *pos) {
*pos = offset; *pos = offset;
const void *k = norcow_ptr(sector, *pos, 2); const void *k = norcow_ptr(sector, *pos, 2);
@ -163,8 +168,8 @@ static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key, const v
/* /*
* Writes one item starting from offset * Writes one item starting from offset
*/ */
static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, const void *val, uint16_t len, uint32_t *pos) static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key,
{ const void *val, uint16_t len, uint32_t *pos) {
uint32_t prefix = ((uint32_t)len << 16) | key; uint32_t prefix = ((uint32_t)len << 16) | key;
*pos = offset + NORCOW_PREFIX_LEN + len; *pos = offset + NORCOW_PREFIX_LEN + len;
ALIGN4(*pos); ALIGN4(*pos);
@ -174,9 +179,10 @@ static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, const v
/* /*
* Finds the offset from the beginning of the sector where stored items start. * Finds the offset from the beginning of the sector where stored items start.
*/ */
static secbool find_start_offset(uint8_t sector, uint32_t *offset, uint32_t *version) static secbool find_start_offset(uint8_t sector, uint32_t *offset,
{ uint32_t *version) {
const uint32_t *magic = norcow_ptr(sector, NORCOW_HEADER_LEN, NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN); const uint32_t *magic = norcow_ptr(sector, NORCOW_HEADER_LEN,
NORCOW_MAGIC_LEN + NORCOW_VERSION_LEN);
if (magic == NULL) { if (magic == NULL) {
return secfalse; return secfalse;
} }
@ -197,8 +203,8 @@ static secbool find_start_offset(uint8_t sector, uint32_t *offset, uint32_t *ver
/* /*
* Finds item in given sector * Finds item in given sector
*/ */
static secbool find_item(uint8_t sector, uint16_t key, const void **val, uint16_t *len) static secbool find_item(uint8_t sector, uint16_t key, const void **val,
{ uint16_t *len) {
*val = NULL; *val = NULL;
*len = 0; *len = 0;
@ -227,8 +233,7 @@ static secbool find_item(uint8_t sector, uint16_t key, const void **val, uint16_
/* /*
* Finds first unused offset in given sector * Finds first unused offset in given sector
*/ */
static uint32_t find_free_offset(uint8_t sector) static uint32_t find_free_offset(uint8_t sector) {
{
uint32_t offset; uint32_t offset;
uint32_t version; uint32_t version;
if (sectrue != find_start_offset(sector, &offset, &version)) { if (sectrue != find_start_offset(sector, &offset, &version)) {
@ -250,8 +255,7 @@ static uint32_t find_free_offset(uint8_t sector)
/* /*
* Compacts active sector and sets new active sector * Compacts active sector and sets new active sector
*/ */
static void compact(void) static void compact(void) {
{
uint32_t offsetr; uint32_t offsetr;
uint32_t version; uint32_t version;
if (sectrue != find_start_offset(norcow_active_sector, &offsetr, &version)) { if (sectrue != find_start_offset(norcow_active_sector, &offsetr, &version)) {
@ -280,7 +284,8 @@ static void compact(void)
// copy the item // copy the item
uint32_t posw; uint32_t posw;
ensure(write_item(norcow_write_sector, offsetw, k, v, l, &posw), "compaction write failed"); ensure(write_item(norcow_write_sector, offsetw, k, v, l, &posw),
"compaction write failed");
offsetw = posw; offsetw = posw;
} }
@ -293,15 +298,15 @@ static void compact(void)
/* /*
* Initializes storage * Initializes storage
*/ */
void norcow_init(uint32_t *norcow_version) void norcow_init(uint32_t *norcow_version) {
{
flash_init(); flash_init();
secbool found = secfalse; secbool found = secfalse;
*norcow_version = 0; *norcow_version = 0;
// detect active sector - starts with magic and has highest version // detect active sector - starts with magic and has highest version
for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) { for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) {
uint32_t offset; uint32_t offset;
if (sectrue == find_start_offset(i, &offset, &norcow_active_version) && norcow_active_version >= *norcow_version) { if (sectrue == find_start_offset(i, &offset, &norcow_active_version) &&
norcow_active_version >= *norcow_version) {
found = sectrue; found = sectrue;
norcow_active_sector = i; norcow_active_sector = i;
*norcow_version = norcow_active_version; *norcow_version = norcow_active_version;
@ -326,8 +331,7 @@ void norcow_init(uint32_t *norcow_version)
/* /*
* Wipe the storage * Wipe the storage
*/ */
void norcow_wipe(void) void norcow_wipe(void) {
{
erase_sector(0, sectrue); erase_sector(0, sectrue);
for (uint8_t i = 1; i < NORCOW_SECTOR_COUNT; i++) { for (uint8_t i = 1; i < NORCOW_SECTOR_COUNT; i++) {
erase_sector(i, secfalse); erase_sector(i, secfalse);
@ -341,16 +345,16 @@ void norcow_wipe(void)
/* /*
* Looks for the given key, returns status of the operation * Looks for the given key, returns status of the operation
*/ */
secbool norcow_get(uint16_t key, const void **val, uint16_t *len) secbool norcow_get(uint16_t key, const void **val, uint16_t *len) {
{
return find_item(norcow_active_sector, key, val, len); return find_item(norcow_active_sector, key, val, len);
} }
/* /*
* Reads the next entry in the storage starting at offset. Returns secfalse if there is none. * Reads the next entry in the storage starting at offset. Returns secfalse if
* there is none.
*/ */
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint16_t *len) secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val,
{ uint16_t *len) {
if (*offset == 0) { if (*offset == 0) {
uint32_t version; uint32_t version;
if (sectrue != find_start_offset(norcow_active_sector, offset, &version)) { if (sectrue != find_start_offset(norcow_active_sector, offset, &version)) {
@ -400,14 +404,13 @@ secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint1
* as val, then norcow_set allocates a new key of size len. The value should * as val, then norcow_set allocates a new key of size len. The value should
* then be written using norcow_update_bytes(). * then be written using norcow_update_bytes().
*/ */
secbool norcow_set(uint16_t key, const void *val, uint16_t len) secbool norcow_set(uint16_t key, const void *val, uint16_t len) {
{
secbool found; secbool found;
return norcow_set_ex(key, val, len, &found); return norcow_set_ex(key, val, len, &found);
} }
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *found) secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
{ secbool *found) {
// Key 0xffff is used as a marker to indicate that the entry is not set. // Key 0xffff is used as a marker to indicate that the entry is not set.
if (key == NORCOW_KEY_FREE) { if (key == NORCOW_KEY_FREE) {
return secfalse; return secfalse;
@ -422,12 +425,15 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
// Try to update the entry if it already exists. // Try to update the entry if it already exists.
uint32_t offset = 0; uint32_t offset = 0;
if (sectrue == *found) { if (sectrue == *found) {
offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE); offset =
(const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
if (val != NULL && len_old == len) { if (val != NULL && len_old == len) {
ret = sectrue; ret = sectrue;
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
for (uint16_t i = 0; i < len; i++) { for (uint16_t i = 0; i < len; i++) {
if (sectrue != flash_write_byte(sector_num, offset + i, ((const uint8_t*)val)[i])) { if (sectrue != flash_write_byte(sector_num, offset + i,
((const uint8_t *)val)[i])) {
ret = secfalse; ret = secfalse;
break; break;
} }
@ -444,7 +450,8 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
// Update the prefix to indicate that the old item has been deleted. // Update the prefix to indicate that the old item has been deleted.
uint32_t prefix = (uint32_t)len_old << 16; uint32_t prefix = (uint32_t)len_old << 16;
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix), NULL); ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix),
NULL);
// Delete the old item data. // Delete the old item data.
uint32_t end = offset + len_old; uint32_t end = offset + len_old;
@ -461,7 +468,8 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
} }
// Write new item. // Write new item.
uint32_t pos; uint32_t pos;
ret = write_item(norcow_write_sector, norcow_free_offset, key, val, len, &pos); ret = write_item(norcow_write_sector, norcow_free_offset, key, val, len,
&pos);
if (sectrue == ret) { if (sectrue == ret) {
norcow_free_offset = pos; norcow_free_offset = pos;
} }
@ -472,8 +480,7 @@ secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *foun
/* /*
* Deletes the given key, returns status of the operation. * Deletes the given key, returns status of the operation.
*/ */
secbool norcow_delete(uint16_t key) secbool norcow_delete(uint16_t key) {
{
// Key 0xffff is used as a marker to indicate that the entry is not set. // Key 0xffff is used as a marker to indicate that the entry is not set.
if (key == NORCOW_KEY_FREE) { if (key == NORCOW_KEY_FREE) {
return secfalse; return secfalse;
@ -486,13 +493,16 @@ secbool norcow_delete(uint16_t key)
return secfalse; return secfalse;
} }
uint32_t offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE); uint32_t offset =
(const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE);
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
// Update the prefix to indicate that the item has been deleted. // Update the prefix to indicate that the item has been deleted.
uint32_t prefix = (uint32_t)len << 16; uint32_t prefix = (uint32_t)len << 16;
ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix), NULL); ensure(flash_write_word(sector_num, offset - NORCOW_PREFIX_LEN, prefix),
NULL);
// Delete the item data. // Delete the item data.
uint32_t end = offset + len; uint32_t end = offset + len;
@ -510,8 +520,7 @@ secbool norcow_delete(uint16_t key)
* Update a word in flash at the given pointer. The pointer must point * Update a word in flash at the given pointer. The pointer must point
* into the NORCOW area. * into the NORCOW area.
*/ */
secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value) secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value) {
{
const void *ptr; const void *ptr;
uint16_t len; uint16_t len;
if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) { if (sectrue != find_item(norcow_write_sector, key, &ptr, &len)) {
@ -520,9 +529,14 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value)
if ((offset & 3) != 0 || offset >= len) { if ((offset & 3) != 0 || offset >= len) {
return secfalse; return secfalse;
} }
uint32_t sector_offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) + offset; uint32_t sector_offset =
(const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) +
offset;
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
ensure(flash_write_word(norcow_sectors[norcow_write_sector], sector_offset, value), NULL); ensure(flash_write_word(norcow_sectors[norcow_write_sector], sector_offset,
value),
NULL);
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
return sectrue; return sectrue;
} }
@ -530,8 +544,8 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value)
/* /*
* Update the value of the given key starting at the given offset. * Update the value of the given key starting at the given offset.
*/ */
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uint8_t *data, const uint16_t len) secbool norcow_update_bytes(const uint16_t key, const uint16_t offset,
{ const uint8_t *data, const uint16_t len) {
const void *ptr; const void *ptr;
uint16_t allocated_len; uint16_t allocated_len;
if (sectrue != find_item(norcow_write_sector, key, &ptr, &allocated_len)) { if (sectrue != find_item(norcow_write_sector, key, &ptr, &allocated_len)) {
@ -540,7 +554,10 @@ secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uin
if (offset + len > allocated_len) { if (offset + len > allocated_len) {
return secfalse; return secfalse;
} }
uint32_t sector_offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) + offset; uint32_t sector_offset =
(const uint8_t *)ptr -
(const uint8_t *)norcow_ptr(norcow_write_sector, 0, NORCOW_SECTOR_SIZE) +
offset;
uint8_t sector = norcow_sectors[norcow_write_sector]; uint8_t sector = norcow_sectors[norcow_write_sector];
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
for (uint16_t i = 0; i < len; i++, sector_offset++) { for (uint16_t i = 0; i < len; i++, sector_offset++) {
@ -553,8 +570,7 @@ secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uin
/* /*
* Complete storage version upgrade * Complete storage version upgrade
*/ */
secbool norcow_upgrade_finish(void) secbool norcow_upgrade_finish(void) {
{
erase_sector(norcow_active_sector, secfalse); erase_sector(norcow_active_sector, secfalse);
norcow_active_sector = norcow_write_sector; norcow_active_sector = norcow_write_sector;
norcow_active_version = NORCOW_VERSION; norcow_active_version = NORCOW_VERSION;

View File

@ -45,9 +45,11 @@ void norcow_wipe(void);
secbool norcow_get(uint16_t key, const void **val, uint16_t *len); secbool norcow_get(uint16_t key, const void **val, uint16_t *len);
/* /*
* Reads the next entry in the storage starting at offset. Returns secfalse if there is none. * Reads the next entry in the storage starting at offset. Returns secfalse if
* there is none.
*/ */
secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint16_t *len); secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val,
uint16_t *len);
/* /*
* Sets the given key, returns status of the operation. If NULL is passed * Sets the given key, returns status of the operation. If NULL is passed
@ -55,7 +57,8 @@ secbool norcow_get_next(uint32_t *offset, uint16_t *key, const void **val, uint1
* then be written using norcow_update_bytes(). * then be written using norcow_update_bytes().
*/ */
secbool norcow_set(uint16_t key, const void *val, uint16_t len); secbool norcow_set(uint16_t key, const void *val, uint16_t len);
secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len, secbool *found); secbool norcow_set_ex(uint16_t key, const void *val, uint16_t len,
secbool *found);
/* /*
* Deletes the given key, returns status of the operation. * Deletes the given key, returns status of the operation.
@ -72,7 +75,8 @@ secbool norcow_update_word(uint16_t key, uint16_t offset, uint32_t value);
* Update the value of the given key starting at the given offset. * Update the value of the given key starting at the given offset.
* Note that you can only change bits from 1 to 0. * Note that you can only change bits from 1 to 0.
*/ */
secbool norcow_update_bytes(const uint16_t key, const uint16_t offset, const uint8_t *data, const uint16_t len); secbool norcow_update_bytes(const uint16_t key, const uint16_t offset,
const uint8_t *data, const uint16_t len);
/* /*
* Complete storage version upgrade * Complete storage version upgrade

View File

@ -19,15 +19,15 @@
#include <string.h> #include <string.h>
#include "common.h"
#include "norcow.h"
#include "storage.h"
#include "pbkdf2.h"
#include "sha2.h"
#include "hmac.h"
#include "rand.h"
#include "memzero.h"
#include "chacha20poly1305/rfc7539.h" #include "chacha20poly1305/rfc7539.h"
#include "common.h"
#include "hmac.h"
#include "memzero.h"
#include "norcow.h"
#include "pbkdf2.h"
#include "rand.h"
#include "sha2.h"
#include "storage.h"
#define LOW_MASK 0x55555555 #define LOW_MASK 0x55555555
@ -37,7 +37,8 @@
// Norcow storage key of the PIN entry log and PIN success log. // Norcow storage key of the PIN entry log and PIN success log.
#define PIN_LOGS_KEY ((APP_STORAGE << 8) | 0x01) #define PIN_LOGS_KEY ((APP_STORAGE << 8) | 0x01)
// Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code entry. // Norcow storage key of the combined salt, EDEK, ESAK and PIN verification code
// entry.
#define EDEK_PVC_KEY ((APP_STORAGE << 8) | 0x02) #define EDEK_PVC_KEY ((APP_STORAGE << 8) | 0x02)
// Norcow storage key of the PIN set flag. // Norcow storage key of the PIN set flag.
@ -53,7 +54,8 @@
#define PIN_EMPTY 1 #define PIN_EMPTY 1
// Maximum number of failed unlock attempts. // Maximum number of failed unlock attempts.
// NOTE: The PIN counter logic relies on this constant being less than or equal to 16. // NOTE: The PIN counter logic relies on this constant being less than or equal
// to 16.
#define PIN_MAX_TRIES 16 #define PIN_MAX_TRIES 16
// The total number of iterations to use in PBKDF2. // The total number of iterations to use in PBKDF2.
@ -90,7 +92,8 @@
// The length of the storage authentication key in bytes. // The length of the storage authentication key in bytes.
#define SAK_SIZE 16 #define SAK_SIZE 16
// The combined length of the data encryption key and the storage authentication key in bytes. // The combined length of the data encryption key and the storage authentication
// key in bytes.
#define KEYS_SIZE (DEK_SIZE + SAK_SIZE) #define KEYS_SIZE (DEK_SIZE + SAK_SIZE)
// The length of the PIN verification code in bytes. // The length of the PIN verification code in bytes.
@ -115,9 +118,9 @@
#define GUARD_KEY_MODULUS 6311 #define GUARD_KEY_MODULUS 6311
#define GUARD_KEY_REMAINDER 15 #define GUARD_KEY_REMAINDER 15
const char* const VERIFYING_PIN_MSG = "Verifying PIN"; const char *const VERIFYING_PIN_MSG = "Verifying PIN";
const char* const PROCESSING_MSG = "Processing"; const char *const PROCESSING_MSG = "Processing";
const char* const STARTING_MSG = "Starting up"; const char *const STARTING_MSG = "Starting up";
static secbool initialized = secfalse; static secbool initialized = secfalse;
static secbool unlocked = secfalse; static secbool unlocked = secfalse;
@ -134,16 +137,19 @@ static uint32_t norcow_active_version = 0;
static const uint8_t TRUE_BYTE = 0x01; static const uint8_t TRUE_BYTE = 0x01;
static const uint8_t FALSE_BYTE = 0x00; static const uint8_t FALSE_BYTE = 0x00;
static void __handle_fault(const char *msg, const char *file, int line, const char *func); static void __handle_fault(const char *msg, const char *file, int line,
const char *func);
#define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__)) #define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__))
static secbool storage_upgrade(void); static secbool storage_upgrade(void);
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len); static secbool storage_set_encrypted(const uint16_t key, const void *val,
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len); const uint16_t len);
static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
const uint16_t max_len, uint16_t *len);
static secbool secequal(const void* ptr1, const void* ptr2, size_t n) { static secbool secequal(const void *ptr1, const void *ptr2, size_t n) {
const uint8_t* p1 = ptr1; const uint8_t *p1 = ptr1;
const uint8_t* p2 = ptr2; const uint8_t *p2 = ptr2;
uint8_t diff = 0; uint8_t diff = 0;
size_t i; size_t i;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
@ -160,7 +166,8 @@ static secbool secequal(const void* ptr1, const void* ptr2, size_t n) {
return diff ? secfalse : sectrue; return diff ? secfalse : sectrue;
} }
static secbool secequal32(const uint32_t* ptr1, const uint32_t* ptr2, size_t n) { static secbool secequal32(const uint32_t *ptr1, const uint32_t *ptr2,
size_t n) {
uint32_t diff = 0; uint32_t diff = 0;
size_t i; size_t i;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
@ -189,7 +196,8 @@ static secbool is_protected(uint16_t key) {
static secbool auth_init(void) { static secbool auth_init(void) {
uint8_t tag[SHA256_DIGEST_LENGTH]; uint8_t tag[SHA256_DIGEST_LENGTH];
memzero(authentication_sum, sizeof(authentication_sum)); memzero(authentication_sum, sizeof(authentication_sum));
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum, sizeof(authentication_sum), tag); hmac_sha256(cached_sak, SAK_SIZE, authentication_sum,
sizeof(authentication_sum), tag);
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE); return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
} }
@ -202,16 +210,18 @@ static secbool auth_update(uint16_t key) {
} }
uint8_t tag[SHA256_DIGEST_LENGTH]; uint8_t tag[SHA256_DIGEST_LENGTH];
hmac_sha256(cached_sak, SAK_SIZE, (uint8_t*)&key, sizeof(key), tag); hmac_sha256(cached_sak, SAK_SIZE, (uint8_t *)&key, sizeof(key), tag);
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH; i++) { for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
authentication_sum[i] ^= tag[i]; authentication_sum[i] ^= tag[i];
} }
hmac_sha256(cached_sak, SAK_SIZE, authentication_sum, sizeof(authentication_sum), tag); hmac_sha256(cached_sak, SAK_SIZE, authentication_sum,
sizeof(authentication_sum), tag);
return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE); return norcow_set(STORAGE_TAG_KEY, tag, STORAGE_TAG_SIZE);
} }
/* /*
* A secure version of norcow_set(), which updates the storage authentication tag. * A secure version of norcow_set(), which updates the storage authentication
* tag.
*/ */
static secbool auth_set(uint16_t key, const void *val, uint16_t len) { static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
secbool found; secbool found;
@ -226,13 +236,13 @@ static secbool auth_set(uint16_t key, const void *val, uint16_t len) {
} }
/* /*
* A secure version of norcow_get(), which checks the storage authentication tag. * A secure version of norcow_get(), which checks the storage authentication
* tag.
*/ */
static secbool auth_get(uint16_t key, const void **val, uint16_t *len) static secbool auth_get(uint16_t key, const void **val, uint16_t *len) {
{
*val = NULL; *val = NULL;
*len = 0; *len = 0;
uint32_t sum[SHA256_DIGEST_LENGTH/sizeof(uint32_t)] = {0}; uint32_t sum[SHA256_DIGEST_LENGTH / sizeof(uint32_t)] = {0};
// Prepare inner and outer digest. // Prepare inner and outer digest.
uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)]; uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
@ -269,10 +279,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
} }
continue; continue;
} }
g[0] = (((uint32_t)k & 0xff) << 24) | (((uint32_t)k & 0xff00) << 8) | 0x8000; // Add SHA message padding. g[0] = (((uint32_t)k & 0xff) << 24) | (((uint32_t)k & 0xff00) << 8) |
0x8000; // Add SHA message padding.
sha256_Transform(idig, g, h); sha256_Transform(idig, g, h);
sha256_Transform(odig, h, h); sha256_Transform(odig, h, h);
for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) { for (uint32_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
sum[i] ^= h[i]; sum[i] ^= h[i];
} }
} }
@ -285,11 +296,11 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
memzero(idig, sizeof(idig)); memzero(idig, sizeof(idig));
// Cache the authentication sum. // Cache the authentication sum.
for (size_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) { for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
#if BYTE_ORDER == LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
REVERSE32(sum[i], ((uint32_t*)authentication_sum)[i]); REVERSE32(sum[i], ((uint32_t *)authentication_sum)[i]);
#else #else
((uint32_t*)authentication_sum)[i] = sum[i]; ((uint32_t *)authentication_sum)[i] = sum[i];
#endif #endif
} }
@ -300,11 +311,12 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
// Check storage authentication tag. // Check storage authentication tag.
#if BYTE_ORDER == LITTLE_ENDIAN #if BYTE_ORDER == LITTLE_ENDIAN
for (size_t i = 0; i < SHA256_DIGEST_LENGTH/sizeof(uint32_t); i++) { for (size_t i = 0; i < SHA256_DIGEST_LENGTH / sizeof(uint32_t); i++) {
REVERSE32(h[i], h[i]); REVERSE32(h[i], h[i]);
} }
#endif #endif
if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE || sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) { if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE ||
sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) {
handle_fault("storage tag check"); handle_fault("storage tag check");
} }
@ -319,10 +331,10 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
} }
/* /*
* Generates a delay of random length. Use this to protect sensitive code against fault injection. * Generates a delay of random length. Use this to protect sensitive code
* against fault injection.
*/ */
static void wait_random(void) static void wait_random(void) {
{
#ifndef TREZOR_STORAGE_TEST #ifndef TREZOR_STORAGE_TEST
int wait = random32() & 0xff; int wait = random32() & 0xff;
volatile int i = 0; volatile int i = 0;
@ -342,8 +354,9 @@ static void wait_random(void)
#endif #endif
} }
static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA256_DIGEST_LENGTH], uint8_t keiv[SHA256_DIGEST_LENGTH]) static void derive_kek(uint32_t pin, const uint8_t *random_salt,
{ uint8_t kek[SHA256_DIGEST_LENGTH],
uint8_t keiv[SHA256_DIGEST_LENGTH]) {
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
REVERSE32(pin, pin); REVERSE32(pin, pin);
#endif #endif
@ -358,21 +371,25 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
} }
PBKDF2_HMAC_SHA256_CTX ctx; PBKDF2_HMAC_SHA256_CTX ctx;
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*) &pin, sizeof(pin), salt, sizeof(salt), 1); pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)&pin, sizeof(pin), salt,
sizeof(salt), 1);
for (int i = 1; i <= 5; i++) { for (int i = 1; i <= 5; i++) {
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10); pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
if (ui_callback && ui_message) { if (ui_callback && ui_message) {
progress = ((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total; progress =
((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message); ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
} }
} }
pbkdf2_hmac_sha256_Final(&ctx, kek); pbkdf2_hmac_sha256_Final(&ctx, kek);
pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t*) &pin, sizeof(pin), salt, sizeof(salt), 2); pbkdf2_hmac_sha256_Init(&ctx, (const uint8_t *)&pin, sizeof(pin), salt,
sizeof(salt), 2);
for (int i = 6; i <= 10; i++) { for (int i = 6; i <= 10; i++) {
pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10); pbkdf2_hmac_sha256_Update(&ctx, PIN_ITER_COUNT / 10);
if (ui_callback && ui_message) { if (ui_callback && ui_message) {
progress = ((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total; progress =
((ui_total - ui_rem) * 1000 + i * DERIVE_SECS * 100) / ui_total;
ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message); ui_callback(ui_rem - i * DERIVE_SECS / 10, progress, ui_message);
} }
} }
@ -384,8 +401,7 @@ static void derive_kek(uint32_t pin, const uint8_t *random_salt, uint8_t kek[SHA
memzero(&salt, sizeof(salt)); memzero(&salt, sizeof(salt));
} }
static secbool set_pin(uint32_t pin) static secbool set_pin(uint32_t pin) {
{
uint8_t buffer[RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE]; uint8_t buffer[RANDOM_SALT_SIZE + KEYS_SIZE + POLY1305_TAG_SIZE];
uint8_t *salt = buffer; uint8_t *salt = buffer;
uint8_t *ekeys = buffer + RANDOM_SALT_SIZE; uint8_t *ekeys = buffer + RANDOM_SALT_SIZE;
@ -402,11 +418,11 @@ static secbool set_pin(uint32_t pin)
chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE); chacha20poly1305_encrypt(&ctx, cached_keys, ekeys, KEYS_SIZE);
rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc); rfc7539_finish(&ctx, 0, KEYS_SIZE, pvc);
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
secbool ret = norcow_set(EDEK_PVC_KEY, buffer, RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE); secbool ret =
norcow_set(EDEK_PVC_KEY, buffer, RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE);
memzero(buffer, sizeof(buffer)); memzero(buffer, sizeof(buffer));
if (ret == sectrue) if (ret == sectrue) {
{
if (pin == PIN_EMPTY) { if (pin == PIN_EMPTY) {
ret = norcow_set(PIN_NOT_SET_KEY, &TRUE_BYTE, sizeof(TRUE_BYTE)); ret = norcow_set(PIN_NOT_SET_KEY, &TRUE_BYTE, sizeof(TRUE_BYTE));
} else { } else {
@ -418,8 +434,7 @@ static secbool set_pin(uint32_t pin)
return ret; return ret;
} }
static secbool check_guard_key(const uint32_t guard_key) static secbool check_guard_key(const uint32_t guard_key) {
{
if (guard_key % GUARD_KEY_MODULUS != GUARD_KEY_REMAINDER) { if (guard_key % GUARD_KEY_MODULUS != GUARD_KEY_REMAINDER) {
return secfalse; return secfalse;
} }
@ -431,7 +446,8 @@ static secbool check_guard_key(const uint32_t guard_key)
return secfalse; return secfalse;
} }
// Check that the guard_key does not contain a run of 5 (or more) zeros or ones. // Check that the guard_key does not contain a run of 5 (or more) zeros or
// ones.
uint32_t zero_runs = ~guard_key; uint32_t zero_runs = ~guard_key;
zero_runs = zero_runs & (zero_runs >> 2); zero_runs = zero_runs & (zero_runs >> 2);
zero_runs = zero_runs & (zero_runs >> 1); zero_runs = zero_runs & (zero_runs >> 1);
@ -449,35 +465,37 @@ static secbool check_guard_key(const uint32_t guard_key)
return sectrue; return sectrue;
} }
static uint32_t generate_guard_key(void) static uint32_t generate_guard_key(void) {
{
uint32_t guard_key = 0; uint32_t guard_key = 0;
do { do {
guard_key = random_uniform((UINT32_MAX/GUARD_KEY_MODULUS) + 1) * GUARD_KEY_MODULUS + GUARD_KEY_REMAINDER; guard_key = random_uniform((UINT32_MAX / GUARD_KEY_MODULUS) + 1) *
GUARD_KEY_MODULUS +
GUARD_KEY_REMAINDER;
} while (sectrue != check_guard_key(guard_key)); } while (sectrue != check_guard_key(guard_key));
return guard_key; return guard_key;
} }
static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask, uint32_t *guard) static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask,
{ uint32_t *guard) {
if (sectrue != check_guard_key(guard_key)) { if (sectrue != check_guard_key(guard_key)) {
handle_fault("guard key check"); handle_fault("guard key check");
return secfalse; return secfalse;
} }
*guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK); *guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK);
*guard = (((guard_key & LOW_MASK) << 1) & guard_key) | (((~guard_key) & LOW_MASK) & (guard_key >> 1)); *guard = (((guard_key & LOW_MASK) << 1) & guard_key) |
(((~guard_key) & LOW_MASK) & (guard_key >> 1));
return sectrue; return sectrue;
} }
static secbool pin_logs_init(uint32_t fails) static secbool pin_logs_init(uint32_t fails) {
{
if (fails >= PIN_MAX_TRIES) { if (fails >= PIN_MAX_TRIES) {
return secfalse; return secfalse;
} }
// The format of the PIN_LOGS_KEY entry is: // The format of the PIN_LOGS_KEY entry is:
// guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log (PIN_LOG_WORDS) // guard_key (1 word), pin_success_log (PIN_LOG_WORDS), pin_entry_log
uint32_t logs[GUARD_KEY_WORDS + 2*PIN_LOG_WORDS]; // (PIN_LOG_WORDS)
uint32_t logs[GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS];
logs[0] = generate_guard_key(); logs[0] = generate_guard_key();
@ -489,30 +507,34 @@ static secbool pin_logs_init(uint32_t fails)
} }
uint32_t unused = guard | ~guard_mask; uint32_t unused = guard | ~guard_mask;
for (size_t i = 0; i < 2*PIN_LOG_WORDS; ++i) { for (size_t i = 0; i < 2 * PIN_LOG_WORDS; ++i) {
logs[GUARD_KEY_WORDS + i] = unused; logs[GUARD_KEY_WORDS + i] = unused;
} }
// Set the first word of the PIN entry log to indicate the requested number of fails. // Set the first word of the PIN entry log to indicate the requested number of
logs[GUARD_KEY_WORDS + PIN_LOG_WORDS] = ((((uint32_t)0xFFFFFFFF) >> (2*fails)) & ~guard_mask) | guard; // fails.
logs[GUARD_KEY_WORDS + PIN_LOG_WORDS] =
((((uint32_t)0xFFFFFFFF) >> (2 * fails)) & ~guard_mask) | guard;
return norcow_set(PIN_LOGS_KEY, logs, sizeof(logs)); return norcow_set(PIN_LOGS_KEY, logs, sizeof(logs));
} }
/* /*
* Initializes the values of VERSION_KEY, EDEK_PVC_KEY, PIN_NOT_SET_KEY and PIN_LOGS_KEY using an empty PIN. * Initializes the values of VERSION_KEY, EDEK_PVC_KEY, PIN_NOT_SET_KEY and
* This function should be called to initialize freshly wiped storage. * PIN_LOGS_KEY using an empty PIN. This function should be called to initialize
* freshly wiped storage.
*/ */
static void init_wiped_storage(void) static void init_wiped_storage(void) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
// We cannot initialize the storage contents if the hardware_salt is not set. // We cannot initialize the storage contents if the hardware_salt is not
// set.
return; return;
} }
random_buffer(cached_keys, sizeof(cached_keys)); random_buffer(cached_keys, sizeof(cached_keys));
uint32_t version = NORCOW_VERSION; uint32_t version = NORCOW_VERSION;
ensure(auth_init(), "set_storage_auth_tag failed"); ensure(auth_init(), "set_storage_auth_tag failed");
ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)), "set_storage_version failed"); ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)),
"set_storage_version failed");
ensure(pin_logs_init(0), "init_pin_logs failed"); ensure(pin_logs_init(0), "init_pin_logs failed");
ui_total = DERIVE_SECS; ui_total = DERIVE_SECS;
ui_rem = ui_total; ui_rem = ui_total;
@ -523,8 +545,8 @@ static void init_wiped_storage(void)
} }
} }
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint16_t salt_len) void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
{ const uint16_t salt_len) {
initialized = secfalse; initialized = secfalse;
unlocked = secfalse; unlocked = secfalse;
norcow_init(&norcow_active_version); norcow_init(&norcow_active_version);
@ -549,31 +571,34 @@ void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint
memzero(cached_keys, sizeof(cached_keys)); memzero(cached_keys, sizeof(cached_keys));
} }
static secbool pin_fails_reset(void) static secbool pin_fails_reset(void) {
{
const void *logs = NULL; const void *logs = NULL;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) { if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
return secfalse; return secfalse;
} }
uint32_t guard_mask; uint32_t guard_mask;
uint32_t guard; uint32_t guard;
wait_random(); wait_random();
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) { if (sectrue !=
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
return secfalse; return secfalse;
} }
uint32_t unused = guard | ~guard_mask; uint32_t unused = guard | ~guard_mask;
const uint32_t *success_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS; const uint32_t *success_log = ((const uint32_t *)logs) + GUARD_KEY_WORDS;
const uint32_t *entry_log = success_log + PIN_LOG_WORDS; const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) { for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
if (entry_log[i] == unused) { if (entry_log[i] == unused) {
return sectrue; return sectrue;
} }
if (success_log[i] != guard) { if (success_log[i] != guard) {
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS), entry_log[i])) { if (sectrue != norcow_update_word(
PIN_LOGS_KEY, sizeof(uint32_t) * (i + GUARD_KEY_WORDS),
entry_log[i])) {
return secfalse; return secfalse;
} }
} }
@ -581,8 +606,7 @@ static secbool pin_fails_reset(void)
return pin_logs_init(0); return pin_logs_init(0);
} }
secbool storage_pin_fails_increase(void) secbool storage_pin_fails_increase(void) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return secfalse; return secfalse;
} }
@ -591,7 +615,8 @@ secbool storage_pin_fails_increase(void)
uint16_t len = 0; uint16_t len = 0;
wait_random(); wait_random();
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) { if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
handle_fault("no PIN logs"); handle_fault("no PIN logs");
return secfalse; return secfalse;
} }
@ -599,12 +624,14 @@ secbool storage_pin_fails_increase(void)
uint32_t guard_mask; uint32_t guard_mask;
uint32_t guard; uint32_t guard;
wait_random(); wait_random();
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) { if (sectrue !=
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
handle_fault("guard key expansion"); handle_fault("guard key expansion");
return secfalse; return secfalse;
} }
const uint32_t *entry_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS + PIN_LOG_WORDS; const uint32_t *entry_log =
((const uint32_t *)logs) + GUARD_KEY_WORDS + PIN_LOG_WORDS;
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) { for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
wait_random(); wait_random();
if ((entry_log[i] & guard_mask) != guard) { if ((entry_log[i] & guard_mask) != guard) {
@ -618,20 +645,22 @@ secbool storage_pin_fails_increase(void)
word = (word >> 2) | (word >> 1); word = (word >> 2) | (word >> 1);
wait_random(); wait_random();
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS + PIN_LOG_WORDS), (word & ~guard_mask) | guard)) { if (sectrue !=
norcow_update_word(
PIN_LOGS_KEY,
sizeof(uint32_t) * (i + GUARD_KEY_WORDS + PIN_LOG_WORDS),
(word & ~guard_mask) | guard)) {
handle_fault("PIN logs update"); handle_fault("PIN logs update");
return secfalse; return secfalse;
} }
return sectrue; return sectrue;
} }
} }
handle_fault("PIN log exhausted"); handle_fault("PIN log exhausted");
return secfalse; return secfalse;
} }
static uint32_t hamming_weight(uint32_t value) static uint32_t hamming_weight(uint32_t value) {
{
value = value - ((value >> 1) & 0x55555555); value = value - ((value >> 1) & 0x55555555);
value = (value & 0x33333333) + ((value >> 2) & 0x33333333); value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
value = (value + (value >> 4)) & 0x0F0F0F0F; value = (value + (value >> 4)) & 0x0F0F0F0F;
@ -640,14 +669,14 @@ static uint32_t hamming_weight(uint32_t value)
return value & 0x3F; return value & 0x3F;
} }
static secbool pin_get_fails(uint32_t *ctr) static secbool pin_get_fails(uint32_t *ctr) {
{
*ctr = PIN_MAX_TRIES; *ctr = PIN_MAX_TRIES;
const void *logs = NULL; const void *logs = NULL;
uint16_t len = 0; uint16_t len = 0;
wait_random(); wait_random();
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) { if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) ||
len != WORD_SIZE * (GUARD_KEY_WORDS + 2 * PIN_LOG_WORDS)) {
handle_fault("no PIN logs"); handle_fault("no PIN logs");
return secfalse; return secfalse;
} }
@ -655,18 +684,21 @@ static secbool pin_get_fails(uint32_t *ctr)
uint32_t guard_mask; uint32_t guard_mask;
uint32_t guard; uint32_t guard;
wait_random(); wait_random();
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) { if (sectrue !=
expand_guard_key(*(const uint32_t *)logs, &guard_mask, &guard)) {
handle_fault("guard key expansion"); handle_fault("guard key expansion");
return secfalse; return secfalse;
} }
const uint32_t unused = guard | ~guard_mask; const uint32_t unused = guard | ~guard_mask;
const uint32_t *success_log = ((const uint32_t*)logs) + GUARD_KEY_WORDS; const uint32_t *success_log = ((const uint32_t *)logs) + GUARD_KEY_WORDS;
const uint32_t *entry_log = success_log + PIN_LOG_WORDS; const uint32_t *entry_log = success_log + PIN_LOG_WORDS;
volatile int current = -1; volatile int current = -1;
volatile size_t i; volatile size_t i;
for (i = 0; i < PIN_LOG_WORDS; ++i) { for (i = 0; i < PIN_LOG_WORDS; ++i) {
if ((entry_log[i] & guard_mask) != guard || (success_log[i] & guard_mask) != guard || (entry_log[i] & success_log[i]) != entry_log[i]) { if ((entry_log[i] & guard_mask) != guard ||
(success_log[i] & guard_mask) != guard ||
(entry_log[i] & success_log[i]) != entry_log[i]) {
handle_fault("PIN logs format check"); handle_fault("PIN logs format check");
return secfalse; return secfalse;
} }
@ -688,10 +720,11 @@ static secbool pin_get_fails(uint32_t *ctr)
return secfalse; return secfalse;
} }
// Strip the guard bits from the current entry word and duplicate each data bit. // Strip the guard bits from the current entry word and duplicate each data
// bit.
wait_random(); wait_random();
uint32_t word = entry_log[current] & ~guard_mask; uint32_t word = entry_log[current] & ~guard_mask;
word = ((word >> 1) | word ) & LOW_MASK; word = ((word >> 1) | word) & LOW_MASK;
word = word | (word << 1); word = word | (word << 1);
// Verify that the entry word has form 0*1*. // Verify that the entry word has form 0*1*.
if ((word & (word + 1)) != 0) { if ((word & (word + 1)) != 0) {
@ -705,12 +738,12 @@ static secbool pin_get_fails(uint32_t *ctr)
// Count the number of set bits in the two current words of the success log. // Count the number of set bits in the two current words of the success log.
wait_random(); wait_random();
*ctr = hamming_weight(success_log[current-1] ^ entry_log[current-1]) + hamming_weight(success_log[current] ^ entry_log[current]); *ctr = hamming_weight(success_log[current - 1] ^ entry_log[current - 1]) +
hamming_weight(success_log[current] ^ entry_log[current]);
return sectrue; return sectrue;
} }
secbool storage_is_unlocked(void) secbool storage_is_unlocked(void) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return secfalse; return secfalse;
} }
@ -718,24 +751,25 @@ secbool storage_is_unlocked(void)
return unlocked; return unlocked;
} }
void storage_lock(void) void storage_lock(void) {
{
unlocked = secfalse; unlocked = secfalse;
memzero(cached_keys, sizeof(cached_keys)); memzero(cached_keys, sizeof(cached_keys));
memzero(authentication_sum, sizeof(authentication_sum)); memzero(authentication_sum, sizeof(authentication_sum));
} }
static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
{
const void *buffer = NULL; const void *buffer = NULL;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) { if (sectrue != initialized ||
sectrue != norcow_get(EDEK_PVC_KEY, &buffer, &len) ||
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
handle_fault("no EDEK"); handle_fault("no EDEK");
return secfalse; return secfalse;
} }
const uint8_t *ekeys = (const uint8_t*) buffer + RANDOM_SALT_SIZE; const uint8_t *ekeys = (const uint8_t *)buffer + RANDOM_SALT_SIZE;
const uint32_t *pvc = (const uint32_t*) buffer + (RANDOM_SALT_SIZE + KEYS_SIZE)/sizeof(uint32_t); const uint32_t *pvc = (const uint32_t *)buffer +
(RANDOM_SALT_SIZE + KEYS_SIZE) / sizeof(uint32_t);
_Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned"); _Static_assert(((RANDOM_SALT_SIZE + KEYS_SIZE) & 3) == 0, "PVC unaligned");
_Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned"); _Static_assert((PVC_SIZE & 3) == 0, "PVC size unaligned");
@ -743,13 +777,15 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t)))); uint8_t tag[POLY1305_TAG_SIZE] __attribute__((aligned(sizeof(uint32_t))));
chacha20poly1305_ctx ctx; chacha20poly1305_ctx ctx;
// Decrypt the data encryption key and the storage authentication key and check the PIN verification code. // Decrypt the data encryption key and the storage authentication key and
// check the PIN verification code.
rfc7539_init(&ctx, kek, keiv); rfc7539_init(&ctx, kek, keiv);
chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE); chacha20poly1305_decrypt(&ctx, ekeys, keys, KEYS_SIZE);
rfc7539_finish(&ctx, 0, KEYS_SIZE, tag); rfc7539_finish(&ctx, 0, KEYS_SIZE, tag);
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
wait_random(); wait_random();
if (secequal32((const uint32_t*) tag, pvc, PVC_SIZE/sizeof(uint32_t)) != sectrue) { if (secequal32((const uint32_t *)tag, pvc, PVC_SIZE / sizeof(uint32_t)) !=
sectrue) {
memzero(keys, sizeof(keys)); memzero(keys, sizeof(keys));
memzero(tag, sizeof(tag)); memzero(tag, sizeof(tag));
return secfalse; return secfalse;
@ -759,9 +795,12 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
memzero(tag, sizeof(tag)); memzero(tag, sizeof(tag));
// Check that the authenticated version number matches the norcow version. // Check that the authenticated version number matches the norcow version.
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the authentication_sum. // NOTE: storage_get_encrypted() calls auth_get(), which initializes the
// authentication_sum.
uint32_t version; uint32_t version;
if (sectrue != storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) || len != sizeof(version) || version != norcow_active_version) { if (sectrue !=
storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) ||
len != sizeof(version) || version != norcow_active_version) {
handle_fault("storage version check"); handle_fault("storage version check");
return secfalse; return secfalse;
} }
@ -769,8 +808,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv)
return sectrue; return sectrue;
} }
static secbool unlock(uint32_t pin) static secbool unlock(uint32_t pin) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return secfalse; return secfalse;
} }
@ -786,7 +824,8 @@ static secbool unlock(uint32_t pin)
wait_random(); wait_random();
if (ctr >= PIN_MAX_TRIES) { if (ctr >= PIN_MAX_TRIES) {
storage_wipe(); storage_wipe();
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL); error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.",
NULL);
return secfalse; return secfalse;
} }
@ -810,17 +849,20 @@ static secbool unlock(uint32_t pin)
} }
} }
// Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and KEIV from the PIN. // Read the random salt from EDEK_PVC_KEY and use it to derive the KEK and
// KEIV from the PIN.
const void *salt = NULL; const void *salt = NULL;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != initialized || sectrue != norcow_get(EDEK_PVC_KEY, &salt, &len) || len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) { if (sectrue != initialized ||
sectrue != norcow_get(EDEK_PVC_KEY, &salt, &len) ||
len != RANDOM_SALT_SIZE + KEYS_SIZE + PVC_SIZE) {
memzero(&pin, sizeof(pin)); memzero(&pin, sizeof(pin));
handle_fault("no EDEK"); handle_fault("no EDEK");
return secfalse; return secfalse;
} }
uint8_t kek[SHA256_DIGEST_LENGTH]; uint8_t kek[SHA256_DIGEST_LENGTH];
uint8_t keiv[SHA256_DIGEST_LENGTH]; uint8_t keiv[SHA256_DIGEST_LENGTH];
derive_kek(pin, (const uint8_t*) salt, kek, keiv); derive_kek(pin, (const uint8_t *)salt, kek, keiv);
memzero(&pin, sizeof(pin)); memzero(&pin, sizeof(pin));
// First, we increase PIN fail counter in storage, even before checking the // First, we increase PIN fail counter in storage, even before checking the
@ -843,7 +885,8 @@ static secbool unlock(uint32_t pin)
wait_random(); wait_random();
if (ctr + 1 >= PIN_MAX_TRIES) { if (ctr + 1 >= PIN_MAX_TRIES) {
storage_wipe(); storage_wipe();
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL); error_shutdown("Too many wrong PIN", "attempts. Storage has",
"been wiped.", NULL);
} }
return secfalse; return secfalse;
} }
@ -856,8 +899,7 @@ static secbool unlock(uint32_t pin)
return pin_fails_reset(); return pin_fails_reset();
} }
secbool storage_unlock(uint32_t pin) secbool storage_unlock(uint32_t pin) {
{
ui_total = DERIVE_SECS; ui_total = DERIVE_SECS;
ui_rem = ui_total; ui_rem = ui_total;
if (pin == PIN_EMPTY) { if (pin == PIN_EMPTY) {
@ -877,8 +919,8 @@ secbool storage_unlock(uint32_t pin)
* If val_dest is not NULL and max_len >= len, then the data is decrypted * If val_dest is not NULL and max_len >= len, then the data is decrypted
* to val_dest using cached_dek as the decryption key. * to val_dest using cached_dek as the decryption key.
*/ */
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len) static secbool storage_get_encrypted(const uint16_t key, void *val_dest,
{ const uint16_t max_len, uint16_t *len) {
const void *val_stored = NULL; const void *val_stored = NULL;
if (sectrue != auth_get(key, &val_stored, len)) { if (sectrue != auth_get(key, &val_stored, len)) {
@ -899,14 +941,15 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
return secfalse; return secfalse;
} }
const uint8_t *iv = (const uint8_t*) val_stored; const uint8_t *iv = (const uint8_t *)val_stored;
const uint8_t *tag_stored = (const uint8_t*) val_stored + CHACHA20_IV_SIZE; const uint8_t *tag_stored = (const uint8_t *)val_stored + CHACHA20_IV_SIZE;
const uint8_t *ciphertext = (const uint8_t*) val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE; const uint8_t *ciphertext =
(const uint8_t *)val_stored + CHACHA20_IV_SIZE + POLY1305_TAG_SIZE;
uint8_t tag_computed[POLY1305_TAG_SIZE]; uint8_t tag_computed[POLY1305_TAG_SIZE];
chacha20poly1305_ctx ctx; chacha20poly1305_ctx ctx;
rfc7539_init(&ctx, cached_dek, iv); rfc7539_init(&ctx, cached_dek, iv);
rfc7539_auth(&ctx, (const uint8_t*)&key, sizeof(key)); rfc7539_auth(&ctx, (const uint8_t *)&key, sizeof(key));
chacha20poly1305_decrypt(&ctx, ciphertext, (uint8_t*) val_dest, *len); chacha20poly1305_decrypt(&ctx, ciphertext, (uint8_t *)val_dest, *len);
rfc7539_finish(&ctx, sizeof(key), *len, tag_computed); rfc7539_finish(&ctx, sizeof(key), *len, tag_computed);
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
@ -926,15 +969,16 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
* Finds the data stored under key and writes its length to len. If val_dest is * Finds the data stored under key and writes its length to len. If val_dest is
* not NULL and max_len >= len, then the data is copied to val_dest. * not NULL and max_len >= len, then the data is copied to val_dest.
*/ */
secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len) secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
{ uint16_t *len) {
const uint8_t app = key >> 8; const uint8_t app = key >> 8;
// APP == 0 is reserved for PIN related values // APP == 0 is reserved for PIN related values
if (sectrue != initialized || app == APP_STORAGE) { if (sectrue != initialized || app == APP_STORAGE) {
return secfalse; return secfalse;
} }
// If the top bit of APP is set, then the value is not encrypted and can be read from a locked device. // If the top bit of APP is set, then the value is not encrypted and can be
// read from a locked device.
secbool ret = secfalse; secbool ret = secfalse;
if ((app & FLAG_PUBLIC) != 0) { if ((app & FLAG_PUBLIC) != 0) {
const void *val_stored = NULL; const void *val_stored = NULL;
@ -960,16 +1004,18 @@ secbool storage_get(const uint16_t key, void *val_dest, const uint16_t max_len,
} }
/* /*
* Encrypts the data at val using cached_dek as the encryption key and stores the ciphertext under key. * Encrypts the data at val using cached_dek as the encryption key and stores
* the ciphertext under key.
*/ */
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len) static secbool storage_set_encrypted(const uint16_t key, const void *val,
{ const uint16_t len) {
if (len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE) { if (len > UINT16_MAX - CHACHA20_IV_SIZE - POLY1305_TAG_SIZE) {
return secfalse; return secfalse;
} }
// Preallocate space on the flash storage. // Preallocate space on the flash storage.
if (sectrue != auth_set(key, NULL, CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len)) { if (sectrue !=
auth_set(key, NULL, CHACHA20_IV_SIZE + POLY1305_TAG_SIZE + len)) {
return secfalse; return secfalse;
} }
@ -985,11 +1031,14 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
// Encrypt all blocks except for the last one. // Encrypt all blocks except for the last one.
chacha20poly1305_ctx ctx; chacha20poly1305_ctx ctx;
rfc7539_init(&ctx, cached_dek, buffer); rfc7539_init(&ctx, cached_dek, buffer);
rfc7539_auth(&ctx, (const uint8_t*)&key, sizeof(key)); rfc7539_auth(&ctx, (const uint8_t *)&key, sizeof(key));
size_t i; size_t i;
for (i = 0; i + CHACHA20_BLOCK_SIZE < len; i += CHACHA20_BLOCK_SIZE, offset += CHACHA20_BLOCK_SIZE) { for (i = 0; i + CHACHA20_BLOCK_SIZE < len;
chacha20poly1305_encrypt(&ctx, ((const uint8_t*) val) + i, buffer, CHACHA20_BLOCK_SIZE); i += CHACHA20_BLOCK_SIZE, offset += CHACHA20_BLOCK_SIZE) {
if (sectrue != norcow_update_bytes(key, offset, buffer, CHACHA20_BLOCK_SIZE)) { chacha20poly1305_encrypt(&ctx, ((const uint8_t *)val) + i, buffer,
CHACHA20_BLOCK_SIZE);
if (sectrue !=
norcow_update_bytes(key, offset, buffer, CHACHA20_BLOCK_SIZE)) {
memzero(&ctx, sizeof(ctx)); memzero(&ctx, sizeof(ctx));
memzero(buffer, sizeof(buffer)); memzero(buffer, sizeof(buffer));
return secfalse; return secfalse;
@ -997,7 +1046,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
} }
// Encrypt final block and compute message authentication tag. // Encrypt final block and compute message authentication tag.
chacha20poly1305_encrypt(&ctx, ((const uint8_t*) val) + i, buffer, len - i); chacha20poly1305_encrypt(&ctx, ((const uint8_t *)val) + i, buffer, len - i);
secbool ret = norcow_update_bytes(key, offset, buffer, len - i); secbool ret = norcow_update_bytes(key, offset, buffer, len - i);
if (sectrue == ret) { if (sectrue == ret) {
rfc7539_finish(&ctx, sizeof(key), len, buffer); rfc7539_finish(&ctx, sizeof(key), len, buffer);
@ -1008,8 +1057,7 @@ static secbool storage_set_encrypted(const uint16_t key, const void *val, const
return ret; return ret;
} }
secbool storage_set(const uint16_t key, const void *val, const uint16_t len) secbool storage_set(const uint16_t key, const void *val, const uint16_t len) {
{
const uint8_t app = key >> 8; const uint8_t app = key >> 8;
// APP == 0 is reserved for PIN related values // APP == 0 is reserved for PIN related values
@ -1030,8 +1078,7 @@ secbool storage_set(const uint16_t key, const void *val, const uint16_t len)
return ret; return ret;
} }
secbool storage_delete(const uint16_t key) secbool storage_delete(const uint16_t key) {
{
const uint8_t app = key >> 8; const uint8_t app = key >> 8;
// APP == 0 is reserved for storage related values // APP == 0 is reserved for storage related values
@ -1050,8 +1097,7 @@ secbool storage_delete(const uint16_t key)
return ret; return ret;
} }
secbool storage_set_counter(const uint16_t key, const uint32_t count) secbool storage_set_counter(const uint16_t key, const uint32_t count) {
{
const uint8_t app = key >> 8; const uint8_t app = key >> 8;
if ((app & FLAG_PUBLIC) == 0) { if ((app & FLAG_PUBLIC) == 0) {
return secfalse; return secfalse;
@ -1065,11 +1111,11 @@ secbool storage_set_counter(const uint16_t key, const uint32_t count)
return storage_set(key, value, sizeof(value)); return storage_set(key, value, sizeof(value));
} }
secbool storage_next_counter(const uint16_t key, uint32_t *count) secbool storage_next_counter(const uint16_t key, uint32_t *count) {
{
const uint8_t app = key >> 8; const uint8_t app = key >> 8;
// APP == 0 is reserved for PIN related values // APP == 0 is reserved for PIN related values
if (sectrue != initialized || app == APP_STORAGE || (app & FLAG_PUBLIC) == 0) { if (sectrue != initialized || app == APP_STORAGE ||
(app & FLAG_PUBLIC) == 0) {
return secfalse; return secfalse;
} }
@ -1079,7 +1125,7 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
uint16_t len = 0; uint16_t len = 0;
const uint32_t *val_stored = NULL; const uint32_t *val_stored = NULL;
if (sectrue != norcow_get(key, (const void**)&val_stored, &len)) { if (sectrue != norcow_get(key, (const void **)&val_stored, &len)) {
*count = 0; *count = 0;
return storage_set_counter(key, 0); return storage_set_counter(key, 0);
} }
@ -1104,22 +1150,21 @@ secbool storage_next_counter(const uint16_t key, uint32_t *count)
} }
} }
secbool storage_has_pin(void) secbool storage_has_pin(void) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return secfalse; return secfalse;
} }
const void *val = NULL; const void *val = NULL;
uint16_t len; uint16_t len;
if (sectrue != norcow_get(PIN_NOT_SET_KEY, &val, &len) || (len > 0 && *(uint8_t*)val != FALSE_BYTE)) { if (sectrue != norcow_get(PIN_NOT_SET_KEY, &val, &len) ||
(len > 0 && *(uint8_t *)val != FALSE_BYTE)) {
return secfalse; return secfalse;
} }
return sectrue; return sectrue;
} }
uint32_t storage_get_pin_rem(void) uint32_t storage_get_pin_rem(void) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return 0; return 0;
} }
@ -1131,15 +1176,15 @@ uint32_t storage_get_pin_rem(void)
return PIN_MAX_TRIES - ctr; return PIN_MAX_TRIES - ctr;
} }
secbool storage_change_pin(uint32_t oldpin, uint32_t newpin) secbool storage_change_pin(uint32_t oldpin, uint32_t newpin) {
{
if (sectrue != initialized) { if (sectrue != initialized) {
return secfalse; return secfalse;
} }
ui_total = 2 * DERIVE_SECS; ui_total = 2 * DERIVE_SECS;
ui_rem = ui_total; ui_rem = ui_total;
ui_message = (oldpin != PIN_EMPTY && newpin == PIN_EMPTY) ? VERIFYING_PIN_MSG : PROCESSING_MSG; ui_message = (oldpin != PIN_EMPTY && newpin == PIN_EMPTY) ? VERIFYING_PIN_MSG
: PROCESSING_MSG;
if (sectrue != unlock(oldpin)) { if (sectrue != unlock(oldpin)) {
return secfalse; return secfalse;
@ -1150,8 +1195,7 @@ secbool storage_change_pin(uint32_t oldpin, uint32_t newpin)
return ret; return ret;
} }
void storage_wipe(void) void storage_wipe(void) {
{
norcow_wipe(); norcow_wipe();
norcow_active_version = NORCOW_VERSION; norcow_active_version = NORCOW_VERSION;
memzero(authentication_sum, sizeof(authentication_sum)); memzero(authentication_sum, sizeof(authentication_sum));
@ -1159,17 +1203,19 @@ void storage_wipe(void)
init_wiped_storage(); init_wiped_storage();
} }
static void __handle_fault(const char *msg, const char *file, int line, const char *func) static void __handle_fault(const char *msg, const char *file, int line,
{ const char *func) {
static secbool in_progress = secfalse; static secbool in_progress = secfalse;
// If fault handling is already in progress, then we are probably facing a fault injection attack, so wipe. // If fault handling is already in progress, then we are probably facing a
// fault injection attack, so wipe.
if (secfalse != in_progress) { if (secfalse != in_progress) {
storage_wipe(); storage_wipe();
__fatal_error("Fault detected", msg, file, line, func); __fatal_error("Fault detected", msg, file, line, func);
} }
// We use the PIN fail counter as a fault counter. Increment the counter, check that it was incremented and halt. // We use the PIN fail counter as a fault counter. Increment the counter,
// check that it was incremented and halt.
in_progress = sectrue; in_progress = sectrue;
uint32_t ctr; uint32_t ctr;
if (sectrue != pin_get_fails(&ctr)) { if (sectrue != pin_get_fails(&ctr)) {
@ -1190,10 +1236,10 @@ static void __handle_fault(const char *msg, const char *file, int line, const ch
} }
/* /*
* Reads the PIN fail counter in version 0 format. Returns the current number of failed PIN entries. * Reads the PIN fail counter in version 0 format. Returns the current number of
* failed PIN entries.
*/ */
static secbool v0_pin_get_fails(uint32_t *ctr) static secbool v0_pin_get_fails(uint32_t *ctr) {
{
const uint16_t V0_PIN_FAIL_KEY = 0x0001; const uint16_t V0_PIN_FAIL_KEY = 0x0001;
// The PIN_FAIL_KEY points to an area of words, initialized to // The PIN_FAIL_KEY points to an area of words, initialized to
// 0xffffffff (meaning no PIN failures). The first non-zero word // 0xffffffff (meaning no PIN failures). The first non-zero word
@ -1208,7 +1254,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
uint16_t len = 0; uint16_t len = 0;
if (secfalse != norcow_get(V0_PIN_FAIL_KEY, &val, &len)) { if (secfalse != norcow_get(V0_PIN_FAIL_KEY, &val, &len)) {
for (unsigned int i = 0; i < len / sizeof(uint32_t); i++) { for (unsigned int i = 0; i < len / sizeof(uint32_t); i++) {
uint32_t word = ((const uint32_t*)val)[i]; uint32_t word = ((const uint32_t *)val)[i];
if (word != 0) { if (word != 0) {
*ctr = hamming_weight(~word); *ctr = hamming_weight(~word);
return sectrue; return sectrue;
@ -1221,8 +1267,7 @@ static secbool v0_pin_get_fails(uint32_t *ctr)
return sectrue; return sectrue;
} }
static secbool storage_upgrade(void) static secbool storage_upgrade(void) {
{
const uint16_t V0_PIN_KEY = 0x0000; const uint16_t V0_PIN_KEY = 0x0000;
const uint16_t V0_PIN_FAIL_KEY = 0x0001; const uint16_t V0_PIN_FAIL_KEY = 0x0001;
uint16_t key = 0; uint16_t key = 0;
@ -1237,7 +1282,8 @@ static secbool storage_upgrade(void)
// Set the new storage version number. // Set the new storage version number.
uint32_t version = NORCOW_VERSION; uint32_t version = NORCOW_VERSION;
if (sectrue != storage_set_encrypted(VERSION_KEY, &version, sizeof(version))) { if (sectrue !=
storage_set_encrypted(VERSION_KEY, &version, sizeof(version))) {
return secfalse; return secfalse;
} }
@ -1246,7 +1292,7 @@ static secbool storage_upgrade(void)
ui_rem = ui_total; ui_rem = ui_total;
ui_message = PROCESSING_MSG; ui_message = PROCESSING_MSG;
if (sectrue == norcow_get(V0_PIN_KEY, &val, &len)) { if (sectrue == norcow_get(V0_PIN_KEY, &val, &len)) {
set_pin(*(const uint32_t*)val); set_pin(*(const uint32_t *)val);
} else { } else {
set_pin(PIN_EMPTY); set_pin(PIN_EMPTY);
} }

View File

@ -20,13 +20,15 @@
#ifndef __STORAGE_H__ #ifndef __STORAGE_H__
#define __STORAGE_H__ #define __STORAGE_H__
#include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include "secbool.h" #include "secbool.h"
typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress, const char* message); typedef secbool (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress,
const char *message);
void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt, const uint16_t salt_len); void storage_init(PIN_UI_WAIT_CALLBACK callback, const uint8_t *salt,
const uint16_t salt_len);
void storage_wipe(void); void storage_wipe(void);
secbool storage_is_unlocked(void); secbool storage_is_unlocked(void);
void storage_lock(void); void storage_lock(void);
@ -35,7 +37,8 @@ secbool storage_has_pin(void);
secbool storage_pin_fails_increase(void); secbool storage_pin_fails_increase(void);
uint32_t storage_get_pin_rem(void); uint32_t storage_get_pin_rem(void);
secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin); secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin);
secbool storage_get(const uint16_t key, void *val, const uint16_t max_len, uint16_t *len); secbool storage_get(const uint16_t key, void *val, const uint16_t max_len,
uint16_t *len);
secbool storage_set(const uint16_t key, const void *val, uint16_t len); secbool storage_set(const uint16_t key, const void *val, uint16_t len);
secbool storage_delete(const uint16_t key); secbool storage_delete(const uint16_t key);
secbool storage_set_counter(const uint16_t key, const uint32_t count); secbool storage_set_counter(const uint16_t key, const uint32_t count);

15
tools/style.c.exclude Normal file
View File

@ -0,0 +1,15 @@
^\./core/embed/bootloader/protob/
^\./crypto/aes/
^\./crypto/chacha20poly1305/
^\./crypto/ed25519-donna/
^\./crypto/gui/
^\./crypto/monero/base58
^\./crypto/monero/int-util
^\./crypto/blake2
^\./crypto/check_mem
^\./crypto/groestl
^\./crypto/ripemd160
^\./crypto/segwit_addr
^\./crypto/sha2
^\./crypto/sha3
^\./legacy/vendor

5
tools/style.c.include Normal file
View File

@ -0,0 +1,5 @@
^\./common/
^\./core/embed/
^\./crypto/
^\./legacy/
^\./storage/

2
tools/style.py.exclude Normal file
View File

@ -0,0 +1,2 @@
^\./legacy/firmware/protob/messages_pb2\.py
^\./legacy/vendor

4
tools/style.py.include Normal file
View File

@ -0,0 +1,4 @@
^\./common/
^\./core/src/
^\./crypto/
^\./legacy/