Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nimiq App Version 2.0 #6

Merged
merged 57 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
cc9f536
Remove Ledger Blue support
danimoh Mar 21, 2021
4df152a
Remove unnecessary properties for Nano S BAGL elements
danimoh Mar 22, 2021
eb278bd
Remove unused glyphs
danimoh Mar 21, 2021
fe88745
Remove unnecessary "Get App Configuration" instruction
danimoh Mar 22, 2021
337fca2
Replace our blake2b implementation by sdk's blake2b
danimoh Mar 24, 2021
f98003e
Switch to Flow UX on Nano S; remove legacy UI
danimoh Mar 26, 2021
417e9a6
Refactor and simplify flows
danimoh Mar 31, 2021
84383db
Remove processing of validity start height
danimoh Mar 31, 2021
7658cb7
Make idle menu a loop
danimoh Apr 2, 2021
5514a41
Support HTLC creation transactions
danimoh Apr 23, 2021
5189238
Support Vesting Contract creation transactions
danimoh May 2, 2021
5689685
Support contracts as sender
danimoh May 2, 2021
07bf226
Print debug error messsages on exceptions
danimoh Apr 23, 2021
0778b5a
Define constants for common string lengths
danimoh May 4, 2021
795b311
Support message signing
danimoh Feb 28, 2022
9a66f88
Improved message signing ux
danimoh Mar 9, 2022
6a1bbf0
Support requesting a preferred message display type
danimoh Mar 9, 2022
9d9d445
Smarter message display type selection based on message
danimoh May 9, 2023
9b10621
Change message signing ASCII display label to "Display as Text"
danimoh May 9, 2023
873ed67
Support displaying binary transaction data as hex
danimoh May 22, 2023
eae9652
Security fix: restrict public key verification messages to 31 bytes
danimoh Nov 29, 2023
b8a879e
Security hardening: Strict data length validations
danimoh May 4, 2024
b720745
Introduce a transaction version byte
danimoh May 4, 2024
6468b4c
Add readUVarInt and readVecU8 buffer utils
danimoh May 5, 2024
b1fdbcc
Support basic Albatross transactions
danimoh May 6, 2024
a9f6a36
Support staking transactions
danimoh May 19, 2024
c119cfd
Automatically create staker signature proof
danimoh May 28, 2024
03b6ec9
Support Ledger Stax and update SDK level
danimoh Jun 29, 2024
9af3421
Add Ragger end-to-end tests
danimoh Jul 2, 2024
e59436f
Reduce RAM usage of NBGL reviews
danimoh Jul 13, 2024
de32a76
Define shortcuts for parsed transaction contents; rename "contents" t…
danimoh Jul 13, 2024
5542f4b
Refactor Makefile to be based on Makefile.standard_app
danimoh Jul 17, 2024
c113672
Error handling: big refactor, remove legacy THROW, related improvements
danimoh Oct 8, 2024
4fe882b
Error handling: sanity check for improper use of logical error expres…
danimoh Oct 9, 2024
2d417e3
Error handling: disable debug checks in prod via NIMIQ_DEBUG preproce…
danimoh Oct 9, 2024
135cfa2
Error handling: introduce a non-conditional RETURN_ERROR macro
danimoh Oct 10, 2024
ea164ea
Error handling: on unexpected or debug errors exit app via LEDGER_ASSERT
danimoh Oct 11, 2024
ad3bd36
Error handling: show debug info on caught legacy exceptions THROWn by…
danimoh Oct 11, 2024
678c69f
Improve code readability / clarity for sending async replies
danimoh Oct 11, 2024
489c3ac
Remove deprecated method usages
danimoh Oct 12, 2024
457b3a8
Resolve remaining compiler warnings
danimoh Oct 12, 2024
da31c5c
Improve definition of string length constants, and their use in parse…
danimoh Oct 13, 2024
6afad59
Move utility macros to a separate file utility_macros.h
danimoh Oct 14, 2024
775864d
Replace unnecessary usages of strncpy by memmove
danimoh Oct 14, 2024
c5093dc
Replace strcpy by memcpy with length checks
danimoh Oct 15, 2024
e5f5c37
Resolve remaining scan-build warnings
danimoh Oct 15, 2024
415dced
Merge remote-tracking branch 'LedgerHQ/develop' into develop
danimoh Oct 15, 2024
5695aef
Update ledger_app.toml
danimoh Oct 15, 2024
b9c4b1f
Update Ragger golden snapshots for latest SDK version
danimoh Oct 15, 2024
d7f7dc7
Use explicit_bzero for clearing private keys from memory
danimoh Oct 15, 2024
d8290e0
Enforce that public key verification messages start with prefix "dumm…
danimoh Oct 15, 2024
cb7c132
Change public key verification message prefix and fix error condition
danimoh Oct 27, 2024
8c27988
Update documentation
danimoh Oct 28, 2024
0304424
Workflows: add CodeQL workflow
danimoh Oct 28, 2024
bfcf7ec
Workflows: add build_and_functional_tests workflow
danimoh Oct 28, 2024
910867a
Workflows: re-export grayscale icons to make guidelines_enforcer's ic…
danimoh Oct 28, 2024
1f8177e
Update app version to 2.0
danimoh Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 32 additions & 0 deletions .github/workflows/build_and_functional_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Build and run functional tests using ragger through reusable workflow

# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation.
# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the
# resulting binaries.
# It then calls another reusable workflow to run the Ragger tests on the compiled application binary.
#
# While this workflow is optional, having functional testing on your application is mandatory and this workflow and
# tooling environment is meant to be easy to use and adapt after forking your application

on:
workflow_dispatch:
push:
branches:
- master
- main
- develop
pull_request:

jobs:
build_application:
name: Build application using the reusable workflow
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
with:
upload_app_binaries_artifact: "compiled_app_binaries"

ragger_tests:
name: Run ragger tests using the reusable workflow
needs: build_application
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1
with:
download_app_binaries_artifact: "compiled_app_binaries"
43 changes: 43 additions & 0 deletions .github/workflows/codeql_checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "CodeQL"

on:
workflow_dispatch:
push:
branches: ["main", "master", "develop"]
pull_request:
branches: ["main", "master", "develop"]
# Excluded path: add the paths you want to ignore instead of deleting the workflow
paths-ignore:
- '.github/workflows/*.yml'
- 'tests/*'

jobs:
analyse:
name: Analyse
strategy:
matrix:
sdk: [ "$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK" ]
#'cpp' covers C and C++
language: [ 'cpp' ]
runs-on: ubuntu-latest
container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest

steps:
- name: Clone
uses: actions/checkout@v3
with:
submodules: recursive
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-and-quality

# CodeQL will create the database during the compilation
- name: Build
run: |
make BOLOS_SDK=${{ matrix.sdk }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
13 changes: 7 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
build
bin
debug
dep
obj
src/glyphs.c
src/glyphs.h
.idea
nano-sdk
blue-sdk

# Temporary directory with snapshots taken during test runs
tests/snapshots-tmp/

# Output folder of clang static analyzer scan-build, see Makefile.rules-generic in Ledger SDK
output-scan-build
220 changes: 97 additions & 123 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,139 +18,113 @@
ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif

include $(BOLOS_SDK)/Makefile.defines

APPNAME = Nimiq
APP_LOAD_PARAMS=--appFlags 0x240 --path "44'/242'" --curve ed25519 $(COMMON_LOAD_PARAMS)

APPVERSION_M=1
APPVERSION_N=4
APPVERSION_P=6
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

#prepare hsm generation
ifeq ($(TARGET_NAME),TARGET_BLUE)
ICONNAME=blue_app_nimiq.gif
else ifeq ($(TARGET_NAME),TARGET_NANOS)
ICONNAME=nanos_app_nimiq.gif
else
ICONNAME=nanox_app_nimiq.gif
endif

################
# Default rule #
################
all: default
##############################
# App description #
##############################

############
# Platform #
############
# Application name
APPNAME = Nimiq

DEFINES += OS_IO_SEPROXYHAL
DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
# Application version
APPVERSION_M = 2
APPVERSION_N = 0
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

# Setting to allow building variant applications. For now, there are no variants, only the main Nimiq app.
VARIANT_PARAM = COIN
VARIANT_VALUES = nimiq


##############################
# Source files #
##############################

# Application source files
APP_SOURCE_PATH += src

# For now, don't include standard app files, as our code is not currently using the new common / standard app utilities,
# with the advantage of not including any utilities we don't use, but of the downside of having to maintain these common
# code utilities ourselves.
DISABLE_STANDARD_APP_FILES = 1

# Application icons following the guidelines:
# https://developers.ledger.com/docs/device-app/deliver/deliverables/icons
# Notes on how to create such icons in GIMP:
# - Open an SVG of the Nimiq logo and set the image width to the size of the safe area for the intended image size, e.g.
# 30px for the 32pxx32px image. Also import the paths.
# - Layer > Transparency > Remove Alpha Channel.
# - Edit > Fill the image with white.
# - Edit > Fill Path with black, or Select > From Path and fill the selection with a radial gradient, potentially with
# an adequate offset set.
# - Set Image > Mode to indexed and for 1bit-per-pixel images (Nano devices) use a color palette with just black and
# white, and for 4bit-per-pixel images (e-ink devices) use a color palette with 16 colors 0x00, 0x11, 0x22, ..., 0xff.
# If desired, enable dithering and experiment with different modes. Mode "positioned" looks quite nice. For more
# control, also Colors > Dither might be used.
# - Set the Layer > Layer Boundary Size to the intended size of the final image, centering the content. Then Image > Fit
# Canvas to Layers.
# - Save the icon as xcf with the indexed color map which can be used for future changes to the image.
# - For binary black/white icons: export the icon with indexed color mode as gif, which will save as 1bit-per-pixel.
# For grayscale icons: The guidelines_enforcer.yml workflow expects grayscale images to have 8bit-per-pixel depth
# (even though the glyph build task seems to be compatible with lower bit-per-pixel), therefore change the Image >
# Mode to Grayscale and then export as gif. Do not overwrite the xcf file, to keep it in indexed mode.
# For some reason, for glyphs/app_nimiq_64px.gif, but not for the other icons, this made the glyph build task complain
# that the image is not indexed. So not quite sure yet, what the proper procedure would be here. Also tried, re-export
# of app_nimiq_64px.gif via https://www.photopea.com/, which exports with a color map with 256 entries, excess entries
# simply being filled up as black, but that still had 4bpp depth the enforcer complained about. Switching to Grayscale
# and then back to an indexed palette with 32 shades of gray seems to have done the trick.
# Note that for checking for the bit depth, ImageMagick's identify can be used: identify -verbose /path/to/icon.gif
ICON_NANOS = icons/app_nimiq_16px.gif
ICON_NANOX = icons/app_nimiq_14px.gif
ICON_NANOSP = icons/app_nimiq_14px.gif
ICON_STAX = icons/app_nimiq_32px.gif
ICON_FLEX = icons/app_nimiq_40px.gif


##############################
# Permissions and features #
##############################

# Application allowed derivation curves.
CURVE_APP_LOAD_PARAMS = ed25519

# Application allowed derivation paths.
PATH_APP_LOAD_PARAMS = "44'/242'"

# See SDK `include/appflags.h` for the purpose of each permission
HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
#HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 # Automatically set in Makefile.standard_app for devices with bluetooth

ENABLE_BLUETOOTH = 1
ENABLE_NBGL_QRCODE = 1

# U2F
# U2F has been deprecated by Ledger, disabled in most apps and is not configured in $(BOLOS_SDK)/Makefile.standard_app,
# but we keep it for now as Nimiq is a browser centric coin, and Firefox and Safari don't support WebHID or WebUSB yet.
# Note though that U2F is somewhat memory hungry, apart from the significant UX flaws. Also see:
# https://www.ledger.com/windows-10-update-sunsetting-u2f-tunnel-transport-for-ledger-devices
# https://developers.ledger.com/docs/connectivity/ledgerJS/faq/U2F
DEFINES += HAVE_IO_U2F
DEFINES += U2F_PROXY_MAGIC=\"w0w\"
DEFINES += U2F_REQUEST_TIMEOUT=28000 # 28 seconds
DEFINES += USB_SEGMENT_SIZE=64
DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20
DEFINES += UNUSED\(x\)=\(void\)x
DEFINES += APPVERSION=\"$(APPVERSION)\"

#WEBUSB_URL = www.ledgerwallet.com
#DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g")
DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL=""

ifeq ($(TARGET_NAME),TARGET_NANOX)
DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000
DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE
endif

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128
else
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300
DEFINES += HAVE_GLO096
DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64
DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
DEFINES += HAVE_UX_FLOW
endif


# Enabling debug PRINTF
DEBUG = 0
ifneq ($(DEBUG),0)

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += HAVE_PRINTF PRINTF=screen_printf
else
DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf
endif
else
DEFINES += PRINTF\(...\)=
endif



##############
# Compiler #
##############
ifneq ($(BOLOS_ENV),)
$(info BOLOS_ENV=$(BOLOS_ENV))
CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
else
$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH)
SDK_SOURCE_PATH += lib_u2f

# Enabling DEBUG flag will enable PRINTF and disable optimizations
# Instead of setting it here you can also enable this flag during compilation via `make DEBUG=1`
#DEBUG = 1
# Make the debug flag available in the code as NIMIQ_DEBUG preprocessor define.
ifneq ($(DEBUG), 0)
DEFINES += NIMIQ_DEBUG
endif
ifeq ($(CLANGPATH),)
$(info CLANGPATH is not set: clang will be used from PATH)
endif
ifeq ($(GCCPATH),)
$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH)
endif

CC := $(CLANGPATH)clang

#CFLAGS += -O0
CFLAGS += -O3 -Os

AS := $(GCCPATH)arm-none-eabi-gcc

LD := $(GCCPATH)arm-none-eabi-gcc
LDFLAGS += -O3 -Os
LDLIBS += -lm -lgcc -lc

# import rules to compile glyphs(/pone)
include $(BOLOS_SDK)/Makefile.glyphs

### computed variables
APP_SOURCE_PATH += src
SDK_SOURCE_PATH += lib_stusb
SDK_SOURCE_PATH += lib_stusb_impl
SDK_SOURCE_PATH += lib_u2f
SDK_SOURCE_PATH += lib_ux

ifeq ($(TARGET_NAME),TARGET_NANOX)
SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl
endif

load: all
python -m ledgerblue.loadApp $(APP_LOAD_PARAMS)

delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)

# import generic rules from the sdk
include $(BOLOS_SDK)/Makefile.rules

#add dependency on custom makefile filename
dep/%.d: %.c Makefile.genericwallet
# Extend the base Makefile for standard apps
include $(BOLOS_SDK)/Makefile.standard_app

listvariants:
@echo VARIANTS COIN nimiq
# Makes a detailed report of code and data size in debug/size-report.txt
# More useful for production builds with DEBUG=0
size-report: bin/app.elf
arm-none-eabi-nm --print-size --size-sort --radix=d bin/app.elf >debug/size-report.txt
38 changes: 17 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
# Nimiq app for the Ledger Nano S and Ledger Blue
# Nimiq app for Ledger devices

## Introduction

This is a wallet app for the [Ledger Nano S](https://www.ledgerwallet.com/products/ledger-nano-s) and [Ledger Blue](https://www.ledgerwallet.com/products/ledger-blue) that makes it possible to store your [Nimiq](https://nimiq.com/)-based assets on those devices.
This is a device app for the [Ledger Hardware Wallets](https://www.ledger.com/) which makes it possible to store your
[Nimiq token (NIM)](https://nimiq.com/) on those devices (more precisely use the associated private key for NIM related
operations).

A companion [Javascript library](https://github.com/LedgerHQ/ledgerjs) is available to communicate with this app.
A companion [Javascript library](https://github.com/nimiq/ledger-api) is available to communicate with this app.

To learn how to use this library you can take look at the [demo project](https://github.com/jeffesquivels/ledgerjs-nimiq).
## Development Setup

## Building and installing

To build and install the app on your Nano S or Blue you must set up the Ledger Nano S or Blue build environment. Please follow the Getting Started instructions at the [Ledger Nano S github repository](https://github.com/LedgerHQ/ledger-nano-s).

Alternatively, you can set up the Vagrant Virtualbox Ledger environment maintained [here](https://github.com/fix/ledger-vagrant). This sets up an Ubuntu virtual machine with the Ledger build environment already set up. Note that if you are on a Mac, at the time of this writing this seems to be the only way to build and load the app.

The command to compile and load the app onto the device is:

```$ make load```

To remove the app from the device do:

```$ make delete```
For build and installation instructions, please refer to:
- The README of the [Ledger Boilerplate App](https://github.com/LedgerHQ/app-boilerplate)
- [Usage instructions of Ledger's VSCode extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools)
and the associated [quickstart guide](https://developers.ledger.com/docs/device-app/beginner/vscode-extension),
or the underlying [ledger-app-builder docker images](https://github.com/LedgerHQ/ledger-app-builder/), if you prefer
to use them directly, without the VSCode extension. Here at Nimiq, mainly the docker images have been used directly
for building and testing the application via the [Speculos](https://github.com/LedgerHQ/speculos) emulator, on real
devices and via [Ragger](https://github.com/LedgerHQ/ragger) functional tests.

## Testing

The `./test` directory contains files for testing the transaction parser and some printing utilities. To build and execute the tests run `./test.sh`.

## Key pair validation
The project contains functional tests powered by [Ragger](https://github.com/LedgerHQ/ragger). They can be launched via
the VSCode extension or docker images as described in the section [Development Setup](#development-setup).

The operation to retrieve the public key implements an optional keypair verification method. Along with the request to retrieve the public key a small message is sent that is to be signed by the device. Back on the host the returned signature can be checked against the returned public key. This is to guard against incompatibility between the keypairs generated by the Ledger device and the ones expected by the Nimiq network, whatever the reason for this might be. The extra precaution prevents users from sending funds to an address they are not able to sign transactions for.
Additionally, the project contains [unit-tests](https://github.com/nimiq/ledger-app-nimiq/tree/master/unit-tests).
Binary file removed ble_app_nimiq.gif
Binary file not shown.
Loading
Loading