Offline Avalanche App installation on a Ledger Nano S+

So I've been looking for a way to install the Avalanche app on new ledger nano devices while 100% disconnected from the Internet


I thought this'd be trivial but it isn't.

First of all : hardware wallets are supposed to be airgapped if you want them to be. They're supposed to work offline.

Also, the fact that we now know the private keys are extractable from the devices makes things all the more complicated because Ledger requires you to enter your recovery phrase BEFORE installing any apps.

In short: Ledger requires your private key FIRST, and THEN asks you to connect to their live service in order to install an app that injects binary code straight into your device.

That's a huge red flag IMO. I'm not going there.

I *could* download a binary build of the Avalanche app. But that's not dont-trust-verifiable at all.

So in this thread I'll log my attempts to build an Avalanche Ledger App binary and then install it using the debugging tools provided by ledger.

The goal here is to do everything while 100% airgapped. Let's see where this goes.
 
First things first, clone the SDK somewhere:

git clone https://github.com/LedgerHQ/ledger-secure-sdk.git

Clone the Avalanche app sources under the same dir as the SDK:

git https://github.com/LedgerHQ/app-avalanche.git

Now cd into the SDK dir:

cd ledger-secure-sdk

git checkout nanos+_1.2.0-rc2
grep API_LEVEL Makefile.defines | head -n1

git checkout API_LEVEL_12
git pull

Now cd into the app repo and build the project:

cd ../app-avalanche
make BOLOS_SDK=../ledger-secure-sdk/ TARGET=nanos2

nanos2 is the Nano S+ alias, choose yours per the documentation at https://github.com/LedgerHQ/ledger-secure-sdk

That's all for the basic build instructions. It doesn't work on my Ubuntu 20.04 box, so we'll dive further in the coming posts.
 
I'm getting

error: failed to parse manifest at `app-avalanche/app/Cargo.toml`

Caused by:
invalid type: map, expected a sequence for key `package.authors`

So...looks like the package.authors key should lead to a list of something, not a scalar value. This reeks of an outdated Cargo.toml file...but why? I cloned the very latest release....or did I?

Well it turns out I didn't.

That ledger app under the LedgerHQ repo is a fork. They haven't pulled recent updates!

This one seems to be the correct repo: https://github.com/ava-labs/ledger-avalanche.git

Let's try that first step again, but now we clone this repo:

git clone https://github.com/ava-labs/ledger-avalanche.git
 
The BOLOS_SDK environment var gotta be an absolute path, cuz make goes into subdirectory makefiles. So we need 2 environment variables set like so:

export BOLOS_SDK=/FULL/PATH/TO/ledger-secure-sdk/
export TARGET=nanos2

In the ledger-avalanche dir, we run make to see what happens this time:

make

error: failed to get `bolos` as a dependency of package `avalanche-app v0.1.0 (/PATH/TO/ledger-avalanche/app)`

Caused by:
failed to load source for dependency `bolos`

Caused by:
Unable to update /PATH/TO//ledger-avalanche/deps/ledger-rust/bolos

Caused by:
failed to read `/PATH/TO//ledger-avalanche/deps/ledger-rust/bolos/Cargo.toml`

Caused by:
No such file or directory (os error 2)
make[1]: *** [Makefile:298: rust] Error 101


K.... so we're definitely missing some stuff under ./depts. But what? We installed all the dependencies....

I don't see these dependencies in the Makefile either...

So we need to install "just". I've no idea why anyone would use this tool but there it is. "just" requires makedeb and all sorts of dependencies. This is a real PITA tbh. Anyway, don't have the time to fix this now, so gotta go with the flow.

bash -ci "$(wget -qO - 'https://shlink.makedeb.org/install')"

Should get makedeb installed.

Then:

git clone 'https://mpr.makedeb.org/just'
cd just
makedeb -si

Which of course fails.

command line argument : Depends: cargo (>= 1.63) but it is not going to be installed

$ cargo --version
cargo 1.72.0 (103a7ff2e 2023-08-15)


We have a newer cargo than this tool wants. That's what you get for using non-standard build tools, this dependency hell can break any project. Makefile would've been a mature and standard choice for this build system, but they just had to go with "just". So we have a newer cargo than this POS wants, we'll need to fool it.

There's a file called PKGBUILD with a cargo requirement line in it. Let's comment that out

#makedepends=('cargo>=1.63')

Now run makedeb -si and it should work

$ just
error: No justfile found

K now we have this piece of crap installed, let's try another build.

make

Now we're missing some ARM build tools. Quick search and I get this:

$ sudo apt-get remove binutils-arm-none-eabi gcc-arm-none-eabi
$ sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
$ sudo apt-get update
$ sudo apt-get install gcc-arm-none-eabi
$ sudo apt-get install gdb-arm-none-eabi

Now all the ARM tools are installed, let's try just init again

just init

I'm getting errors about a zemu target. This seems to be some emulator. We don't want that for now, all we need is an app build, so I'll comment out the zemu line out of the Justfile:

# just make zemu_install

Retry:

$ just init
just deps/sdk true
Adding existing repo at 'deps/ledger-rust' to the index
Submodule path 'ledger-rust': checked out '0aa766899815369c1fd96cab468db7e0346ceda4'
Previous HEAD position was 0aa7668 Merge pull request #35 from Zondax/dev
HEAD is now at 55a2b14 fix(build:stax): `-Ilib_nbgl/include`
just make deps
make deps
make: 'deps' is up to date.

Alright. We got the deps down now. Let's try another build

AAAANDDD BOOM

It failed

1693882450995.png

Well that sucks. Gotta take a break now. To be continued
 
1.5 hours later finally got this to work

First, the ARM cross-compiler needs to be installed from here.

Follow the instructions here for post-install config.

Then do a full cleanup of the ledger-avalanche repo. I was getting random core dumps, probably from mixed up partial compilations.
rm -rf ledger-avalanche

git clone https://github.com/ava-labs/ledger-avalanche.git
Edit Justfile and comment out the zemu task:
# just make zemu_install
(Zemu looks cool so feel free to experiment with it. We won't use it on this build.)
Run just init :
just init
Then build the project:
make
Here's the output tail:
[LINK] build/stax/bin/app.elf
[CP] build/stax/bin/app.elf => bin/app.elf
[CP] build/stax/bin/app.hex => bin/app.hex
[CP] build/stax/dbg/app.map => debug/app.map
[CP] build/stax/dbg/app.asm => debug/app.asm
[CP] build/stax/bin/app.apdu => bin/app.apdu
[CP] build/stax/bin/app.sha256 => bin/app.sha256
# Commented due to a crash when trying to sign BTC transactions, it needs to be allowed to
# use generic paths, instead of being limited to the paths passed bellow.
# @echo "APPPATH=\"""44'/9000'" --path "44'/60'""\"" >> /app/app/../build/pkg/installer_fs.sh

There you go! We got ourselves a installer_fs.sh script built from source AND a app.elf Avalanche App for Ledger Nano S+ built from the auditable sources!

Next step:

installer_fs.sh load

Since you got the binaries locally, no need to keep your Ledger online now.

Disconnect all your networking, set airplane mode. Now generate a mnemonic using avax-toolbox (completely airgapped) and set your Ledger up 100% offline.

Keep buidling frens!
 
A final note:

I noticed that the Ava Labs repo


is ahead of the Ledger Hq one:


I could be wrong but maybe the version at LedgerHQ is the latest one they audited before building and publishing on the ledger live store.

Just a guess ;)
 
Back
Top