├── .gitignore ├── Makefile ├── README.md ├── VERSIONING.md └── source ├── _static └── theme_overrides.css ├── additional ├── external_docs.rst ├── images │ ├── app_architecture.png │ ├── bitcoin-live.png │ ├── device_template.png │ ├── horizontal_menu.png │ ├── manager.png │ ├── manager_template.png │ ├── scroll.gif │ └── vertical_menu.png ├── publishing_an_app.rst └── security_guidelines.rst ├── background ├── application_isolation.rst ├── hd_keys.rst ├── hd_use_cases.rst ├── images │ └── where_are_my_assets.png ├── introduction.rst ├── master_seed.rst └── personal_security_devices.rst ├── bolos ├── application_environment.rst ├── features.rst ├── hardware_architecture.rst ├── images │ ├── app_centric_view.png │ ├── bolos_architecture.png │ ├── chain_of_trust.png │ ├── secure_channel_protocol.png │ ├── seproxyhal.png │ ├── usb_delegation_overview.png │ └── wallet_not_genuine.png ├── introduction.rst └── overview.rst ├── conf.py ├── index.rst └── userspace ├── advanced_display_management.rst ├── alignment.rst ├── application_structure.rst ├── debugging.rst ├── display_management.rst ├── images ├── common_protocols.png ├── deadbeef.png ├── debug_nano.jpg ├── nanos │ ├── nanos_address.png │ ├── nanos_address_merged.png │ ├── nanos_amount.png │ ├── nanos_approve.png │ └── nanos_boilerplate.png └── nanox │ ├── nanox_address.png │ ├── nanox_address_merged.png │ ├── nanox_amount.png │ ├── nanox_approve.png │ └── nanox_boilerplate.png ├── introduction.rst ├── low_level_display_management.rst ├── memory.rst ├── setup.rst ├── speculos.rst ├── syscalls.rst ├── troubleshooting.rst └── writing_apps.rst /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal Makefile for Sphinx documentation 2 | 3 | # You can set these variables from the command line. 4 | SPHINXOPTS = 5 | SPHINXBUILD = python3 -msphinx 6 | SPHINXPROJ = Ledger 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ledger Developer Documentation (DEPRECATED - please use https://github.com/LedgerHQ/developer-portal) 2 | 3 | This repository contains the core documentation for developers who wish to make 4 | BOLOS applications, and for those who would like to gain a better understanding 5 | of the features offered by BOLOS and the background theory behind our products. 6 | 7 | The latest version of this repository can be viewed, pre-built, here: 8 | https://ledger.readthedocs.io. 9 | 10 | ## Contributing 11 | 12 | If you notice a mistake or would like to contribute, feel free to issue a pull 13 | request or talk to us on the [developer Slack](https://ledger-dev.slack.com). 14 | 15 | If you make a contribution with a pull request, don't bother bumping the version 16 | number yourself. We will do this at some point if your pull request is accepted. 17 | 18 | ## Building 19 | 20 | If you wish, you may install Sphinx and build this documentation into a 21 | collection of HTML files yourself. 22 | 23 | Firstly, make sure you have [pip3 24 | installed](https://linuxize.com/post/how-to-install-pip-on-ubuntu-18.04/). 25 | 26 | Secondly, install Sphinx and the Read the Docs theme: 27 | 28 | ``` 29 | pip3 install sphinx sphinx_rtd_theme 30 | ``` 31 | 32 | Finally, build: 33 | 34 | ``` 35 | make html 36 | ``` 37 | 38 | You will need internet access for intersphinx to work properly. 39 | -------------------------------------------------------------------------------- /VERSIONING.md: -------------------------------------------------------------------------------- 1 | # Versioning 2 | 3 | The version for this documentation is represented by a single integer number 4 | which is tagged on the commit corresponding to the release of a specific version 5 | of the documentation. In `/source/conf.py`, both the `version` and `release` 6 | option shall always be the same, and represent the latest release version. As 7 | such, they should always be bumped by the commit that was tagged with a version 8 | number. 9 | 10 | The version numbers used for this documentation doesn't have any relevant 11 | meaning to the reader. Versioning was implemented such that links to this 12 | documentation could be retained, even in future versions if certain references 13 | change (this is mainly important for intersphinx). 14 | 15 | For example, to link to a specific reference for a specific version, you may do 16 | so like this: 17 | 18 | https://ledger.readthedocs.io/en/1/bolos/features.html#term-issuer 19 | 20 | The version number is simply an integer counter that increments every time the 21 | docs have been changed and are ready for publication. All that matters is that 22 | the version number is bumped every time a new build should be available on RTD. 23 | 24 | As such, the checklist for releasing a new version of this documentation is as 25 | follows: 26 | 27 | 1. Create a final commit that bumps the version numbers in `/source/conf.py`. 28 | 2. Tag that commit with the appropriate version number. 29 | 3. Done! RTD should find the tag and build the docs automagically. 30 | -------------------------------------------------------------------------------- /source/_static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | /* override table width restrictions */ 2 | @media screen and (min-width: 767px) { 3 | 4 | .wy-table-responsive table td { 5 | /* !important prevents the common CSS stylesheets from overriding 6 | this as on RTD they are loaded after this stylesheet */ 7 | white-space: normal !important; 8 | } 9 | 10 | .wy-table-responsive { 11 | overflow: visible !important; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /source/additional/external_docs.rst: -------------------------------------------------------------------------------- 1 | External Documentation 2 | ====================== 3 | 4 | In addition to the documentation provided in this hub, we also have the 5 | following resources available: 6 | 7 | * :doc:`python-loader:index` 8 | -------------------------------------------------------------------------------- /source/additional/images/app_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/app_architecture.png -------------------------------------------------------------------------------- /source/additional/images/bitcoin-live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/bitcoin-live.png -------------------------------------------------------------------------------- /source/additional/images/device_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/device_template.png -------------------------------------------------------------------------------- /source/additional/images/horizontal_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/horizontal_menu.png -------------------------------------------------------------------------------- /source/additional/images/manager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/manager.png -------------------------------------------------------------------------------- /source/additional/images/manager_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/manager_template.png -------------------------------------------------------------------------------- /source/additional/images/scroll.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/scroll.gif -------------------------------------------------------------------------------- /source/additional/images/vertical_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/additional/images/vertical_menu.png -------------------------------------------------------------------------------- /source/additional/publishing_an_app.rst: -------------------------------------------------------------------------------- 1 | Publishing an Application 2 | ========================= 3 | The Ledger Manager is the service which centralizes the distribution of :doc:`BOLOS ` applications on Ledger devices. It is the place where both Ledger's apps and third party apps are distributed to users. 4 | This document aims at explaining the procedure for a third party app to be released on the Ledger Manager. 5 | 6 | .. figure:: images/manager.png 7 | :align: center 8 | 9 | The Ledger Manager 10 | 11 | First, let's see the typical end-to-end architecture of a BOLOS application, in 12 | the case of an app for a cryptocurrency: 13 | 14 | .. figure:: images/app_architecture.png 15 | :align: center 16 | 17 | End-to-end architecture of a BOLOS application 18 | 19 | In this example, 3 pieces of software are required: 20 | 21 | 1. A BOLOS application, written in C, running on a Ledger device 22 | 2. The companion app, with business logic and typically a GUI, running on a 23 | computer or a phone connected to the Ledger device 24 | 3. A transaction explorer that interfaces between the front-end and the 25 | cryptocurrency daemon, running either locally (in the case of a full node) or 26 | remotely (light wallet) 27 | 28 | If you're not developing an app adding support for a cryptocurrency, then you 29 | can ignore the 3rd piece. Depending on your use case, the companion app might be a simple daemon or a command line tool, without a GUI. 30 | *The companion app should always be compatible with Windows, MacOS and Linux* 31 | 32 | .. figure:: images/bitcoin-live.png 33 | :align: center 34 | 35 | Ledger's main companion app: the Ledger Live 36 | 37 | When these pieces are ready for deployment, they must be sent to Ledger for 38 | a security review. One of the things we're going to do is review the security of the BOLOS 39 | application code, and check that it functions as intended in conjunction with 40 | its companion app. Here is a non-exhaustive list of what we're looking at 41 | during the review process: 42 | 43 | * Backdoors 44 | * Buffer overflows 45 | * Correct use of the device (for example, minimizing :ref:`NVRAM wearing 46 | `) 47 | * Correct use of the SDK 48 | * Application stability, correct handling of errors 49 | * Correct usability (see `Design Guidelines`_) 50 | 51 | Review time depends on Ledger’s available resources and code complexity. The 52 | more unique and complex the code, the longer the review. Please note that forks 53 | of supported BOLOS apps will require a new review. The decision to reject or 54 | revoke an app is at Ledger’s sole discretion. We will make our best efforts to 55 | provide a rationale for such decisions. Upon fixing identified issues, app 56 | authors will be allowed to re-submit their apps. 57 | A new all-in-one native app called *Ledger Live* 58 | has been released on the 9th of July, 2018. This new platform will be open to 59 | pull requests for adding support for new cryptocurrencies in the coming months, 60 | *it is not available yet*. Currently, your best shot is to build your own companion 61 | app with its own backend. It is less convenient for users than a full integration 62 | to Ledger Live, but on the other hand, it gives you more freedom on the design 63 | of the interface you want users to see, and the way it will be implemented 64 | (Web app? Native app? It's up to you!). 65 | 66 | Design Guidelines 67 | ----------------- 68 | 69 | 70 | The design of your device app will be added to our website to inform that your app is 71 | available. In that respect, we thank you to provide us with the design in a format and 72 | with measurements that shall meet the criteria communicated by our team. 73 | 74 | There are 2 mandatory icons that should be provided for Ledger to release an app: 75 | 76 | - The Device icon, displayed on the Nano S dashboard 77 | - The Manager icon, displayed in the Manager application list 78 | 79 | Below are the Adobe Illustrator templates for such icons, please respect their guidance. 80 | 81 | - The color palette for Blue icons shall contain 16 colors maximum 82 | 83 | - The icon file shall not contain any alpha channel 84 | 85 | - In order to blend well with the Blue's Dashboard background, the 4 rounded white corners of the blue icon shall be set to this RGB value: #F9F9F9 (and not #FFFFFF) 86 | 87 | 88 | - Nano X icons must be 14x14 px in size. Developers can create their Nano X icons from the 16x16 px Nano S one with the following command on Linux (it first requires to install the package `imagemagick`): ``convert nanos_app_.gif -crop 14x14+1+1 +repage -negate nanox_app_.gif`` 89 | 90 | 91 | **Click on each image to download the corresponding .ai file, and fill them directly before sending them back. They should correspond to the icons used to compile your app.** 92 | 93 | .. figure:: images/device_template.png 94 | :align: center 95 | :target: https://drive.google.com/a/ledger.fr/file/d/1FVUWDGYPvLuyiwDFgGYiwfwk7YGsxzJ0/view?usp=sharing 96 | 97 | Device icon template (click to access Illustrator file) 98 | 99 | .. figure:: images/manager_template.png 100 | :align: center 101 | :target: https://drive.google.com/a/ledger.fr/file/d/1OOAZWlnLlBSpScPnF5NGJ4AfczB3D591/view?usp=sharing 102 | 103 | Manager icon template (click to access Illustrator file) 104 | 105 | 106 | Most of the time, Bolos apps expose few functionalities to the user. However, 107 | despite this simplicity, it is still challenging to build a user-friendly 108 | interface, because of the few inputs (only 2 buttons !) and also because of 109 | the screen size which offer only 128*32 pixels. 110 | Ledger provides some guidance to avoid third party developers to reinvent 111 | the wheel. 112 | 113 | .. note:: 114 | 115 | See the :doc:`BAGL Toolkit` for more information 116 | on the BOLOS Application Graphics Library technical details. 117 | 118 | 119 | Even though the screen is small, you don't want to bloat it with plenty of tiny text 120 | to fit everything in a single time. Instead, multiple successives screens are the 121 | way to go, with a configurable time interval between each screen switch. 122 | Doing this allows you to split and segment the information to display. 123 | It is also a good practice to inform the user of what is the kind of information 124 | currently displayed, by giving it a title. 125 | In some cases, even when the information is segmented by type, there won't be 126 | enough space for it to fit entirely on screen. Rather than splitting this information 127 | in multiple screens, it is better to use automatic scrolling display. 128 | Here is an example that sums it up: 129 | 130 | .. figure:: images/scroll.gif 131 | :align: center 132 | 133 | Example: transaction confirmation screen 134 | 135 | On this example two pieces of information are shown: an amount of bitcoins, and a 136 | destination address. 137 | The two screens are alternating periodically until the user validates or cancel. 138 | A title is present to describe each information. For the too-long-to-display destination 139 | address, the automatic scrolling is used. 140 | 141 | A few graphical pointers (glyphs) help users to make a link between the right and left 142 | buttons and their effects. 143 | There are four principal functions fulfilled by pressing buttons: 144 | 145 | - Making a binary choice for a question asked by the device (1 button) 146 | - Moving in a menu (1 button) 147 | - Selecting a menu entry (2 buttons) 148 | - Proceeding with a disclaimer (2 buttons) 149 | 150 | To propose a binary choice to the user, 2 glyphs representing the 2 choices should be 151 | placed on each side of the screen (a cross symbol to cancel and a validation symbol to 152 | accept). 153 | You can display a question and relevant information in between the glyphs, like in the 154 | upper example. 155 | 156 | To move inside a menu, be it vertical or horizontal, the same technique is applied with 157 | different glyphs. We recommend using arrows: up and down for a vertical menu, left and 158 | right for a horizontal one). 159 | 160 | .. figure:: images/horizontal_menu.png 161 | :align: center 162 | 163 | Example use of arrows in an horizontal menu 164 | 165 | 166 | .. figure:: images/vertical_menu.png 167 | :align: center 168 | 169 | Example use of arrows in a vertical menu 170 | 171 | Once positioned on the right menu entry, the user can select the entry by pressing both 172 | buttons. This potential action is not represented by glyphs. 173 | Same goes when going through a set of disclaimer screens: only text is displayed, and 174 | the user goes to the next part by pressing both buttons. 175 | This is a consistent behavior across the device, so you can assume that users are used 176 | to it. It should feel obvious when the user has to press two buttons to go through 177 | something in your app. 178 | 179 | Ledger does not impose the icons nor the interface for third party applications, however user 180 | friendliness and guidelines compliance is something being reviewed during the integration process. 181 | Therefore, a very poor design might be a cause of delay in your release roadmap if the 182 | outcome of the review is negative because of it. Don't neglect it ! 183 | 184 | Design Warranty 185 | --------------- 186 | 187 | The design of your device app shall free from any encumbrances and shall not infringe upon any third party intellectual property right, in particular trademark and design rights. You grant Ledger the right to use such design for free with the right to reproduce and exploit the design for the duration of its display on Ledger website. 188 | 189 | You represent and warrant that the device app you are making available on Ledger Live is in compliance with all relevant laws and regulations. 190 | 191 | You agree to hold Ledger harmless of any claim arising out of the use of the design and or distribution of the device app . 192 | 193 | Release Process 194 | --------------- 195 | 196 | There are different release levels for a given application: 197 | 198 | * **Public release** (official Ledger support) 199 | * **Developer mode release** (experimental support) 200 | 201 | * Developer mode with an **audited** application 202 | * Developer mode with an **unaudited** application 203 | 204 | 205 | .. warning:: 206 | 207 | In any case, Ledger's decision to publish a third party application may not be considered as any form of partnership nor endorsement of such. 208 | 209 | 210 | As long as an application isn't audited by Ledger security team, the message ``Pending Ledger Review`` will be made visible when the application is started. 211 | The user can aknowledge and skip this warning by pressing both buttons and use the application at his own risks. 212 | As an unaudited application is considered experimental, such application will be visible **only once the developer mode settings has been enabled** in Ledger Live settings. 213 | 214 | Some applications are also visible once the developer mode setting is enabled, not because of a lack of security review, but rather because they are considered too complex to use. A reason might be a the mandatory compatible GUI is missing, or the application purpose is considered too technical for the vast majority of users. 215 | 216 | An application will be listed publicly (official Ledger support) once: 217 | 218 | * It passed the security audit 219 | * It's been tested and validated by at least someone from Ledger Customer Success Team 220 | * The application is compatible with a GUI companion app (CLI is not enough) 221 | * Ledger is ready to communicate officially about the app release (tweet, blogpost, website page update) 222 | * Customer support pages are available on Ledger Help Center 223 | 224 | .. note:: 225 | 226 | Ledger releases new cryptocurrency apps for its devices whenever reviews, tests, and resources allow it. Applications are usually released on Tuesday or Wednesday. 227 | 228 | 229 | 230 | Third Party Applications Support 231 | -------------------------------- 232 | 233 | .. note:: 234 | 235 | The following only applies if you are adding support for a cryptocurrency and 236 | chose to build your own companion app. 237 | 238 | Ledger does not provide support for third party applications. 239 | **It is required for third party teams to provide and host a complete tutorial that will guide 240 | users before the app is released on the Ledger Manager** (please follow `these guidelines 241 | `_). 242 | 243 | Along with your publication request, app sources and tutorial, 244 | please provide information that will allow the Ledger support team to redirect 245 | users to relevant support resources: 246 | 247 | * **Identity: Name, Surname, Legal Entity** 248 | * **Point of Contact: URL, email address, phone number** 249 | 250 | .. note:: 251 | 252 | Name, surname and phone number are kept private and will be used only in case of emergency. 253 | 254 | Contact 255 | ------- 256 | External developer teams are welcome on `Ledger's Developer Slack 257 | `_. This is the place to get technical 258 | support, to discuss Ledger's tech stack, and more broadly to get in touch with 259 | us. 260 | 261 | Warranty and liability disclaimer 262 | --------------------------------- 263 | 264 | The review and publication of third-party Ledger device applications (collectively “the Service”) are provided by Ledger on an “as-is” and “as-available” basis. The Service is subject to change without notice. Ledger disclaims all warranties of accuracy, non-infringement, merchantability and fitness for a particular purpose. To the extent that Ledger makes any pre-release of Ledger device applications available to third-party developers, you understand that Ledger is under no obligation to provide updates, enhancements, or corrections, or to notify you of any changes that Ledger may make, or to publicly announce or introduce the Ledger device applications at any time in the future. 265 | 266 | To the extent not prohibited by applicable law, in no event will Ledger be liable for personal injury, or any incidental, special, indirect, consequential or punitive damages whatsoever, including, without limitation, damages resulting from delay of delivery, for loss of profits, data, business or goodwill, for business interruption, or any other commercial damages or losses, arising out of or related to this agreement or your use or inability to use the service. 267 | 268 | 269 | Deliverables summary 270 | -------------------- 271 | 272 | Please apply on `Ledger's Listing Program 273 | `_: 274 | 275 | 276 | * Bolos app Release Candidate source code (preferably a git repository) 277 | * Companion app (binaries or package, for Windows/MacOS/Linux) 278 | * Adobe Illustrator templates filled with your icons (see `Design Guidelines`_) 279 | * Contact information (Name, Surname, Legal Entity, URL, email address, phone number) 280 | * Link to tutorial hosted on third party website (see `Third Party Applications Support`_) 281 | * Video of your application running on the Ledger device 282 | 283 | * Verify public address on the Ledger device 284 | * Display transaction information before allowing signature 285 | * Reject a transaction on the Ledger device 286 | * Sign a transaction on the Ledger device 287 | 288 | .. note:: 289 | 290 | 291 | Ledger will review new applications and Pull Requests on a best-effort basis. Submitting an application or a Pull Request isn't a guarantee it will be released. 292 | -------------------------------------------------------------------------------- /source/additional/security_guidelines.rst: -------------------------------------------------------------------------------- 1 | .. Security Guidelines for Ledger Applications documentation master file, created by 2 | sphinx-quickstart on Wed Sep 11 11:09:50 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Developing Secure Ledger Apps 7 | ============================= 8 | 9 | 10 | 11 | Developing applications for Ledger devices (Nano S, X, Blue) is an 12 | intricate process. The security of the user funds relies on the fact 13 | that the application works in a correct and secure manner and that 14 | potential attackers cannot misuse it to extract private data and/or sign 15 | requests which are not authorized by the user. The app should guard 16 | against such attacks because they have a very low entry point -- a 17 | Ledger device attached to a compromised host might be a victim of the 18 | attacker's program sending invalid/non-standard requests to the device. 19 | 20 | This guide is meant to be a summary of all important aspects of Ledger 21 | Apps security and it shall be read by developers before developing an 22 | app for Ledger. The guide is divided into multiple sections, each taking 23 | on a different aspect of security. 24 | 25 | Development practices 26 | --------------------- 27 | 28 | Whenever writing a secure Ledger app, the following advice should not be 29 | taken lightly. 30 | 31 | Code reviews 32 | ~~~~~~~~~~~~ 33 | 34 | We encourage all written code to be peer-reviewed. Importantly, the 35 | review should have at least: 36 | 37 | 1. One reviewer proficient in C and knowing C security weaknesses. 38 | 2. One reviewer with "hacker's mind" (looking at the code from the 39 | perspective of an attacker). 40 | 41 | Security audits 42 | ~~~~~~~~~~~~~~~ 43 | 44 | We encourage third-party security reviews. Note, however, that solid 45 | review takes time and a short review might yield a false sense of 46 | security (especially if the reviewing party does not have an extensive 47 | knowledge of Ledger code specifics). 48 | 49 | Developing First App 50 | ~~~~~~~~~~~~~~~~~~~~ 51 | 52 | Apart from reading developer documentation at 53 | https://ledger.readthedocs.io/en/latest/ we recommend looking at Sia app 54 | https://github.com/LedgerHQ/ledger-app-sia which provides a nice 55 | starting point for an app, including lots of explanatory comments. A 56 | sample of security-wise overly-paranoid app is 57 | https://github.com/LedgerHQ/ledger-app-cardano. 58 | 59 | Cryptography 60 | ------------ 61 | 62 | This section presents general concepts about cryptography development, 63 | but also guidelines specific to the security model of the Ledger 64 | devices. It gives guidelines to: 65 | 66 | * Ensure a potential vulnerability in one application will not cause 67 | damages to other apps. 68 | * Make sure all the operations that manipulate secrets are approved by 69 | the user. 70 | * Restrict the use of these secrets by apps. 71 | 72 | Own crypto primitives 73 | ~~~~~~~~~~~~~~~~~~~~~ 74 | 75 | **You should never roll your own crypto primitives** (including 76 | encryption/derivation schemes, hashing functions, HMAC, etc.) 77 | 78 | Rationale: It is a purpose of BOLOS operating system to perform these in 79 | a secure manner. Importantly, writing your own crypto primitives is 80 | likely to open you to side-channel attacks or other problems. If your 81 | primitive is not supported by BOLOS (e.g., some very new cryptography), 82 | consult with Ledger developers the possibility of including it in the 83 | OS. 84 | 85 | Avoid blindly signing data 86 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 87 | 88 | **You should never allow signing of any attacker-controlled message 89 | unless it has been verified for structural validity. Importantly, you 90 | should never sign a message that might be a hash of transaction.** 91 | 92 | Rationale: If you allow an attacker to blindly sign a message, she can 93 | easily supply a hash of a valid transaction. Your signature could then 94 | be used to send an unauthorized transaction. 95 | 96 | If you want to sign user-supplied "personal" messages, prefix them with 97 | a fixed string (which shouldn't be a valid transaction prefix). It is 98 | also a good practice to include message length in the text to be signed. 99 | Ledger-app-eth has a good example in function 100 | ``handleSignPersonalMessage``. Note that sometimes cryptocurrencies have 101 | a standardized way of signing such personal messages and in that case 102 | you should use the approved scheme. 103 | 104 | Warning: If you allow signing untrusted hashes (while displaying a 105 | prompt to the user), be aware that 106 | 107 | 1. Users do not understand security and could be easily tricked. In 108 | fact, they will probably click through your prompt without thinking 109 | unless you give them explicit "Warning: this is a very unusual 110 | operation. Do not continue unless you know what you are doing" 111 | warning. They might not listen even then 112 | 2. A compromised host might both change hash on the screen and also data 113 | sent to device. This opens the possibility of users signing something 114 | they didn't want to. 115 | 116 | Restrict Apps to Coin-Specific BIP32 Prefix 117 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 118 | 119 | BIP32 paths on which the app can derive keys must be restricted in your 120 | application. The chosen derivation paths must not conflict with existing 121 | paths if the use case differs. 122 | 123 | .. warning:: 124 | Ledger will not sign apps whose BIP32 prefixes have not been properly set. 125 | 126 | Restricting the derivation path can be done by setting the ``--path`` property 127 | in the app Makefile. 128 | 129 | For example, if your application derive keys on the hardened path 44'/60', 130 | specify in your Makefile: 131 | 132 | .. code:: makefile 133 | 134 | APP_LOAD_PARAMS += --path "44'/60'" 135 | 136 | 137 | Derivation can also be restricted to a specific curve using the ``--curve`` 138 | property. Supported curves are ``secp256k1``, ``prime256r1`` and ``ed25519``. 139 | 140 | Several curves and paths can be configured. For example, if your app must derive 141 | keys on paths 44'/535348', 13' and 17', on curves Ed25519 and prime256r1, the 142 | Makefile should contain: 143 | 144 | .. code:: makefile 145 | 146 | APP_LOAD_PARAMS=--curve ed25519 --curve prime256r1 --path "44'/535348'" --path "13'" --path "17'" 147 | 148 | 149 | Rationale: Setting prefixes is crucial, as it limites the amount of damages 150 | an attacker can do if he manages to compromise an application. If a 151 | vulnerability is exploited on a poorly written of backdoored application, an 152 | attacker should not be able to exploit it to extract private keys from other 153 | apps, such as Bitcoin or Ethereum keys. 154 | 155 | .. warning:: 156 | 157 | If your application derives keys on the hardened path 44'/60' then the chainID parameter must be different from 0 or 1. 158 | This is necessary to avoid replaying transactions broadcoast on Ethereum-like chains on Ethereum. 159 | As a general recommendation, and to ensure a good level of privacy for the end user, we recommend to always use the correct coin type in the derivation path as defined in slip44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) 160 | 161 | 162 | Signing/disclosing keys without user approval 163 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 164 | 165 | .. warning:: 166 | 167 | You must always require user approval for signing transactions/messages. 168 | 169 | Rationale: If you do not require user consent for signing important 170 | data, an attacker can use your device as a signing black box and sign 171 | whatever it wants. 172 | 173 | .. note:: 174 | 175 | You might also consider approvals for extracting public keys, as 176 | some users might want extended privacy. 177 | 178 | 1. They might not want to reveal their *root/account* public key, only 179 | address keys 180 | 2. They might not want to reveal address public key until it is required. 181 | (Some cryptocurrencies use addresses that are hash of public keys. It 182 | is therefore enough to send the address to the host). 183 | 184 | Note that there is a trade-off between privacy and usability here. If 185 | you want privacy, it would require a user interaction every time they 186 | want to use Ledger device, as opposed to only interaction while signing 187 | transactions. The behaviour could also be manually set in the application 188 | options. 189 | 190 | Private Key Management 191 | ~~~~~~~~~~~~~~~~~~~~~~ 192 | 193 | **You should minimize the code that works with private (ECDSA, RSA, etc.) or 194 | secret (HMAC, AES, etc.) keys.** Importantly, you should always **clear the 195 | memory** after you use these keys. That includes key data and key objects. 196 | 197 | Leaving parts of private or secret keys lying around in memory is not a 198 | security issue on its own because there is no easy way to extract the content 199 | of RAM on the chip. If a key is left in RAM by an app, another app will not be 200 | able to access it. 201 | 202 | However, if the key has not been properly erased, a security issue could lead 203 | to the leak of this key, even if it is not used anymore. An attacker able to 204 | read arbitrary memory from the app, or execute arbitrary code, will be able 205 | to read the content of the stack segment, hence the parts of the key which have 206 | not been erased. 207 | 208 | A common (and wrong) way of doing this: 209 | 210 | .. code:: c 211 | 212 | uint8_t privateKeyData[64]; 213 | cx_ecfp_private_key_t privateKey; 214 | 215 | os_perso_derive_node_bip32( 216 | tmpCtx.transactionContext.curve, tmpCtx.transactionContext.bip32Path, 217 | tmpCtx.transactionContext.pathLength, privateKeyData, 218 | NULL); 219 | cx_ecfp_init_private_key(tmpCtx.transactionContext.curve, privateKeyData, 220 | 32, &privateKey); 221 | explicit_bzero(privateKeyData, sizeof(privateKeyData)); 222 | 223 | // (later, after privateKey is not needed) 224 | explicit_bzero(&privateKey, sizeof(privateKey)); 225 | 226 | In the happy path, the previous code will correctly clean the memory 227 | once the private key is initialized. Note, however, that this code 228 | **fails to protect private key in case some system call throws (for 229 | example cx_ecfp_init_private_key)**. Correct code should wrap the 230 | clearing in ``BEGIN_TRY { TRY { ... } FINALLY { explicit_bzero() } END_TRY;``. 231 | 232 | Applications where such issues were fixed include 233 | `the ARK app `_ 234 | and `the Solana app `_. 235 | 236 | Be Wary of Untrusted Input 237 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 238 | 239 | Some cryptocurrencies do not have *explicit* fee encoded in the 240 | transaction. In such cases, the app cannot rely on fee value sent from 241 | the host. Instead, it should receive previous UTxOs and check their 242 | output amounts. Note that this usually needs to be done in a separate 243 | step due to memory constraints. Check with BTC/Cardano app design for 244 | this. 245 | 246 | Properly protect data you wish to cache on the host computer 247 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 248 | 249 | Sometimes your app needs to compute over more data than it can fit 250 | inside memory. Taking an example from the previous section, it might not 251 | be easy to store all UTxOs in memory of Ledger. As such, you might break 252 | computation into multiple steps and, for example, verify each UTxO 253 | separately and let the host computer to cache a "certified summary". If 254 | you do this, be aware that 255 | 256 | 1. If the information you want the host to cache is public, you still 257 | need to attach a signature to it so that the host cannot send some 258 | other value later. This could be done with standard HMAC digest. We 259 | would recommend using a temporary (per session) key for this -- 260 | having a per-session HMAC allows you to truncate the digest size 261 | (e.g., you don't need to have HMAC which withstands years of 262 | brute-force attack. Instead, you can balance the digest size against 263 | some reasonable upper bound on how long the session lives (e.g., one 264 | month should be enough)). 265 | 266 | 2. If the information is not public, you need to both encrypt and 267 | provide a signature. Notably, it is not enough to "scramble" the data 268 | by XORing with a random key as this would still allow the attacker to 269 | tamper with the values. (Or even break the scrambling if you re-use 270 | the same key). 271 | 272 | Instead: 273 | 274 | - Encrypt the information with a sufficiently strong cipher 275 | - Provide a digest to avoid tampering with the value 276 | 277 | Do not allow the host to freely manipulate with key-pairs 278 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 279 | 280 | Some cryptocurrencies (notably Monero) need to perform an extensive 281 | calculation with *(public, private)* key-pair spread over multiple APDU 282 | exchanges. If you need to do the same, **do not** allow the attacker to 283 | step out of the protocol. Notably, allowing the attacker to freely 284 | perform key manipulation (e.g., group multiplications, exponentiations, 285 | etc.) could undermine your app security **even if the private key never 286 | leaves the device**. In general, keep an explicit protocol state machine 287 | during the computation. Also, consult with cryptography experts to check 288 | for implications if you misstep from the protocol. 289 | 290 | C is your enemy 291 | --------------- 292 | 293 | Know your C compiler 294 | ~~~~~~~~~~~~~~~~~~~~ 295 | 296 | Ledger apps are written in C. Unlike typical embedded project, the goal 297 | here is to write for a single platform with a single compiler. 298 | 299 | The current supported compiler is clang, and it supports newest language 300 | features (up to C11). This is useful for both development and security. 301 | You should really learn about the new features and use them extensively 302 | as they might help you writing more secure code. 303 | 304 | A random collection of useful features: intermingled declarations and code, 305 | support of ``_Generic``, ``_Static_assert``, ``__builtin_types_compatible_p``, 306 | ``__typeof`` (very useful for safer versions of macros), etc. 307 | 308 | Use safe macro constructs 309 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 310 | 311 | C is a minefield of problems related to pointers. You can alleviate some 312 | of the problems with good macros. However, beware of when they can 313 | fail. For example, take the following code: 314 | 315 | .. code:: c 316 | 317 | #define ARRAY_LEN(a) sizeof(a) / sizeof(a[0]) 318 | 319 | Apart from the "obvious" problem of ARRAY\_LEN macro being written 320 | without external parenthesis, making code such as 321 | 322 | .. code:: c 323 | 324 | (uint8_t) ARRAY_LEN(x) 325 | 326 | compile to what is understood by the compiler as 327 | 328 | .. code:: c 329 | 330 | (uint8_t) sizeof(x) / sizeof(x[0]) 331 | 332 | there is an important problem with this macro. If used in the function 333 | like this 334 | 335 | .. code:: c 336 | 337 | void fn(int x[10]) { 338 | int len = ARRAY_LEN(x) 339 | } 340 | 341 | The result is unexpectedly len=1. The reason is that ``int x[10]`` in 342 | the function header is silently converted into ``int* x`` and the length 343 | is therefore ``sizeof(ptr) / sizeof(int)`` which is indeed 1 on the 344 | platform. You can read more about the problem and how to define a safe 345 | version in 346 | http://zubplot.blogspot.com/2015/01/gcc-is-wonderful-better-arraysize-macro.html 347 | which explains a patch to the Linux kernel to improve safety of its 348 | ARRAY\_SIZE macro. 349 | 350 | Note that similar problems exist, if x is a pointer, with: 351 | 352 | .. code:: c 353 | 354 | memset(x, 0, sizeof(x)) 355 | 356 | In general, if writing macros, try to write them in a way that they will 357 | fail if they get a pointer instead of struct/array. 358 | 359 | Buffer overflows/underflows 360 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 361 | 362 | Buffer overflows and underflows are perhaps the biggest source of 363 | security vulnerabilities in C code. The following example shows a buffer 364 | overflow in (a past version) of one Ledger app. 365 | 366 | .. code:: c 367 | 368 | #define MAX_RAW_TX 200 369 | ... 370 | struct tmpCtx { 371 | ... 372 | uint8_t rawTx[MAX_RAW_TX]; 373 | } transactionContext_t; 374 | 375 | const uint8_t PREFIX[] = {0x00, 0x01, 0x02 ... } // coin-specific signing prefix 376 | 377 | void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, 378 | uint16_t dataLength, volatile unsigned int *flags, 379 | volatile unsigned int *tx) { 380 | ... // (no dataLength validation, we can get up to 255 from APDU) 381 | // Note: we can pass this line with dataLength > 200 382 | if (parseTx(workBuffer, dataLength, &txContent) != USTREAM_FINISHED) { 383 | THROW(0x6A80); 384 | } 385 | ... 386 | memmove(tmpCtx.rawTx, PREFIX, sizeof(PREFIX)); 387 | 388 | // Here is the vulnerability. There should be a check of 389 | // if (!(dataLength + sizeof(SIGN_PREFIX) < MAX_RAW_TX)) THROW(...) 390 | memmove(tmpCtx.transactionContext.rawTx + sizeof(SIGN_PREFIX), workBuffer, dataLength); 391 | } 392 | 393 | In general, there is only a single remedy for buffer overflows - 394 | **always check for available buffer space before writing to memory**. 395 | The best is to not rely on some specific buffer size but instead rely on 396 | sizeof operator. If using sizeof, however, be very careful - if you 397 | ever pass a buffer to a function, you are losing its size! 398 | 399 | .. code:: c 400 | 401 | uint8_t a[100]; 402 | 403 | main() { 404 | sizeof(a); // 100 405 | f(a); 406 | g(a); 407 | } 408 | 409 | void f(uint8_t* x) { 410 | sizeof(x); // 4 411 | } 412 | 413 | void g(uint8_t oops[100]) { 414 | sizeof(oops); // 4 415 | } 416 | 417 | For the extra safery, consider using a SIZEOF macro defined similarly to 418 | https://github.com/LedgerHQ/ledger-app-cardano/blob/f578c903c19288495a359a2bc909b39c33ee69ca/src/utils.h#L27 419 | 420 | Be also wary of constructs like 421 | 422 | .. code:: c 423 | 424 | memset(displayAddress, 0, sizeof(fullAddress)); 425 | memmove((void *)displayAddress, tmpCtx.address, 5); 426 | memmove((void *)(displayAddress + 5), "...", 3); 427 | memmove((void *)(displayAddress + 8), tmpCtx.address + addressLength - 4, 4); 428 | 429 | There are several problematic aspects of such code. Apart from 430 | truncating important values (see next sections), this code makes a lot 431 | of assumptions. For example, if addressLength < 4 (maybe some previous 432 | function returns addressLength=0 instead of an error) we get buffer 433 | underflow and copy up to 4 bytes of other memory and display it to the 434 | user. Or a programmer decides to shorten definition of fullAddress below 435 | 13 and we would overwrite memory after the buffer. Finally, this code 436 | uses explicit indexes (e.g., 5, 8=5+3). A better trick would be to have 437 | a safe helper macro: 438 | 439 | .. code:: c 440 | 441 | #define APPEND(ptr, end, from, len) \ 442 | do { \ 443 | if (ptr + len >= end || len < 0) THROW(); // not enough space \ 444 | memcpy(ptr, from, len); \ 445 | ptr += len; \ 446 | } while(0) 447 | 448 | char* ptr_begin = displayAddress; 449 | char* ptr_end = displayAddress + sizeof(displayAddress); // points behind buffer 450 | APPEND(ptr_begin, ptr_end, tmpCtx.address, 5); // we should also assert addressLength>5 451 | APPEND(ptr_begin, ptr_end, "...", 3); // Note, we still have explicit size here 452 | APPEND(ptr_begin, ptr_end, tmpCtx.address - 4, 4); // Note: another assert 453 | 454 | Finally, you can use SPRINTF macro from 455 | ``sdk/include/os_io_seproxyhal.h`` but be aware that the definition is 456 | 457 | .. code:: c 458 | 459 | #define SPRINTF(strbuf, ...) snprintf(strbuf, sizeof(strbuf), __VA_ARGS__) 460 | 461 | so the above warning about passing pointers instead of arrays applies to 462 | it. 463 | 464 | Integer overflows/underflows 465 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 466 | 467 | Integer overflows go hand in hand with buffer overflows. In fact, they 468 | can cause serious buffer overflows. Consider following code where a 469 | numeric underflow causes buffer overflow of 64kB! 470 | 471 | .. code:: c 472 | 473 | void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, 474 | uint16_t dataLength, volatile unsigned int *flags, 475 | volatile unsigned int *tx) 476 | { 477 | uint32_t i; 478 | 479 | // here we don't check if dataLength > 0 so we might be reading behind the buffer 480 | tmpCtx.transactionContext.pathLength = workBuffer[0]; 481 | if ((tmpCtx.transactionContext.pathLength < 0x01) || 482 | (tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) 483 | { 484 | PRINTF("Invalid path\n"); 485 | THROW(0x6a80); 486 | } 487 | workBuffer++; 488 | dataLength--; 489 | for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) 490 | { 491 | tmpCtx.transactionContext.bip32Path[i] = 492 | (workBuffer[0] << 24) | (workBuffer[1] << 16) | 493 | (workBuffer[2] << 8) | (workBuffer[3]); 494 | workBuffer += 4; 495 | // here we again blindly assume dataLength >= 4 496 | dataLength -= 4; 497 | } 498 | 499 | initTxContext(&txProcessingCtx, &sha256, &dataSha256, &txContent, N_storage.dataAllowed); 500 | // if we sent APDU with dataLength=0 at the beginning, we would end up with dataLength ~ 64kB here 501 | txResult = parseTx(&txProcessingCtx, workBuffer, dataLength); 502 | ... 503 | } 504 | 505 | As a general rule, be very careful about variables which might overflow 506 | or underflow. If possible, use bigger types that can accommodate the 507 | arithmetic operations you need to perform. For buffer sizes, prefer 508 | unsigned types -- that way, you can easily check both overflow and 509 | underflow in one go, i.e. 510 | 511 | .. code:: c 512 | 513 | void f(uint8_t* buf, size_t bufSize) { // size_t is unsigned 514 | if (bufSize < REASONABLE_SIZE) THROW(); // guards both against underflow and overflow! 515 | } 516 | 517 | Data Truncation 518 | ~~~~~~~~~~~~~~~ 519 | 520 | Speaking of safely formatting data, be wary of truncated values. 521 | Importantly, make sure you do not truncate any important data when 522 | displaying on the Ledger screen. 523 | 524 | Example 1: Truncating tx hash from 525 | "f6954eb23ecd1d64c782e6d6c32fad2876003ae92986606585ae7187470d5e04" to 526 | "f695...5e04" might look nice for the users but this effectively reduces 527 | the security of hash and an attacker can now easily try to create a hash 528 | collision. Instead, prefer scrolling/paging of long such important 529 | values. 530 | 531 | Example 2: Raise errors instead of truncation 532 | 533 | .. code:: c 534 | 535 | int tmp[10]; // max 10 digits, right? 536 | 537 | uint32_t amount = 1987654321 538 | SPRINTF(tmp, "%d", amount) // at least we won't get buffer overflow here ... 539 | display(tmp) // but we display an empty screen! 540 | 541 | // but it could be worse 542 | // with bad custom formatting function we could get 543 | format_amount(tmp, SIZEOF(tmp), amount) // "198765432" or "987654321" 544 | 545 | Stack overflow 546 | ~~~~~~~~~~~~~~ 547 | 548 | You application has only a limited size (about ~700B) of stack. That is 549 | one of the reasons why stack cookies are not supported yet on the platform. 550 | 551 | Given the memory constraints, BOLOS OS does not have memory mapping which 552 | would protect from stack overflow errors. As a result, it is very easy to 553 | consume more stack space and overwrite the end of your data. 554 | 555 | Recommendation: 556 | 557 | Enable ``DEFINES += HAVE_BOLOS_APP_STACK_CANARY`` in your Makefile. This 558 | will help you detect stack overflows during app development. If overflow 559 | is detected, the app will reboot the device. Note that the overflow check 560 | happens only on the next I/O. This means that the protection is not instant 561 | and an attacker might avoid the canary check: this option is not a security 562 | feature, and has been added to analyze the stack usage during testing 563 | process. 564 | 565 | Optimizations 566 | ~~~~~~~~~~~~~ 567 | 568 | Do not clear sensitive data with for-loops or other techniques. Do not 569 | user ``memset`` or ``bzero`` to clear sensitive data: it could be 570 | optimized and removed by the compiler. 571 | 572 | Recommendation: Use ``explicit_bzero`` which guarantees that the 573 | compiler will not remove the erasure. (See 574 | https://www.owasp.org/index.php/Insecure\_Compiler\_Optimization for an 575 | example of how things could go wrong.) 576 | 577 | Business logic problems 578 | ----------------------- 579 | 580 | Swallowing errors & half-updated states 581 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 582 | 583 | It goes without saying that you should check return value of functions 584 | for any errors. Fortunately, BOLOS throws an error if something goes 585 | wrong and you might want to do the same instead of relying on error 586 | codes. 587 | 588 | There is, however, a more indirect problem. Some BOLOS apps silently 589 | catch exceptions in the main event loop without erasing app memory. This 590 | could lead into a following insidious bug: 591 | 592 | .. code:: c 593 | 594 | uint16_t totalSize; 595 | uint8_t totalBuf[1000]; 596 | 597 | void signTx(uint8_t p1, uint8_t p2, uint8_t* data, uint16_t dataSize) { 598 | if (p1 == P1_INIT) { 599 | totalSize = 0; 600 | } 601 | 602 | uint8_t* ptr = totalBuf[totalSize]; 603 | totalSize += dataSize; 604 | if (totalSize > SIZEOF(totalBuf)) THROW(ERR); 605 | memcpy(ptr, data, dataSize); 606 | 607 | if (p2 == P2_CONTINUE) { 608 | THROW(0x9000); // early exit with success 609 | } 610 | do_something(); 611 | } 612 | 613 | An attacker might do 614 | 615 | 1. SignTx(INIT, 100 bytes of data) // OK 616 | 617 | 2. SignTx(CONTINUE, 100 bytes of data) // OK 618 | 619 | ... 620 | 621 | 10. SignTx(CONTINUE, 100 bytes of data) // OK 622 | 623 | 11. SignTx(CONTINUE, 100 bytes of data) // throws 624 | 625 | … 626 | 627 | 5. SignTx(CONTINUE, 100 bytes of data) // throws 628 | 629 | 6. SignTx(CONTINUE, 100 bytes of data) **// writes to data[-64..36]** 630 | 631 | The problem here is that the app state is not updated in a 632 | "transactional" manner and attacker exploits this. 633 | 634 | Recommendations: Try to not affect global state before you throw. Many 635 | times you can use a scratch memory to assemble result and only then do 636 | ``memmove`` to write the result. Even better, wipe memory/reboot device 637 | on exceptions to destroy any half-updated app states. 638 | 639 | Too lenient parsing of transactions 640 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 641 | 642 | It might happen that your transaction parsing is too lenient. 643 | Importantly, this might cause problems if the transaction serialization 644 | spec is ambiguous and different clients might interpret it differently. 645 | For example, if a field might be repeated one parser might take the 646 | first value while another one a second. In general, lenient tx 647 | serialization spec should not happen (and if so, the cryptocurrency has 648 | bigger concerns than Ledger wallet). 649 | 650 | However, even if the network nodes are strict with the serialization 651 | checking, you should not slack off on your part. Any ambiguity in 652 | parsing adds an attacker a leverage point once it finds some other 653 | vulnerability. 654 | 655 | Recommendation: Be as strict as possible with transaction parsing. 656 | Accept only fields which are in normalized form. If possible, avoid 657 | repeated fields and accept fields only in a pre-described order. 658 | 659 | Note: you can even go further and do not parse transaction on the device 660 | at all. Instead, just send the data in a custom format and let both the 661 | app and host serialize the transaction on their own with the app 662 | revealing (and signing) only the serialized hash. This way you can avoid 663 | bugs in parsing code and be sure both the host wallet and the app agree 664 | perfectly on the content of the transaction. 665 | 666 | Protect Against "Instruction Change" Attacks 667 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 668 | 669 | Ledger applications live on a secure chip which is very limited in terms 670 | of its memory and communication channel. This brings in an interesting 671 | problem -- the application might not be able to perform all its work in 672 | a single request. Instead, the work will need to be spread over multiple 673 | requests. Whenever this happens, the application needs to be protected 674 | against attacker mixing multiple non-related (or even related) requests. 675 | 676 | If your application contains at least one instruction which works over 677 | multiple APDU exchanges (e.g., having ``P1_INIT/P1_CONTINUE`` flag in 678 | the standard application "terminology"), you have to protect it from 679 | interference. Common attack scenarios: 680 | 681 | Example: Two multi-APDU instructions 682 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 683 | 684 | Let's say you have SignTx and SignMessage, both sharing the same global 685 | ``hash`` variable, both instructions working over multiple APDU 686 | exchanges.The attacker might now call 687 | 688 | 1. SignMessage(INIT) 689 | 2. SignTx(INIT) 690 | 3. SignMessage(CONTINUE) with data (no finish yet) 691 | 4. SignTx(CONTINUE) with data (finish) 692 | 693 | At this point, the global memory might be in an inconsistent state (for 694 | example, the SignTx hash does contain a different hash than it should 695 | be). This might lead to an easy attack. 696 | 697 | Example: Single multi-APDU instruction 698 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 699 | 700 | Even if you have only a single instruction with multiple APDU exchanges, 701 | an attacker might gain some leverage. Let's say you have roughly 702 | 703 | .. code:: c 704 | 705 | struct pubkey_ctx { 706 | int[10] bip32_path; 707 | int bip32_path_len; 708 | } 709 | 710 | struct sign_ctx { 711 | hash_ctx hash; 712 | // some other data 713 | } 714 | 715 | union { 716 | pubkey_ctx pubkey; 717 | sign_ctx signTx; 718 | } ctx; 719 | 720 | To overwrite the hash context with an exact chosen value. 721 | 722 | Example: "Self"-attack on a single multi-APDU instruction 723 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 724 | 725 | You don't even need two instructions to perform a variation of the 726 | attack. Suppose your code goes along these lines 727 | 728 | .. code:: c 729 | 730 | void signTx () { 731 | if (p1 == P1_INIT) { 732 | initialize_half_of_my_state() 733 | if (some_bad_input) THROW(error) 734 | initialize_rest_of_the_state 735 | } else { 736 | // do something 737 | } 738 | } 739 | 740 | Assuming that you do not reset state on exceptions, this might happen 741 | 742 | 1. signTx(INIT, valid data) 743 | 2. signTx(CONTINUE, valid data) 744 | 3. signTx(INIT, data which throws) 745 | 4. signTx(CONTINUE, more data) 746 | 747 | An attacker now managed to reset half of your state (maybe tx length) 748 | but not the rest of it (maybe tx hash) which might allow it to attack 749 | your code. 750 | 751 | Obviously, there are many variations of this basic scheme and an utmost 752 | care needs to be taken here. The recommendation here is: 753 | 754 | 1. Do not allow mixing of instructions 755 | 2. Within instruction, keep an explicit state machine of what is allowed 756 | to happen next) 757 | 3. Clear memory on exceptions 758 | 759 | Use explicit state machines 760 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 761 | 762 | Whenever a host is required to perform certain actions in a specific 763 | order, be sure to explicitly track the state and verify that the next 764 | step is consistent. Good examples of what might need to be checked 765 | 766 | 1. If host claims some number of tx inputs/outputs, make sure you 767 | receive exactly that amount, not more and not less 768 | 2. If the host needs to send multiple transaction inputs and outputs and 769 | you have to process inputs before outputs, make sure the host cannot 770 | send additional input after it received an output. 771 | 3. Check that once you finished an action (signing), the attacker cannot 772 | resume with additional data (which might be empty). This is 773 | important, because usually signing "closes" some hash contexts (or 774 | destroy some other data) and re-running 775 | ``SignTx(CONTINUE, empty data)`` might, therefore, yield either crash 776 | or produce a signature of some different data. In general, after 777 | finishing a request you should wipe the context variable 778 | 4. If you do not reset UI after sending APDU (for example, because you 779 | displayed an address and now you are waiting for another APDU 780 | containing tx amount), make sure your button handlers fire just once 781 | -- a user might press the buttons multiple times. A general 782 | recommendation would be to always reset UI with APDU response. 783 | Additionally, you can guard your app against itself (and against bad 784 | SDK) with tracking whether it should be in IO/UI phase and assert on 785 | it in APDU/UI handlers. 786 | 787 | An (somewhat contrived) example of problematic button handlers 788 | 789 | .. code:: c 790 | 791 | void handle_sign_message(...) { 792 | ... // validations 793 | if (!is_last_apdu) { 794 | cx_hash(CX_CONTINUE, ctx->hash, data); 795 | else { 796 | memcpy(ctx->last_part, data); 797 | flags *= IO_ASYNCH; 798 | display_tx_prompt(); 799 | } 800 | } 801 | 802 | unsigned int io_seproxyhal_touch_tx_ok() { 803 | // for some reason we modify ctx state here 804 | cx_hash(CX_LAST, ctx->last_part); 805 | sign(ctx->last_part); 806 | // now do io_exchange 807 | 808 | // Warning: this might throw (host might do something weird with USB) 809 | // -> user will press the button second time 810 | // -> we do another round of cx_hash -> efficiently signing 811 | io_exchange(....); 812 | // now reset UI 813 | ui_idle(); // <-- this line resets button callback 814 | } 815 | 816 | A fully resilient solution would be 817 | 818 | .. code:: c 819 | 820 | void display_tx_prompt() { 821 | tx_prompt_handled = false; 822 | ... 823 | } 824 | 825 | unsigned int io_seproxyhal_touch_tx_ok() { 826 | assert(!tx_prompt_handled); 827 | tx_prompt_handled = true; 828 | ... 829 | } 830 | 831 | unsigned int io_seproxyhal_touch_tx_cancel() { 832 | assert(!tx_prompt_handled); 833 | tx_prompt_handled = true; 834 | ... 835 | } 836 | 837 | But such a solution is needed only if tx\_ok or tx\_cancel modify 838 | context/global variables before calling ui\_idle(). (As a side note, if 839 | your\_\_ok()/\_\_cancel() handler both 1) do not check whether the 840 | memory is cleared, but 2) clear the memory inside the handler; make sure 841 | that memclear happens after calling ui\_idle()). 842 | 843 | Note: If not guarded properly, an attacker might try a following line of 844 | attack: 845 | 846 | 1. Send transaction which is not what user wanted 847 | 2. User realizes that the transaction is wrong and presses reject 848 | 3. Attacker hogs ``io_exchange`` (presumably by doing some bad things to 849 | USB communication) 850 | 4. User tries again a few more times, thinks that the UI is broken and 851 | the app hanged. The callbacks are fired again and again but 852 | ``io_exchange`` still throws 853 | 5. At this point in time, a desperate user might click on "confirm" 854 | button to unblock the UI. If an attacker can guess this time, she can 855 | un-hog USB and receive confirm callback 856 | -------------------------------------------------------------------------------- /source/background/application_isolation.rst: -------------------------------------------------------------------------------- 1 | Application Isolation 2 | ===================== 3 | 4 | So how do I know that the apps I'm running on my Ledger Nano S are doing what I 5 | intend them to do? What protects me from getting a virus on my Ledger Nano S? 6 | 7 | Ledger solves these problems by utilizing the application isolation technology 8 | available in the Secure Element - the ARM `Memory Protection Unit 9 | `_ 10 | and `Operating Modes 11 | `_. 12 | The Memory Protection Unit is used to natively isolate each app to its own 13 | memory region, and apps run in User mode whereas the operating system runs in 14 | Supervisor mode. By restricting the device to a single-task model where only one 15 | app can run at a time, and each app is isolated from the rest of the device, 16 | apps are prevented from accessing your cryptographic secrets on the device 17 | unless you explicitly give them permission to. 18 | 19 | The access that applications have to cryptographic secrets managed by the 20 | operating system can be configured when loading an application onto the device. 21 | Instead of accessing secrets like the device's master seed directly, 22 | applications instead have to request the operating system to derive a node from 23 | the master seed by providing the operating system with a path to the requested 24 | node. When the application is loaded, the BIP 32 paths that the application is 25 | permitted to derive nodes from are specified. If the application requests the 26 | operating system to derive a node on a path that it is not permitted to use, the 27 | request is denied. In this way, many different applications can be loaded onto 28 | the device, and each of them can be restricted to a specific subtree of the HD 29 | tree depending on the application's purpose. This process of requesting the 30 | operating system to perform an operation as Supervisor is called a syscall, and 31 | we'll discuss it further in :doc:`later sections `. 32 | 33 | Still, the importance of only installing apps that you can trust should not be 34 | understated. In the next section, we'll talk about how Ledger's operating system 35 | provides attestation features that allow the device to verify the authenticity 36 | of the apps that you're installing by checking a digital signature that is sent 37 | along with apps when they're loaded onto the device. Additionally, we'll discuss 38 | how Ledger's platform is open-source friendly which enables you to review the 39 | apps that you're using to manage your assets. 40 | -------------------------------------------------------------------------------- /source/background/hd_keys.rst: -------------------------------------------------------------------------------- 1 | HD Key Generation 2 | ================= 3 | 4 | In :doc:`the previous section ` we discussed how Ledger devices use 5 | a master 24-word mnemonic seed to derive a theoretically infinite number of 6 | cryptographic secrets. Though it might seem impossible at first glance, this can 7 | be done using nothing more than some mathematical sorcery. The process used to 8 | do this is called hierarchical deterministic (HD) key generation. 9 | 10 | The process for HD key generation used by all Ledger devices (and many other HD 11 | wallets) is defined by `BIP 32 12 | `_. 13 | 14 | Here's how it works. 15 | 16 | The Master Node 17 | --------------- 18 | 19 | Hierarchical deterministic key generation involves creating a theoretically 20 | infinite tree of cryptographic secrets. The root of this tree from which 21 | everything is generated is called the master node. The master node is derived 22 | directly from the master binary seed described in the previous section using 23 | HMAC-SHA512. The master node of your wallet is all the information you need to 24 | access an infinite hierarchy of private keys. As such, you should take good care 25 | to keep your mnemonic seed safe. 26 | 27 | Passphrases 28 | ^^^^^^^^^^^ 29 | 30 | Passphrases are a standard feature of BIP 39 supported by many HD wallets. 31 | Passphrases are an optional way of adding additional data to the master seed 32 | before deriving the master node of the HD wallet. By specifying a different 33 | passphrase (or no passphrase at all), the value of the master node is completely 34 | changed. As you will discover as you read the rest of this section, changing the 35 | master node of the HD wallet completely changes all of the information derived 36 | from it (for example, your Bitcoin addresses). In this way, you can keep the 37 | same master seed on a device, but use different passphrases to access completely 38 | unique, separated wallets. 39 | 40 | An Infinite Tree 41 | ---------------- 42 | 43 | Descending from the master node is a tree of an infinite number of private keys. 44 | All you need to determine a particular key is the master node (your mnemonic 45 | seed) and the location of the key in the tree (called its "path"). This tree is 46 | created using an incredibly powerful algorithm defined by BIP 32 called the CKD 47 | function. All you need to know about this magical algorithm is that it can be 48 | used to calculate any node on the HD tree given the node's position and the 49 | value of the master node. Essentially, the CKD function is applied to the master 50 | node a number of times in order to "scramble" its bits and output a brand new 51 | node. This algorithm is magical because **it is impossible to reverse**. Given a 52 | private key on your tree, it is impossible to go backwards up the tree and 53 | determine your master node.\ [#]_ 54 | 55 | Child Key Derivation Function 56 | ----------------------------- 57 | 58 | The HD tree is made up of "nodes". Using the CKD function, many "child" nodes 59 | can be derived from a single "parent" node. Each node contains three pieces of 60 | information: a private key, a public key, and a chain code. In the case of a 61 | cryptocurrency wallet, the private key is the part that is used to sign 62 | transactions and the public key is used to generate the corresponding 63 | cryptocurrency address. The node's chain code is an extra little bit to prevent 64 | someone from determining the children of a node using only the node's public and 65 | private keys. 66 | 67 | The CKD function has been designed in a way that provides great flexibility in 68 | the way child nodes are derived. Specifically, instead of requiring the public 69 | key, private key, and chain code to derive a child node, the CKD function can be 70 | used to derive child public keys from the parent public key and child private 71 | keys from the parent private key. Additionally, BIP 32 defines the concept of 72 | "hardened" child nodes. If a child node is "hardened", then its public key 73 | cannot be determined from its parent node's public key. 74 | 75 | These are the transformations that the CKD function can perform: 76 | 77 | * parent private key & chain code ➞ child private key & chain code 78 | * parent public key & chain code ➞ child public key & chain code (unless the 79 | child node is hardened) 80 | * parent private key & chain code ➞ child public key & chain code 81 | 82 | Note that it is impossible to derive a child private key from a parent public 83 | key. This model has some interesting consequences, mainly that the parent public 84 | key and chain code can be shared which allows someone to derive all child public 85 | keys (unless the child nodes are hardened), but no private keys. 86 | 87 | For example, this model can be used to facilitate the process of auditing an HD 88 | wallet. By sharing the public key and chain code of all accounts in an HD 89 | wallet, one can give an auditor the ability to view all addresses in the wallet 90 | (without having the associated private keys). As such, the auditor could 91 | determine what money is going where, without having access to any private keys, 92 | meaning the auditor couldn't sign any transactions. We'll talk about what 93 | "accounts" are in the next section. 94 | 95 | For a more detailed list and explanation of some of the use-cases made possible 96 | by this model, see `this section 97 | `_ of 98 | the BIP 32 specification. 99 | 100 | In the next section, :doc:`hd_use_cases`, we'll talk about how all of these 101 | features are used by HD wallets and other applications. 102 | 103 | .. tip:: 104 | 105 | If you'd like to play with BIP 39 mnemonics or BIP 32 derivation on a 106 | computer, take a look at this tool: https://iancoleman.io/bip39/. 107 | 108 | .. rubric:: Footnotes 109 | 110 | .. [#] 111 | 112 | Technically it isn't impossible to determine a node given the child node and 113 | the corresponding index, but there is no known attack to do this faster than 114 | a properly executed brute-force attack. See `this section of BIP 32 115 | `_ 116 | for details. 117 | -------------------------------------------------------------------------------- /source/background/hd_use_cases.rst: -------------------------------------------------------------------------------- 1 | Applications of HD Trees 2 | ======================== 3 | 4 | In the previous section, :doc:`hd_keys`, we described how an infinite number of 5 | cryptographic secrets can be generated from a single master seed. In this 6 | section, we'll talk about how Ledger applies this concept to develop 7 | applications for our :doc:`personal security devices 8 | ` that are lightweight and easily recoverable. 9 | 10 | Coin Types 11 | ---------- 12 | 13 | So how are HD trees useful? Simple: developers of different cryptocurrencies got 14 | together and `reserved a space on the tree 15 | `_. 16 | Developers for these cryptocurrencies each specified which "location" on the 17 | tree they wanted users to store their private keys (called the coin's "path"). 18 | This path is public information, because nobody can determine the actual value 19 | of your keys without knowing your master node (your mnemonic seed). The paths 20 | that correspond to various cryptocurrencies, and the paths used to derive 21 | cryptocurrency addresses and private keys, are defined by `BIP 44 22 | `_ (which in 23 | turn defers coin type registration to `SLIP 44 24 | `_). 25 | 26 | For each cryptocurrency, there is a node on the tree where all of the keys for 27 | that coin begin (from this point on, we'll call this the "coin type root node", 28 | for lack of a better term). Since this is a hierarchical deterministic tree, we 29 | can apply the same rules to that coin type root node as we applied to the master 30 | node. Just as an infinite tree of keys descended from the master node, there is 31 | also an infinite tree of keys descending from the coin type root node. This 32 | means that if you have a 24-word mnemonic seed, even if you don't use Bitcoin, 33 | you have a virtually infinite\ [#]_ number of Bitcoin addresses. You have a 34 | virtually infinite number of Ethereum addresses, too. 35 | 36 | .. warning:: 37 | 38 | In the Ledger Ethereum Wallet desktop app, addresses are not derived 39 | according to BIP 44. Instead of using the derivation path ``m / 44' / 60' / 40 | account' / change / address_index`` (as defined by BIP 44 for Ethereum), the 41 | Ledger Ethereum Wallet desktop app uses the derivation path ``m / 44' / 60' / 42 | 0' / address_index``. 43 | 44 | How does my wallet know which addresses I've used? 45 | -------------------------------------------------- 46 | 47 | In most BIP 44-compliant HD wallet programs (including the Ledger Bitcoin Wallet 48 | desktop app) your addresses are split into "accounts". You can split your coins 49 | across multiple accounts in the same way you might with multiple bank accounts. 50 | You can have an account for savings, an account for donations, an account for 51 | common expenses, et cetera. Within each of these accounts, there are two 52 | virtually infinite "chains" of addresses: an external chain and an internal 53 | chain (commonly called the "change address" chain). Each of the addresses in 54 | these chains are given numbers (called the "address index") starting at 0. 55 | 56 | When your wallet software starts up for the first time, it searches the 57 | blockchain for transactions involving address number 0 for each address chain. 58 | If it finds any transactions, then the address is displayed by the wallet 59 | software and the wallet searches for transactions involving address number 1. 60 | This process continues until the wallet finds an address that you haven't used 61 | yet. It displays this address to you, then stops searching for more addresses in 62 | the chain, making the assumption that no more of them have been used yet.\ [#]_ 63 | 64 | In this way, all of the important information about your transaction history is 65 | stored in the blockchain, so none of it has to be stored in the hardware wallet 66 | itself. If your wallet is destroyed / reset, all you need to do is input your 67 | 24-word mnemonic seed into a new HD wallet and the wallet will search the public 68 | blockchain for all of the information it needs. 69 | 70 | Summary 71 | ------- 72 | 73 | .. figure:: images/where_are_my_assets.png 74 | :align: center 75 | 76 | A diagram of a hierarchical deterministic wallet; everything in the box 77 | labelled "hierarchical deterministic tree" is recoverable if your wallet is 78 | lost, destroyed, or reset because it is all derived from the master seed 79 | 80 | An HD wallet has a few very important properties, so let's reiterate: 81 | 82 | * The "tree" that makes up an HD wallet is generated using nothing more than 83 | your 24-word mnemonic seed. This is all you need to generate all of your 84 | cryptocurrency addresses, and sign transactions. 85 | * No private keys need to be saved, anywhere. Even if you continue to receive 86 | Bitcoins to more and more of your addresses, you don't need to save any of 87 | those private keys anywhere. This is because they were there all along, in the 88 | HD tree. 89 | * The HD wallet standards used by Ledger (BIPs 32, 39, and 44) are industry 90 | standards. Your 24-word mnemonic seed will work with any other HD wallet that 91 | supports these standards, not just with Ledger wallets. 92 | 93 | Going Beyond Cryptocurrencies 94 | ----------------------------- 95 | 96 | Hierarchical deterministic wallets are useful for a lot more than just securing 97 | assets on blockchains. You could also expand this concept and use your master 98 | seed to derive passwords, PGP keys, SSH keys, et cetera. 99 | 100 | For example, Ledger is currently developing a `Password Manager app 101 | `_. It is currently 102 | available for the Ledger Nano S in an early alpha form by clicking "show 103 | developer items" in the `Ledger Manager 104 | `_. 105 | 106 | The password manager app works by converting a node on the HD tree into a text 107 | password that looks like random gibberish. When you create a new password, you 108 | must enter a label for the password (for example: "Google", "Dropbox", 109 | "Twitter", etc.). **The location of a password's node on the HD tree is encoded 110 | in the corresponding password's label.** When you ask the Password Manager app 111 | for your password, it uses the password's label to locate a specific node on the 112 | HD tree, and then it converts that node into a text password. You cannot specify 113 | your own passwords to use, the passwords are generated for you. 114 | 115 | .. rubric:: Footnotes 116 | 117 | .. [#] 118 | 119 | In this case, virtually infinite = 2\ :sup:`63` = 9 223 372 036 854 775 808. 120 | 121 | .. [#] 122 | 123 | In this example, we described a wallet that operates with a `gap limit 124 | `_ 125 | of 1. Different wallet software use different values, but BIP 44 currently 126 | recommends a gap limit of 20. 127 | -------------------------------------------------------------------------------- /source/background/images/where_are_my_assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/background/images/where_are_my_assets.png -------------------------------------------------------------------------------- /source/background/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | In this chapter, we'll first provide some background information about personal 5 | security devices and hierarchical deterministic wallets. Then, we'll introduce 6 | the application isolation technology that helps make Ledger devices secure and 7 | open-source friendly. 8 | -------------------------------------------------------------------------------- /source/background/master_seed.rst: -------------------------------------------------------------------------------- 1 | The Master Seed 2 | =============== 3 | 4 | Applications running on Ledger :doc:`personal security devices 5 | ` are designed to be lightweight and easily 6 | recoverable. Ledger achieves both of these goals by using **hierarchical 7 | deterministic key generation**. Hierarchical deterministic key generation is 8 | used by applications to derive a theoretically infinite number of cryptographic 9 | secrets from a single master seed. In this way, your cryptocurrency private 10 | keys, passwords, and other cryptographic secrets can all be determined and 11 | intrinsically "stored" in a single master seed. Because of this, the device's 12 | apps don't have to store their own private keys, because they can all be 13 | generated on-demand by the device from the master seed. This means that if your 14 | device is lost, destroyed, or reset then all you need is your master seed to 15 | recover your secrets. In addition, an application that supports this scheme can 16 | be deleted and reinstalled without losing any secure data or assets. Your master 17 | seed is randomly generated for you when you first set up your Ledger device, and 18 | then you just need to write it down to allow you to recover your device in the 19 | future. 20 | 21 | Generation and Serialization 22 | ---------------------------- 23 | 24 | The master seed is the key to your cryptographic secrets. As such, the master 25 | seed should be something that is long and nearly impossible for anyone to guess. 26 | Your master seed isn't like a password or a PIN (Ledger devices already have 27 | PINs to protect access to them), instead it's the root of all of your 28 | cryptographic secrets. You only need to access it when you first write it down 29 | on paper when your device randomly generates it for the first time, or in the 30 | future if you have to recover your device. 31 | 32 | Ledger uses a standard called `BIP 39 33 | `_ for the 34 | generation and interpretation of the master seed on all of our devices. BIP 39 35 | is an industry standard used by many other hierarchical deterministic wallets. 36 | The exact type of BIP 39 seed used by Ledger devices by default is a 24-word 37 | mnemonic that consists of only the 2048 words from the `BIP 39 English wordlist 38 | `_. Here's how 39 | a BIP 39 24-word mnemonic seed is generated: 40 | 41 | 1. The device generates a sequence of 256 random bits using the true random 42 | number generator (TRNG) built into the device's Secure Element. 43 | 2. The first 8 bits of the SHA-256 hash of the initial 256 bits is appended to 44 | the end, giving us 264 bits. 45 | 3. All 264 bits are split into 24 groups of 11 bits. 46 | 4. Each group of 11 bits is interpreted as a number in the range 0 - 2047, which 47 | serves as an index to the BIP 39 wordlist, giving us 24 words. 48 | 49 | The result of this process is that your device will generate a single mnemonic 50 | seed out of 2\ :sup:`256` possible mnemonic seeds (That's one of 115 792 089 237 51 | 316 195 423 570 985 008 687 907 853 269 984 665 640 564 039 457 584 007 913 129 52 | 639 936 possible mnemonic seeds). Note that while the first 23 words are 53 | completely random, the final word was derived from 3 random bits and 8 54 | calculated bits from the SHA-256 hash. This means that the final word can act 55 | like a checksum - if you input an incorrect seed into the device while 56 | recovering it, it is possible for the device to detect that the inputted seed is 57 | invalid. 58 | 59 | .. note:: 60 | 61 | **Can someone guess my seed?** There are 2\ :sup:`256` different possible 62 | 24-word mnemonic seeds. For comparison, the number of atoms on Earth is 63 | estimated to be around 2\ :sup:`166`. Just let that sink in for a second. The 64 | chance of someone else being able to guess your seed is astronomically small, 65 | to say the least. 66 | 67 | But all we have here is a sequence of 24 words, how can the device use this as a 68 | cryptographic secret? 69 | 70 | After the 24-word mnemonic is generated, it has to be converted into a binary 71 | seed by the device (this process is called serialization). This is done using 72 | the PBKDF2-HMAC-SHA512 key derivation function to convert your mnemonic seed 73 | **and an optional passphrase of your choosing** into a 512 bit binary seed. This 74 | BIP 39 passphrase can be `set on your device 75 | `_ 76 | through the Settings menu, and it can be changed at will without resetting your 77 | device (in fact, you can have multiple passphrases loaded onto the device at 78 | once if you wish). By changing the passphrase, the resulting 512 bit binary seed 79 | is completely changed. 80 | 81 | This 512 bit binary seed is the root of your device's cryptographic secrets. 82 | Every cryptographic secret that your device needs (cryptocurrency private keys & 83 | addresses, passwords, etc.) can be derived from this 512 bit binary seed. We'll 84 | explore how an infinite number of cryptographic secrets can be derived from this 85 | one seed in the next section, :doc:`hd_keys`. 86 | -------------------------------------------------------------------------------- /source/background/personal_security_devices.rst: -------------------------------------------------------------------------------- 1 | Personal Security Devices 2 | ========================= 3 | 4 | Personal security devices are designed to isolate cryptographic secrets (like 5 | PGP or Bitcoin private keys) from your potentially insecure computer which has 6 | known vulnerabilities. Storing cryptographic secrets on a physical medium that 7 | cannot be infected with a virus such as writing them on a piece of paper (or 8 | storing them on an encrypted drive) is secure until you need to use your funds. 9 | The instant you need to transfer your funds, you need to load your private keys 10 | onto your computer to sign the transaction and as such you expose them to 11 | potential malware (unless you'd like to perform the cryptographic operations 12 | necessary to sign the transaction by hand, which is far from convenient, to say 13 | the least). This is where personal security devices come in - they don't just 14 | store your cryptographic secrets safely, they also allow you to perform 15 | operations with them (like signing transactions) securely and conveniently. 16 | Ledger devices also generate secrets securely with a large amount of entropy 17 | using an AIS-31 compliant true random number generator (TRNG). As such, it is 18 | more secure to use the device's internally generated secrets rather than 19 | importing a secret from elsewhere which could have been compromised before being 20 | loaded onto the device. 21 | 22 | Ledger leverages Secure Element technology to build personal security devices 23 | for cryptocurrencies and blockchains which provide an interface between humans 24 | and the blockchain world. They keep your private keys secure from hackers by 25 | storing them in a tamper-proof and eavesdropping-proof Secure Element. 26 | Additionally, the Ledger Nano S and Ledger Blue have a screen which serves as a 27 | trusted source of information about your assets as it is controlled by the 28 | device itself, not by potentially vulnerable computer software. 29 | 30 | However, personal security devices aren't intended to be a store of data - 31 | they're a root of trust. Apps for these devices tend to be lightweight apps that 32 | work in conjunction with a host computer. The Secure Element places a limit on 33 | the storage capacity of these devices, so storing data encrypted on a host 34 | computer is preferred over storing data directly on the device. As such, the 35 | device contains a set of private keys that you can use to unlock your data and 36 | assets, without any risk of compromising the security of your assets in the 37 | event that your computer becomes infected with a virus. Applications that 38 | process large amounts of data may not be able to store all of the data on the 39 | device at once. There are two effective solutions to this problem: 1) stream 40 | data through the device while the application processes it (for example, it may 41 | be encrypting / decrypting the data) or 2) derive a secret on the device 42 | (preferably from the master seed) and use it on the computer to process the data 43 | (this is how the `PGP app `_ 44 | works). 45 | 46 | This is an important concept: personal security devices are a secure portal to 47 | your assets, not a bank. If your device gets lost or destroyed, your assets are 48 | still safe. The key to this portal is your "master seed". That brings us to our 49 | next section, :doc:`master_seed`. 50 | -------------------------------------------------------------------------------- /source/bolos/application_environment.rst: -------------------------------------------------------------------------------- 1 | Application Environment 2 | ======================= 3 | 4 | Due to its limited amount of RAM, the Secure Element is designed to only support 5 | one application running at a time. This isolated model implies that once the 6 | application is running, no other application can spuriously disturb the SE-MCU 7 | link. It also means that BOLOS can give the currently running application full 8 | control of I/O with the device's peripherals. This model allowed the BOLOS 9 | architecture to be designed in a way that gives applications as much control 10 | over the device's features as possible. In essence, each application runs in a 11 | "virtual" device and can reconfigure all of the hardware as it pleases. BOLOS 12 | :doc:`isolates the application ` from the 13 | other applications on the device, and restricts access to all areas of flash 14 | memory other than those exclusively allocated for the running application. 15 | 16 | This model has the tremendous advantage of not limiting what the application can 17 | do, however it also implies that every application has to do **all** of the 18 | heavy lifting involved in managing every layer of the transport protocols used 19 | to communicate with the world outside of the SE. Luckily, the SDK implements all 20 | I/O handling that typical applications need to do. However, developers have the 21 | option to customize I/O protocols for more specialized applications. 22 | 23 | .. figure:: images/app_centric_view.png 24 | :alt: Application-centric view 25 | :align: center 26 | 27 | The application-centric view of the BOLOS environment 28 | 29 | The above diagram shows a view of the system as seen by the application. The app 30 | directly accesses multiple peripherals and is the real brain of the device while 31 | it is running. Each box can be seen as a coprocessor, under direct command of 32 | the application. 33 | 34 | Some peripherals not only receive commands from the SE, but also trigger events 35 | which are relayed back to the SE by the MCU. This is the case for buttons, 36 | activated upon user actions, and I/O peripherals which can perform background 37 | communication (for example, the USB controller) or convey requests to be 38 | processed by the application. 39 | 40 | In this model, the application is at the center, and does not rely on any other 41 | embedded co-applications. 42 | 43 | Delegation Model 44 | ---------------- 45 | 46 | .. figure:: images/usb_delegation_overview.png 47 | :alt: USB delegation overview 48 | :align: center 49 | 50 | An overview of the USB delegation model 51 | 52 | Once BOLOS boots the application, BOLOS is not reachable anymore, it only 53 | provides basic services to the application during its execution via system 54 | calls. As a consequence, BOLOS does not process commands sent to the device from 55 | peripherals (like USB) and therefore BOLOS does not play a role in I/O handling. 56 | 57 | Featuring these two key points, applications are in charge on the device. This 58 | allows them to customize not only the display, but user input actions, and by 59 | extension, the way the device is enumerated on USB. If an application requires 60 | Mass Storage emulation, or being seen as a WinUSB peripheral, it’s only a matter 61 | of event handling. 62 | -------------------------------------------------------------------------------- /source/bolos/features.rst: -------------------------------------------------------------------------------- 1 | BOLOS Features 2 | ============== 3 | 4 | In this section, we'll discuss some of the features that are built into BOLOS. 5 | These features are available through the :ref:`dashboard app ` and / 6 | or can be utilized by userspace applications. 7 | 8 | Management of Cryptographic Secrets 9 | ----------------------------------- 10 | 11 | There are two important cryptographic secrets that are stored and managed by 12 | BOLOS that will be discussed in this section: the :term:`Device` keypair (which 13 | is generated in-factory) and the :doc:`BIP 32 master node 14 | ` (which is derived from the user's BIP 39 mnemonic 15 | seed). Both of these secrets are stored by BOLOS and are not directly accessible 16 | to applications for security reasons. The Device keypair can be used indirectly 17 | by applications for purposes of :ref:`application attestation `. 18 | Applications can derive secrets from the BIP 32 master node using a system call 19 | to BOLOS, provided the app was given the appropriate permissions when loaded 20 | onto the device. 21 | 22 | Passphrases in BOLOS 23 | ^^^^^^^^^^^^^^^^^^^^ 24 | 25 | Since firmware version 1.3 on the Ledger Nano S, BOLOS allows users to load 26 | multiple `BIP 39 passphrases 27 | `_ 28 | onto the device at once. As described in :doc:`the previous chapter 29 | `, passphrases are a method to add additional entropy 30 | to the BIP 39 master seed in order to completely change the :doc:`HD tree 31 | `. Users can set a temporary passphrase which is activated 32 | until the device is disconnected, or store a passphrase on the device by 33 | attaching it to a PIN. When a passphrase is attached to a PIN, it is only 34 | activated when the user unlocks the device using the PIN corresponding to that 35 | passphrase. See our `Help Center article on the advanced passphrase options 36 | `_ 37 | for more information about using passphrases. 38 | 39 | When a passphrase is activated, the binary seed derived according to BIP 39 is 40 | changed and as such the entire HD tree is changed. This means that using a 41 | different passphrase causes applications that derive information from the HD 42 | tree (like cryptocurrency wallet applications) to derive entirely different 43 | information (different cryptocurrency addresses will be generated). 44 | 45 | Attestation 46 | ----------- 47 | 48 | Attestation is a process used by Ledger devices to prove that they are a genuine 49 | Ledger device, and not a knock-off or fake version. It can be used by BOLOS when 50 | connecting to a host computer to prove that the device has not been tampered 51 | with. It can also be used by applications to prove that they are running on a 52 | genuine Ledger device. BOLOS also supports endorsement of the device by third 53 | parties (called :term:`Owners `) for attestation purposes. 54 | 55 | .. _anti-tampering: 56 | 57 | Anti-Tampering with Attestation 58 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 59 | 60 | .. figure:: images/wallet_not_genuine.png 61 | :align: center 62 | 63 | Ledger devices are protected from interdiction attacks (being tampered with 64 | while en route from Ledger's warehouses to your home) due to anti-tampering 65 | technology built into the firmware. Using attestation, the authenticity of the 66 | device is verified in software every time you plug it into one of the Ledger 67 | Chrome applications. 68 | 69 | When all Ledger devices are provisioned in the factory, they first generate a 70 | unique :term:`Device` public-private keypair. The Device's public key is then 71 | signed by Ledger's :term:`Issuer` key to create an Issuer Certificate which is 72 | stored in the device. This certificate is a digital seal of authenticity of the 73 | Ledger device. By providing the Device's public key and Issuer Certificate, the 74 | device can prove that it is a genuine Ledger device. 75 | 76 | When the Ledger device connects to one of the Ledger Chrome applications, the 77 | device uses the Issuer Certificate to prove that it is an authentic device (this 78 | takes place during establishment of the :ref:`Secure Channel `, 79 | as we'll discuss later in this section). If an attacker created a clone of the 80 | device running rogue firmware, this attestation process would fail and the 81 | device would be rejected as non-genuine. It is impossible for an attacker to 82 | replace the firmware on the device and have it pass attestation without having a 83 | Device private key and the corresponding Issuer Certificate, signed by Ledger. 84 | 85 | It is incredibly unlikely for the Device private key to become compromised, 86 | because the Secure Element is designed to be a stronghold against such physical 87 | attacks. It is theoretically possible to extract the private key, but only with 88 | great expense and time, so only an organization such as the NSA could do it. 89 | 90 | .. tip:: 91 | 92 | For more information about the benefits of Ledger's use of a Secure Element 93 | for verifying device authenticity, see our blog post `How to protect hardware 94 | wallets against tampering 95 | `_ 96 | (though keep in mind that not all of the information in this article applies 97 | to Ledger's latest products). 98 | 99 | .. _endorsement: 100 | 101 | Endorsement & Application Attestation 102 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 103 | 104 | As discussed in the previous subsection, the :term:`Device` private key can be 105 | used to prove authenticity of a Ledger device. However, direct access to the 106 | device private key is limited to BOLOS, so it can't be directly utilized by 107 | individual applications on the device (to avoid compromising the key). However, 108 | applications can indirectly use the Device private key for attestation purposes 109 | by generating attestation keypairs. 110 | 111 | Attestation keypairs can be generated on demand by the user for applications to 112 | use. An attestation key can be setup using the :ref:`endorsementSetup.py` or 113 | :ref:`endorsementSetupLedger.py` Python loader scripts. When generating an 114 | attestation keypair, the host computer connects to the dashboard application and 115 | initiates a :ref:`Secure Channel ` before instructing the device 116 | to create an attestation keypair. The device generates a new attestation keypair 117 | and signs it using the :term:`Device` private key to create a Device 118 | Certificate. The device then returns the attestation public key, the Device 119 | Certificate, and the Issuer Certificate over the Secure Channel to the host. The 120 | host, which may be Ledger or a third party, then signs the attestation public 121 | key with an :term:`Owner` private key, thus creating an Owner Certificate which 122 | is sent back over the Secure Channel and stored by the device (in this way, the 123 | Owner "endorses" the authenticity of the device). The device can then prove that 124 | the attestation key belongs to a genuine Ledger device using the Device 125 | Certificate and the Issuer Certificate, and that the attestation key is trusted 126 | by the Owner using the Owner Certificate. 127 | 128 | The attestation keys are not accessible to apps directly, instead BOLOS provides 129 | attestation functionality to userspace applications through cryptographic 130 | primitives available as system calls. There are two different Endorsement 131 | Schemes available to applications (Endorsement Scheme #1 and Endorsement Scheme 132 | #2). When creating an attestation keypair, the user must choose which scheme the 133 | keypair shall belong to. Applications can then use that keypair by using the 134 | cryptographic primitives offered for the appropriate Endorsement Scheme. 135 | 136 | Endorsement Scheme #1 offers two cryptographic primitives: 137 | 138 | ``os_endorsement_key1_get_app_secret(...)`` 139 | Derive a secret from the attestation private key and the hash of the running 140 | application. 141 | 142 | ``os_endorsement_key1_sign_data(...)`` 143 | Sign a message concatenated with the hash of the running application using 144 | the attestation private key (this signature can be verified using 145 | :ref:`verifyEndorsement1.py`). 146 | 147 | Endorsement Scheme #2 offers a single cryptographic primitive: 148 | 149 | ``os_endorsement_key2_derive_sign_data(...)`` 150 | Sign a message using a private key derived from the attestation private key 151 | and the hash of the running application (this signature can be verified using 152 | :ref:`verifyEndorsement2.py`). 153 | 154 | For an example of how these features may be used, check out `blue-app-otherdime 155 | `_ and `this blog post 156 | `_ 157 | which discusses the app in detail. 158 | 159 | Attestation Chain of Trust 160 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 161 | 162 | .. figure:: images/chain_of_trust.png 163 | :align: center 164 | 165 | The chain of trust for Ledger's attestation model 166 | 167 | This diagram shows the chain of trust of our attestation model. All data signed 168 | by the attestation keys can be trusted to have been signed by an authentic 169 | Ledger device. This is because the Device Certificate is proof that the 170 | attestation keys belong to a device, and the Issuer Certificate is proof that 171 | the device is genuine. Additionally, the Owner Certificate is proof that the 172 | attestation keys are trusted by Owner (which may be Ledger or a third party). 173 | 174 | .. _secure-channel: 175 | 176 | Secure Channel 177 | -------------- 178 | 179 | Throughout the standard device lifecycle, it is possible for a host computer to 180 | establish a Secure Channel with a device to verify its authenticity and to 181 | securely exchange secrets with it. 182 | 183 | As discussed in :ref:`anti-tampering`, the authenticity of a Ledger device can 184 | be verified when it connects to a host computer by requesting the device's 185 | :term:`Issuer Certificate`, which is signed by Ledger. This is done when 186 | establishing a Secure Channel with the device. However, the Secure Channel is 187 | not only a means to verify the authenticity of a Ledger device, it also allows 188 | the host computer to establish an encrypted communication channel with the 189 | device. Only the :ref:`dashboard application ` is able to establish a 190 | Secure Channel with the host computer, as doing so requires access to the 191 | :term:`Device` private key. 192 | 193 | The Secure Channel protocol is built on top of the APDU protocol used to 194 | communicate with the device over USB. As such, the protocol consists of a series 195 | of Command APDUs being sent from the host computer, and then associated Response 196 | APDUs being sent back from the device, with a one-to-one correspondence. The 197 | Secure Channel exists between two parties: the Signer and the Device. The Signer 198 | is the remote host connecting to the device. This may be the Issuer (Ledger) 199 | connecting to the device through our APIs, a :term:`Custom Certificate Authority 200 | ` connecting to the device using a previously :ref:`enrolled Custom 201 | CA public key `, or another end-user using a randomly 202 | generated keypair. 203 | 204 | When establishing the Secure Channel, both parties (the Signer and the Device) 205 | generate an ephemeral keypair which is later used to calculate a shared secret 206 | using ECDH for encrypted communications between the two parties. Both parties 207 | prove that they trust their respective ephemeral public keys by each providing a 208 | certificate chain. These certificate chains incorporate both a Signer nonce and 209 | a Device nonce to avoid reuse of the certificates by an eavesdropper. If the 210 | root certificate in the certificate chain provided by the Signer is signed by a 211 | party that is trusted by the device, then the device grants the remote host 212 | special permissions after establishing the Secure Channel. For example, if the 213 | root certificate in the Signer's certificate chain is signed by a previously 214 | enrolled Custom CA keypair or Ledger's Issuer keypair, then the host can add or 215 | remove apps from the device without the user's confirmation. 216 | 217 | The process of establishing a Secure Channel is illustrated in the following 218 | diagram. 219 | 220 | .. figure:: images/secure_channel_protocol.png 221 | :align: center 222 | 223 | An admittedly not-so-simple diagram of the Secure Channel protocol handshake 224 | 225 | In the above diagram, during segment (6), the Device provides a Signer serial. 226 | The Signer serial is a number stored by the device which identifies the specific 227 | Issuer keypair used to sign the device's Issuer Certificate, as Ledger does not 228 | use the same Issuer keypair for every device. 229 | 230 | The Signer certificate chain is generated, sent to the device, and verified from 231 | (7) to (11). The Device certificate chain is generated, sent to the Signer, and 232 | verified from (12) to (16). In this example, both certificate chains consist of 233 | two certificates. The root certificate in the Signer certificate chain is 234 | self-signed. The final certificate in the Signer certificate chain is signed by 235 | the Signer and verifies the authenticity of the Signer ephemeral public key. The 236 | root certificate in the Device certificate chain is the Issuer Certificate (as 237 | such, verifying this certificate implicitly verifies the authenticity of the 238 | device). The final certificate in the Device certificate chain is signed by the 239 | Device and verifies the authenticity of the Device ephemeral public key. 240 | 241 | .. _custom-ca-enrollment: 242 | 243 | Custom CA Public Key Enrollment 244 | ------------------------------- 245 | 246 | :term:`Custom Certificate Authorities ` have the option to generate a 247 | keypair (using :ref:`genCAPair.py`) and enroll their public key onto the device 248 | (using :ref:`setupCustomCA.py`). Enrolling the Custom CA public key onto the 249 | device gives them the following special privileges: 250 | 251 | * The Custom CA can open authenticated :ref:`Secure Channels ` 252 | with the device (using the ``--rootPrivateKey`` option of the Python loader 253 | scripts). 254 | * The Custom CA can sign applications (using :ref:`signApp.py`) to create a 255 | signature which can be used to avoid the user confirmation when loading the 256 | app on the device. 257 | 258 | This feature may be used by BOLOS application developers to simplify the 259 | development process, but it is intended to be much wider in scope than that. 260 | This feature may also be used by third party companies to give their own 261 | application manager permissions to manage the device without needing user 262 | confirmation on every action. 263 | 264 | Parties Involved in our Model 265 | ----------------------------- 266 | 267 | Below is a definition of all of the parties involved in our public key 268 | cryptography model. 269 | 270 | .. glossary:: 271 | 272 | Device 273 | Device Certificate 274 | The meaning of this term should be quite self-evident, however in our 275 | public key cryptography model it has a distinct meaning. Each Device has a 276 | **unique** public-private keypair that is known **only to that device**. 277 | In the factory, the Device generates it's own public-private keypair. The 278 | Device's private key is not known by Ledger. The Device public-private key 279 | pair can be used to sign certificates. 280 | 281 | Issuer 282 | Issuer Certificate 283 | The Issuer is the party that initially provisions the :term:`Device`. This 284 | party is always Ledger. The Issuer has a public-private keypair that can 285 | be used to sign Issuer Certificates. Note that Ledger uses multiple Issuer 286 | keypairs, not just one. 287 | 288 | Owner 289 | Owner Certificate 290 | An Owner is simply a party that owns and / or verifies the authenticity of 291 | a Ledger device. An Owner has a public-private keypair that can be used to 292 | sign certificates. A single :term:`Device` can have zero or more Owners, 293 | and the Owner doesn't have to be Ledger. The device uses Owner 294 | Certificates exclusively for the purposes of :ref:`application attestation 295 | `. 296 | 297 | Custom CA 298 | Custom CA Certificate 299 | A Custom Certificate Authority has a public-private keypair, where the 300 | public key is :ref:`enrolled on the device `. The 301 | Custom CA's private key can then be used to establish authenticated 302 | :ref:`Secure Channels ` with the device and sign 303 | applications. 304 | 305 | A Custom CA may be a BOLOS application developer or a third party company 306 | that would like to give their application manager special administration 307 | permissions with a BOLOS device. 308 | -------------------------------------------------------------------------------- /source/bolos/hardware_architecture.rst: -------------------------------------------------------------------------------- 1 | Hardware Architecture 2 | ===================== 3 | 4 | Ledger devices have a very unique architecture in order to leverage the security 5 | of the Secure Element while still being able to interface with many different 6 | peripherals such as the screen, buttons, the host computer over USB, or 7 | Bluetooth & NFC in the case of the Ledger Blue. In order to accomplish this, we 8 | attached an additional STM32 microcontroller ("the MCU") to the Secure Element 9 | ("the SE") which acts as a "dumb router" between the Secure Element and the 10 | peripherals. The microcontroller doesn't perform any application logic and it 11 | doesn't store any of the cryptographic secrets used by BOLOS, it simply manages 12 | the peripherals and notifies the Secure Element whenever new data is ready to be 13 | received. BOLOS applications are executed entirely on the Secure Element. In 14 | this section, we'll take a look at the hardware architecture to better embrace 15 | the hardware related constraints before analyzing their software implications. 16 | 17 | Multiple Processors: Secure Element Proxy 18 | ----------------------------------------- 19 | 20 | .. figure:: images/bolos_architecture.png 21 | :alt: Detailed BOLOS architecture 22 | :align: center 23 | 24 | A detailed BOLOS architecture diagram 25 | 26 | BOLOS is split between two hardware chips, one being secure (the ST31 Secure 27 | Element), and the other having JTAG enabled and acting as a proxy (the STM32 28 | MCU). 29 | 30 | Furthermore, the Secure Element is also split into two parts: the firmware which 31 | is under NDA and is therefore closed-source, and the SDK & application-loaded 32 | code which is open source friendly. The BOLOS firmware is responsible for 33 | low-level I/O operations and implements the SE-MCU link (though the handling of 34 | the protocol between the SE and the MCU is done by the currently running app). 35 | 36 | BOLOS relies on the collaboration of both chips to empower Secure Element 37 | applications. At first glance, and even at second and all following, the Secure 38 | Element is a very powerful piece of hardware but lacks inputs / outputs. In our 39 | architecture, we solved this problem by appending the MCU which is full of 40 | inputs / outputs so it can act as a proxy for the Secure Element to explore new 41 | horizons. In a sense, the MCU can be seen as a supercharged coprocessor of the 42 | Secure Element. Not considering security implications (which is beyond the scope 43 | of this section), and thanks to a simple asynchronous protocol, the Secure 44 | Element drives the proxy. 45 | 46 | The SE-MCU link protocol is called SEPROXYHAL or SEPH in source code and 47 | documentation. The "HAL" stands for Hardware Abstraction Layer. 48 | 49 | SEPROXYHAL 50 | ---------- 51 | 52 | The SEPROXYHAL protocol is structured as a serialized list of three types of 53 | packets: Events, Commands, and Statuses. Since SEPROXYHAL is the only channel 54 | for the SE to communicate with the outside world, if there is an error at the 55 | protocol level (such as the order or formatting of Events / Commands / Statuses 56 | getting messed up), then the SE ends up completely isolated and unable to 57 | communicate. When developing an application this is typically the most common 58 | failure scenario. If this happens, the device must be rebooted to reset the 59 | SEPROXYHAL protocol state. Hopefully, multiple levels of software guards are 60 | implemented to avoid such cases. 61 | 62 | The protocol works as follows: 63 | 64 | 1. The MCU sends an Event (button press, ticker, USB transfer, ...). 65 | 2. The SE responds with a list of zero or more Commands in response to the 66 | Event. 67 | 3. The SE sends a Status indicating that the Event is fully processed and waits 68 | for another Event. 69 | 70 | .. figure:: images/seproxyhal.png 71 | :alt: SEPROXYHAL protocol concept 72 | :align: center 73 | 74 | SEPROXYHAL protocol concept 75 | 76 | As a matter of fact, due to buffer size, requests to display something to the 77 | screen are sent using a Status. When the MCU has finished processing the Display 78 | Status, it issues a Display Processed Event indicating that it is ready to 79 | receive another Display Status. As a result, displaying multiple elements on the 80 | screen (in order to build an entire user interface) must be done asynchronously 81 | from the core application logic. This process is facilitated by a UX helper 82 | implemented in the SDK, which will be discussed further in the next chapter. 83 | 84 | The SE throws an exception to applications willing to send more than one Status 85 | in a row, without a new Event being fetched in between. 86 | -------------------------------------------------------------------------------- /source/bolos/images/app_centric_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/app_centric_view.png -------------------------------------------------------------------------------- /source/bolos/images/bolos_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/bolos_architecture.png -------------------------------------------------------------------------------- /source/bolos/images/chain_of_trust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/chain_of_trust.png -------------------------------------------------------------------------------- /source/bolos/images/secure_channel_protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/secure_channel_protocol.png -------------------------------------------------------------------------------- /source/bolos/images/seproxyhal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/seproxyhal.png -------------------------------------------------------------------------------- /source/bolos/images/usb_delegation_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/usb_delegation_overview.png -------------------------------------------------------------------------------- /source/bolos/images/wallet_not_genuine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/bolos/images/wallet_not_genuine.png -------------------------------------------------------------------------------- /source/bolos/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | This chapter contains detailed documentation about the core features offered by 5 | BOLOS, and how they can be utilized by BOLOS applications and end-users. We'll 6 | discuss how BOLOS manages the master device seed and the device private key, and 7 | how it can be used for attestation purposes. We'll also describe the hardware 8 | architecture that is common between all BOLOS devices. 9 | -------------------------------------------------------------------------------- /source/bolos/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | The operating system behind all Ledger personal security devices is called the 5 | Blockchain Open Ledger Operating System, or BOLOS for short. BOLOS provides a 6 | lightweight, open-source framework for developers to build source code portable 7 | applications that run in a secure environment. BOLOS is a way of turning 8 | hardware wallets into fully fledged :doc:`personal security devices 9 | `. 10 | 11 | BOLOS allows users to review and install applications that let them do more with 12 | their cryptographic secrets, while protecting the device and other applications 13 | from malicious code. The key to BOLOS's open-source friendliness and ability to 14 | limit the exposure of user's cryptographic secrets to their apps is its 15 | :doc:`application isolation ` technology. 16 | 17 | BOLOS is organized into the following modules: 18 | 19 | * An input / output module which allows applications executing in a secure 20 | environment to communicate with the outside world and third party peripherals 21 | * A cryptography module that implements low level cryptographic primitives and 22 | provides access to hardware acceleration where available 23 | * A persistent storage module that lets applications store data securely on the 24 | device 25 | * A personalization module for interfacing with the device master seed 26 | * An endorsement & application attestation module allowing BOLOS applications to 27 | provide proof of execution 28 | * A user interface module for rendering the GUI and handling user input (eg. via 29 | buttons on the device) 30 | 31 | .. _dashboard: 32 | 33 | The Dashboard 34 | ------------- 35 | 36 | All BOLOS devices have a special app installed that runs on the OS with certain 37 | special privileges called the Dashboard application or the PSD Content Manager. 38 | The dashboard app contains the main GUI that the user sees when they aren't in 39 | any other app. This is what the users use to enter their master seed, and its 40 | what they use to launch other applications. The dashboard application is also 41 | what the host computer communicates with when loading or deleting apps off of 42 | the device. 43 | 44 | An important component of the dashboard is the :ref:`BOLOS UX `, which 45 | is the implementation of the device-wide user interface that all applications 46 | need to interface with for certain device-wide UI features (like screen 47 | locking). The UI of the default dashboard app that is built into the firmware 48 | for the Nano S is also available as an external application that can be loaded 49 | onto the device `on GitHub `_. 50 | -------------------------------------------------------------------------------- /source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Ledger documentation build configuration file. 4 | 5 | def setup(app): 6 | app.add_stylesheet('theme_overrides.css') # Override wide tables in RTD theme 7 | 8 | # General Configuration 9 | # ===================== 10 | 11 | extensions = [] 12 | 13 | source_suffix = ['.rst'] 14 | 15 | master_doc = 'index' 16 | 17 | project = u'Ledger Documentation Hub' 18 | copyright = u'2016 - 2021, Ledger Team' 19 | author = u'Ledger Team' 20 | 21 | version = u'4' 22 | release = u'4' 23 | 24 | pygments_style = 'sphinx' 25 | 26 | # Options for HTML Output 27 | # ======================= 28 | 29 | html_theme = 'sphinx_rtd_theme' 30 | 31 | html_static_path = ['_static'] 32 | 33 | # intersphinx 34 | # =========== 35 | 36 | extensions += ['sphinx.ext.intersphinx'] 37 | 38 | intersphinx_mapping = { 39 | 'python-loader': ('https://ledger.readthedocs.io/projects/blue-loader-python/en/0.1.15/', None) 40 | } 41 | -------------------------------------------------------------------------------- /source/index.rst: -------------------------------------------------------------------------------- 1 | Ledger Documentation Hub 2 | ======================== 3 | 4 | .. note:: 5 | 6 | This documentation is intended for developers only and not general users. 7 | 8 | Ledger produces personal security devices such as the Ledger Nano S and the 9 | Ledger Blue, both of which are architected around a Secure Element and the BOLOS 10 | platform. 11 | 12 | This documentation contains information about developing apps for these devices, 13 | from high-level concepts like hierarchical deterministic key generation to 14 | low-level details about the hardware architecture of these devices. 15 | 16 | .. toctree:: 17 | :caption: Background Information 18 | :maxdepth: 1 19 | 20 | background/introduction 21 | background/personal_security_devices 22 | background/master_seed 23 | background/hd_keys 24 | background/hd_use_cases 25 | background/application_isolation 26 | 27 | .. toctree:: 28 | :caption: BOLOS Platform 29 | :maxdepth: 1 30 | 31 | bolos/introduction 32 | bolos/overview 33 | bolos/features 34 | bolos/hardware_architecture 35 | bolos/application_environment 36 | 37 | .. toctree:: 38 | :caption: Userspace Development 39 | :maxdepth: 1 40 | 41 | userspace/introduction 42 | userspace/setup 43 | userspace/writing_apps 44 | userspace/display_management 45 | userspace/advanced_display_management 46 | userspace/low_level_display_management 47 | userspace/syscalls 48 | userspace/application_structure 49 | userspace/memory 50 | userspace/alignment 51 | userspace/troubleshooting 52 | userspace/debugging 53 | userspace/speculos 54 | 55 | .. toctree:: 56 | :caption: Additional Resources 57 | :maxdepth: 1 58 | 59 | additional/publishing_an_app 60 | additional/external_docs 61 | additional/security_guidelines 62 | -------------------------------------------------------------------------------- /source/userspace/advanced_display_management.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Advanced display management 3 | =========================== 4 | 5 | This article talks about more advanced flows that are sometimes needed when writing applications. 6 | 7 | Cherry-picking steps at runtime 8 | =============================== 9 | 10 | Usecase 11 | ------- 12 | 13 | The :doc:`Display Management ` doc taught us how to use the :code:`UX_FLOW` macro. This macro is quite handy but comes with its **drawbacks**: everything needs to be declared at **compilation time**. What if we wished to change the :code:`flow` at runtime? 14 | 15 | Imagine an app where you have a flow for a transaction signature. 16 | 17 | .. code-block:: c 18 | 19 | UX_FLOW(ux_transaction_signature, 20 | &step_review, 21 | &step_amount, 22 | &step_fee, 23 | &step_address, 24 | &step_accept, 25 | &step_reject 26 | ); 27 | 28 | This works well enough for a transaction signature. But suppose there's an update to the protocol: now some transactions can also sign some arbitrary data. However, not all transactions are required to sign the arbitrary data, so you need two flows: 29 | 30 | .. code-block:: c 31 | 32 | // The standard signature, nothing has changed. 33 | UX_FLOW(ux_vanilla_transaction_signature, 34 | &step_review, 35 | &step_amount, 36 | &step_fee, 37 | &step_address, 38 | &step_accept, 39 | &step_reject 40 | ); 41 | 42 | // This flow is almost the same as the one above, except is contains "step_arbitrary_data". 43 | UX_FLOW(ux_data_transaction_signature, 44 | &step_review, 45 | &step_amount, 46 | &step_fee, 47 | &step_address, 48 | &step_arbitrary_data, // Arbitrary data 49 | &step_accept, 50 | &step_reject 51 | ); 52 | 53 | And now somewhere in your app at runtime you will be able to decide which flow to use: 54 | 55 | .. code-block:: c 56 | 57 | void launch_flow() { 58 | if (g.has_arbitrary_data) { 59 | ux_flow_init(0, ux_data_transaction_signature, NULL); 60 | } else { 61 | ux_flow_init(0, ux_vanilla_transaction_signature, NULL); 62 | } 63 | } 64 | 65 | Great this works. Hu-oh but now the community also wants to be able to see the nonce for the transaction. But they want it to be optional. You know for *advanced* users. 66 | 67 | Ok so back to work: we need a flow for the vanilla signature, as well as a flow for the vanilla signature where we show the nonce. Oh but wait we also need the option to display the nonce when there is arbitrary data to sign, so we **also** need the "data signature" flow **and** the "data signature + nonce" flow. 68 | 69 | .. code-block:: c 70 | 71 | // The standard signature, nothing has changed. 72 | UX_FLOW(ux_vanilla_transaction_signature, 73 | &step_review, 74 | &step_amount, 75 | &step_fee, 76 | &step_address, 77 | &step_accept, 78 | &step_reject 79 | ); 80 | 81 | // Now the vanilla flow where we just add the step to display the nonce. 82 | UX_FLOW(ux_vanilla_nonce_transaction_signature, 83 | &step_review, 84 | &step_amount, 85 | &step_fee, 86 | &step_address, 87 | &step_nonce, // Nonce 88 | &step_accept, 89 | &step_reject 90 | ); 91 | 92 | // This is identical to the previous example, where we signed some arbitrary data. 93 | UX_FLOW(ux_data_transaction_signature, 94 | &step_review, 95 | &step_amount, 96 | &step_fee, 97 | &step_address, 98 | &step_arbitrary_data, // Arbitrary data 99 | &step_accept, 100 | &step_reject 101 | ); 102 | 103 | // This is identical to the flow just above, except we add a step to display the nonce. 104 | UX_FLOW(ux_data_nonce_transaction_signature, 105 | &step_review, 106 | &step_amount, 107 | &step_fee, 108 | &step_address, 109 | &step_arbitrary_data, // Arbitrary data 110 | &step_nonce, // Nonce 111 | &step_accept, 112 | &step_reject 113 | ); 114 | 115 | And now somewhere in our app at runtime we're able to decide which flow to use: 116 | 117 | .. code-block:: c 118 | 119 | void launch_flow() { 120 | if (g.has_arbitrary_data) { 121 | if (g.display_nonce) { 122 | ux_flow_init(0, ux_data_nonce_transaction_signature, NULL); 123 | } else { 124 | ux_flow_init(0, ux_data_transaction_signature, NULL); 125 | } 126 | } else { 127 | if (g.display_nonce) { 128 | ux_flow_init(0, ux_vanilla_nonce_transaction_signature, NULL); 129 | } else { 130 | ux_flow_init(0, ux_vanilla_transaction_signature, NULL); 131 | } 132 | } 133 | } 134 | 135 | Ugh. Ok now everyone's happy: we've updated our app to support the protocol and the advanced users in the community can display the nonce. 136 | But now a new upgrade to the protocol is planned for the near future: the fees can sometimes be paid by another user of the blockchain, called a relayer. Anyways now some transactions now need to **hide** the fees (displaying a fee of 0.000 is not an option because it would confuse users more than anything). 137 | 138 | So we need... **8 different flows**. That escalated quickly! Indeed, for every little *upgrade*, we're doubling the number of flows. Soon enough we'll end up with 16 or even 32 different flows... Notice that whilst the number of flows will grow exponentially, the number of different steps though will only grow linearly (one for every new feature). 139 | 140 | To fix this problem, we would need to define the UX_FLOW at runtime, cherry-picking which steps we wish to include depending on the details of our transaction. 141 | 142 | Don't worry, Ledger's got your back! The fix is quite simple, so let's dive right into it! 143 | 144 | Cherry-picking explained 145 | ------------------------ 146 | 147 | The idea is to create an array of steps that would be big enough to fit all the steps. Since steps grow linearly, this array won't be too big. 148 | Once this array created, we simply need to fill it with the steps we wish to include. Finally, we need to add a last step :code:`FLOW_END_STEP` for it to work properly. 149 | 150 | We can then call the :code:`ux_init_flow` and pass in our array as argument! 151 | 152 | .. code-block:: c 153 | 154 | // The maximum number of steps we will ever need. Here it's 8: step_review, step_amount, 155 | // step_fee, step_address, step_arbitrary_data, step_nonce, step_accept, step_reject. 156 | #define MAX_NUM_STEPS 8 157 | 158 | // The array of steps. Notice the type used, as it's important if you wish to use ux_init_flow. 159 | // We're adding `+ 1` because we need to ensure we always have extra room for the last step, FLOW_END_STEP. 160 | const ux_flow_step_t *ux_signature_flow[MAX_NUM_STEPS + 1]; 161 | 162 | .. code-block:: c 163 | 164 | void start_display() { 165 | uint8_t index = 0; 166 | 167 | // Set the first step to be `step_review`, and then increment `index`. 168 | ux_signature_flow[index++] = step_review; 169 | // Set the second step to be `step_amount`, and then increment `index`. 170 | ux_signature_flow[index++] = step_amount; 171 | // etc... 172 | ux_signature_flow[index++] = step_fee; 173 | ux_signature_flow[index++] = step_address; 174 | // We can now conditionally add steps at runtime! 175 | if (g.has_arbitrary_data) { 176 | ux_signature_flow[index++] = step_arbitrary_data; 177 | } 178 | if (g.display_nonce) { 179 | ux_signature_flow[index++] = step_nonce; 180 | } 181 | ux_signature_flow[index++] = step_accept; 182 | ux_signature_flow[index++] = step_reject; 183 | 184 | // Don't forget to finish your flow with this special step. 185 | ux_signature_flow[index++] = FLOW_END_STEP; 186 | 187 | // Start the display! 188 | ux_init_flow(0, ux_signature_flow, NULL); 189 | } 190 | 191 | 192 | Defining steps at runtime 193 | ========================= 194 | 195 | In the previous section we saw that we could define a :code:`UX_FLOW` at runtime. But we did this whilst still having steps defined statically. What if we wish to define steps at runtime too? This would give us a very fine-grained control over what we wish to display, without having to declare a step everytime. 196 | 197 | Finding a step that would be generic enough to fit all our needs. Naively, the code we'd expect would look something like that: 198 | 199 | .. code-block:: c 200 | 201 | // Naive definition of a UX_FLOW. 202 | // Note: we are still keeping step_review, step_accept and 203 | // step_reject because we know our flow will need those anyway. 204 | UX_FLOW(ideal_dynamic_fow, 205 | &step_welcome, 206 | &step_generic, // A generic step that would fit all our needs. 207 | &step_quit 208 | FLOW_LOOP 209 | ); 210 | 211 | 212 | However this wouldn't work: if we only defined a single step, then how could it dynamically change its information? Pressing the right button would make it loop and we'd end up on the same exact screen, and pressing the left button would lead to the same situation. 213 | 214 | So here's a solution: 215 | 216 | * Add an extra step just before the :code:`step_generic` step, and another one right after it. 217 | * Those extra steps are nothing but delimiters for the :code:`step_generic` . They allow us to execute special logic to update the screen and redisplay it. They also allow us to keep track of an index, so that we know whether we're still within our array boundaries or not. 218 | 219 | Here's what the code looks like. 220 | 221 | .. code-block:: c 222 | 223 | UX_FLOW(dynamic_flow, 224 | &step_welcome, 225 | 226 | &step_upper_delimiter, // A special step that serves as the upper delimiter. It won't print anything on the screen. 227 | &step_generic, // Our generic step that will actually display stuff on the screen. 228 | &step_lower_delimiter, // A special step that serves as the lower delimiter. It won't print anything on the screen. 229 | 230 | &step_quit, 231 | FLOW_LOOP 232 | ); 233 | 234 | The definition of :code:`step_upper_delimiter`, :code:`step_lower_delimiter` and :code:`step_generic` could look like this: 235 | 236 | .. code-block:: c 237 | 238 | 239 | // Note we're using UX_STEP_INIT because this step won't display anything. 240 | UX_STEP_INIT( 241 | step_upper_delimiter, 242 | NULL, 243 | NULL, 244 | { 245 | // This function will be detailed later on. 246 | display_next_state(true); 247 | } 248 | ); 249 | 250 | UX_STEP_NOCB( 251 | step_generic, 252 | bnnn_paging, 253 | { 254 | .title = global.title, 255 | .text = global.text, 256 | } 257 | ); 258 | 259 | // Note we're using UX_STEP_INIT because this step won't display anything. 260 | UX_STEP_INIT( 261 | step_lower_delimiter, 262 | NULL, 263 | NULL, 264 | { 265 | // This function will be detailed later on. 266 | display_next_state(false); 267 | } 268 | ); 269 | 270 | As you can see, :code:`step_upper_delimiter` and :code:`step_lower_delimiter` are very similar. :code:`step_generic` is a simple :code:`bnnn_paging` that will always display what's located in :code:`global.title` and :code:`global.text`. 271 | 272 | And now we only need to implement the special logic for this to work! 273 | 274 | Inside the :code:`.h` file, we only need to add an enum definition and an instance of this enum in our global structure: 275 | 276 | .. code-block:: c 277 | 278 | // State of the dynamic display. 279 | // Use to keep track of whether we are displaying screens that are inside the 280 | // array (dynamic), or outside the array (static). 281 | enum e_state { 282 | STATIC_SCREEN, 283 | DYNAMIC_SCREEN, 284 | }; 285 | 286 | struct global { 287 | // An instance of our new enum 288 | enum e_state current_state; 289 | 290 | // The rest of the global stays unchanged... 291 | } 292 | 293 | And in the :code:`.c` file, we add all the business logic. A helper function 294 | 295 | .. code-block: c 296 | 297 | bool get_next_data(char *title_buffer, char *text_buffer, bool forward); 298 | 299 | is used throughout the code. This function is yours to define, and basically fills the title_buffer and the text_buffer with the appropriate strings. Is returns a :code:`bool` corresponding to whether or not it found data to fill the buffers. The `:code:`bool forward` parameter is used to indicate whether we wish to display the next screen or the previous screen. 300 | 301 | The code is commented thoroughly, so take your time and read it carefully. 302 | 303 | .. code-block:: c 304 | 305 | // This is a special function we must call for bnnn_paging to work properly in an edgecase. 306 | // It does some weird stuff with the `G_ux` global which is defined by the SDK. 307 | // No need to dig deeper into the code, a simple copy paste will do. 308 | void bnnn_paging_edgecase() { 309 | G_ux.flow_stack[G_ux.stack_count - 1].prev_index = G_ux.flow_stack[G_ux.stack_count - 1].index - 2; 310 | G_ux.flow_stack[G_ux.stack_count - 1].index--; 311 | ux_flow_relayout(); 312 | } 313 | 314 | // Main function that handles all the business logic for our new display architecture. 315 | void display_next_state(bool is_upper_delimiter) { 316 | if (is_upper_delimiter) { // We're called from the upper delimiter. 317 | if (global.current_state == STATIC_SCREEN) { 318 | // Fetch new data. 319 | bool dynamic_data = get_next_data(&global.title, &global.text, true); 320 | 321 | if (dynamic_data) { 322 | // We found some data to display so we now enter in dynamic mode. 323 | global.current_state = DYNAMIC_SCREEN; 324 | } 325 | 326 | // Move to the next step, which will display the screen. 327 | ux_flow_next(); 328 | } else { 329 | // The previous screen was NOT a static screen, so we were already in a dynamic screen. 330 | 331 | // Fetch new data. 332 | bool dynamic_data = get_next_data(&global.title, &globa.text, false); 333 | if (dynamic_data) { 334 | // We found some data so simply display it. 335 | ux_flow_next(); 336 | } 337 | else { 338 | // There's no more dynamic data to display, so 339 | // update the current state accordingly. 340 | global.current_state = STATIC_SCREEN; 341 | 342 | // Display the previous screen which should be a static one. 343 | ux_flow_prev(); 344 | } 345 | } else { 346 | // We're called from the lower delimiter. 347 | 348 | if (global.current_state == STATIC_SCREEN) { 349 | // Fetch new data. 350 | bool dynamic_data = get_next_data(&global.title, &global.text, false); 351 | 352 | if (dynamic_data) { 353 | // We found some data to display so enter in dynamic mode. 354 | global.current_state = DYNAMIC_SCREEN; 355 | } 356 | 357 | // Display the data. 358 | ux_flow_prev(); 359 | } else { 360 | // We're being called from a dynamic screen, so the user was already browsing the array. 361 | 362 | // Fetch new data. 363 | bool dynamic_data = get_next_data(&global.title, &global.text, true); 364 | if (dynamic_data) { 365 | // We found some data, so display it. 366 | // Similar to `ux_flow_prev()` but updates layout to account for `bnnn_paging`'s weird behaviour. 367 | bnnn_paging_edgecase(); 368 | } else { 369 | // We found no data so make sure we update the state accordingly. 370 | global.current_state = STATIC_SCREEN; 371 | 372 | // Display the next screen 373 | ux_flow_next(); 374 | } 375 | } 376 | } 377 | } 378 | } 379 | 380 | That was a mouthful! But we did it: we managed to dynamically adapt our flow AND our steps! -------------------------------------------------------------------------------- /source/userspace/alignment.rst: -------------------------------------------------------------------------------- 1 | .. _alignment: 2 | 3 | Memory alignment 4 | ================ 5 | 6 | The Secure Elements on top of which the BOLOS Operating System and the associated applications run imply a 32-bit alignment. 7 | This paragraph aims at explaining the C associated development constraints. 8 | 9 | Alignment concept 10 | ----------------- 11 | 12 | The memory alignment is a concept which applies to memory and pointers: 13 | 14 | - A memory address is 'b-bits aligned' when it is a multiple of b/8, b/8 being a power of 2, 15 | - A memory address is said to be aligned when the data referenced by said address is b bits long, and said address is b-bits aligned, 16 | - A pointer is 'aligned' when it points on aligned memory, 17 | - A pointer is 'unaligned' when it points on unaligned memory. 18 | 19 | Alignment constraints for basic types and structures 20 | ---------------------------------------------------- 21 | 22 | Implementing C source code with types and structures is not functionally impacted by the 32-bit alignment, except for potentially wasting a few bytes without even noticing. 23 | 24 | 25 | It might be important to be aware of this paragraph contents when it comes to writing memory-efficient structures, once the application is compiled and loaded onto a device. 26 | 27 | 28 | Within any application source code, the alignment of basic types will be considered as follows, at compilation time: 29 | 30 | - ``char`` / ``unsigned char`` / ``int8_t`` / ``uint8_t`` : 8-bit aligned, 31 | - ``short`` / ``unsigned short`` / ``int16_t`` / ``uint16_t``: 16-bit aligned, 32 | - ``int`` / ``unsigned int`` / ``int32_t`` / ``uint32_t``: 32-bit aligned, 33 | - any pointer: 32-bit aligned. 34 | 35 | Please note that 8-bit aligned means that there is actually no alignment constraint. 36 | 37 | The compiler will add padding in any structure which is not aligned by design, in order to respect: 38 | 39 | - The alignment of each field associated to their respective length, 40 | - The alignment of the whole structure, which shall have a total length, padding included, multiple of the largest field's length. 41 | 42 | For instance the following structure is 8 bytes long before compilation: 43 | 44 | .. code-block:: c 45 | 46 | // Before compilation 47 | struct Example1 48 | { 49 | char field_1; 50 | short field_2; 51 | int field_3; 52 | char field_4; 53 | }; 54 | 55 | However during compilation, the structure is modified to ensure the alignment, and will thus be 12 bytes long: 56 | 57 | .. code-block:: c 58 | 59 | // After compilation 60 | struct Example1 61 | { 62 | char field_1; 63 | // Padding added for field_2 to start on a 16-bit aligned address 64 | char padding_1; 65 | short field_2; 66 | // With padding_1 being added, field_3 will start on a 32-bit aligned 67 | // address and no padding is required here. 68 | int field_3; 69 | char field_4; 70 | // The structure is aligned to the number of bits corresponding to the 71 | // largest field's alignment, in this case, due to field_3, 32-bits. 72 | // For the structure to be 32-bit aligned, it needs 3 more bytes of padding. 73 | char padding_2[3]; 74 | }; 75 | 76 | In this example, it is possible to reorganize the structure's fields to avoid alignment-induced padding, but sometimes padding will not be avoidable. 77 | 78 | One can order the structure fields according to their length in decreasing order: 79 | 80 | .. code-block:: c 81 | 82 | // Before compilation 83 | struct Example1_reordered 84 | { 85 | int field_3; 86 | short field_2; 87 | char field_1; 88 | char field_4; 89 | }; 90 | 91 | .. code-block:: c 92 | 93 | // After compilation 94 | struct Example1_reordered 95 | { 96 | int field_3; 97 | // No need for padding since field_2 is already on a 16-bit aligned address. 98 | short field_2; 99 | // No need for padding for char types. 100 | char field_1; 101 | char field_4; 102 | // No need for padding since the structure is 8 bytes long and thus, its length 103 | // is already a multiple of its largest field's length. 104 | }; 105 | 106 | One can also order the structure fields to make sure the minimum amount of padding bytes will be added by the compilation phase: 107 | 108 | .. code-block:: c 109 | 110 | // Before compilation 111 | struct Example1_reordered_other_way 112 | { 113 | int field_3; 114 | char field_1; 115 | char field_4; 116 | short field_2; 117 | }; 118 | 119 | .. code-block:: c 120 | 121 | // After compilation 122 | struct Example1_reordered_other_way 123 | { 124 | int field_3; 125 | // No need for padding for char types. 126 | char field_1; 127 | char field_4; 128 | // No need for padding since field_2 is already on a 16-bit aligned address. 129 | short field_2; 130 | // No need for padding since the structure is 8 bytes long and thus, its length 131 | // is already a multiple of its largest field's length. 132 | }; 133 | 134 | 135 | Alignment constraints for pointers 136 | ---------------------------------- 137 | 138 | Using pointers within C source code might be functionally impacted by the 32-bit alignment in a specific case: when the pointer points on a memory area which type differs from the pointer, and is dereferenced. 139 | 140 | Dereferencing unaligned pointers within an application stalls the device. 141 | 142 | Usually, pointers are used to store the address of an element which type corresponds to the pointer one, and for simple example: 143 | 144 | .. code-block:: c 145 | 146 | uint16_t *pointer; 147 | uint16_t array[10]; 148 | 149 | // Pointer positioning is perfectly fine. 150 | pointer = &array[3]; 151 | 152 | // Dereferencing this pointer is also perfectly fine, since the 153 | // pointed memory is aligned in accordance with the pointer type. 154 | *pointer = 0x0001; 155 | 156 | However, if we use a pointer with a specific type to store the address of a memory area declared with another type (usually with an alignment-related size less than the pointer one), it can lead to hardware faults and stall the device: 157 | 158 | .. code-block:: c 159 | 160 | uint16_t *pointer; 161 | uint8_t array[10]; 162 | 163 | // Case where it will work even if not advised. 164 | 165 | // Pointer positioning is fine. 166 | pointer = (uint16_t*)&array[2]; 167 | 168 | // Dereferencing this pointer is also fine: the pointed memory is aligned 169 | // in accordance with the pointer type (because the offset 2 in the array variable 170 | // is a multiple of 16 bits). 171 | if (*pointer == 0x0001) { 172 | do_something(); 173 | } 174 | 175 | // Case where it will stall the device. 176 | 177 | // Pointer positioning is fine, but it is unaligned. 178 | pointer = (uint16_t*)&array[3]; 179 | 180 | // Dereferencing this pointer will stall the device: the pointed memory is not aligned 181 | // in accordance with the pointer type (because the offset 3 in the array variable 182 | // is not a multiple of 16 bits). 183 | if (*pointer == 0x0001) { /* This dereferencing stalls the device. */ 184 | do_something(); 185 | } 186 | 187 | The same reasoning applies to pointing on structures: 188 | 189 | .. code-block:: c 190 | 191 | // Same example as within the previous paragraph, being ordered 192 | // makes it 8 bytes long. 193 | struct Example1_reordered 194 | { 195 | int field_3; 196 | short field_2; 197 | char field_1; 198 | char field_4; 199 | }; 200 | 201 | Example1_reordered *pointer; 202 | uint8_t array[32]; 203 | 204 | // Case where it will work even if not advised. 205 | 206 | // Pointer positioning is fine. 207 | pointer = (Example1_reordered*)&array[8]; 208 | 209 | // Dereferencing this pointer is also fine: the pointed memory is aligned 210 | // in accordance with the pointer type (because the offset 8 in the array variable 211 | // is a multiple of the structure's size after compilation). 212 | if (pointer->field_2 == 0x0001) { 213 | do_something(); 214 | } 215 | 216 | // Case where it will stall the device. 217 | 218 | // Pointer positioning is fine, but it is unaligned. 219 | pointer = (Example1_reordered*)&array[3]; 220 | 221 | // Dereferencing this pointer will stall the device: the pointed memory is not aligned 222 | // in accordance with the pointer type (because the offset 3 in the array variable 223 | // is not a multiple of the structure's size after compilation). 224 | if (pointer->field_2 == 0x0001) { /* This dereferencing stalls the device. */ 225 | do_something(); 226 | } 227 | 228 | 229 | Unaligned pointers can thus occur in cases where a pointer: 230 | 231 | - declared as positioning on some data type (or structure) 232 | - is used to point on a memory area actually containing another type of data, 233 | - and is dereferenced. 234 | 235 | In order to produce C source code robust to alignment constraints, one need to avoid using pointers in such a way. 236 | 237 | External links 238 | -------------- 239 | 240 | - https://en.wikipedia.org/wiki/Data_structure_alignment 241 | - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/BABFAIGG.html 242 | - http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html 243 | -------------------------------------------------------------------------------- /source/userspace/application_structure.rst: -------------------------------------------------------------------------------- 1 | Application Structure and I/O 2 | ============================= 3 | 4 | Many of the existing BOLOS applications are based on a smartcard architecture. 5 | This is because BOLOS applications are not meant to run standalone, but rather 6 | assist a host process (on a computer / smartphone) to perform a secure task 7 | (signing a message, encryption / decryption, etc.). Therefore the device is 8 | commonly addressed using a command / response scheme. Numerous design decisions 9 | have been made when developing the SDKs in order to support this model. 10 | 11 | However, the Event / Commands / Status model is designed to avoid limitations on 12 | the application, as it does not follow the command / response synchronous model. 13 | Developers are free to work around the model and redesign a custom event 14 | processing loop to suit their needs. 15 | 16 | APDU Interpretation Loop 17 | ------------------------ 18 | 19 | The command / response scheme used to address the device is similar to the 20 | `ISO/IEC 7816-4 21 | `_ 22 | smartcard protocol. Each command / response packet is called an APDU. The 23 | application is driven by a never-ending APDU interpretation loop called straight 24 | from the application main function. 25 | 26 | Each cycle of the APDU interpretation loop calls ``io_exchange(...)`` from the 27 | SDK, which first sends a response APDU (unless it's the first call, in which 28 | case it sends nothing), and then receives the next command APDU. 29 | 30 | However, sometimes, a user confirmation to perform a security action must be 31 | performed before replying to an APDU (for example, when signing a message). Such 32 | behavior is handled by replying no data to the command in the APDU interpreter 33 | by using the ``IO_ASYNCH_REPLY`` flag, then following the user action calling 34 | ``io_exchange`` with the ``IO_RETURN_AFTER_TX`` flag and with the amount of data 35 | to reply to the stalled command. 36 | 37 | For an example of this feature, refer to `blue-app-samplesign 38 | `_. 39 | In this app, when the command APDU to sign a message is received (line 510), the 40 | flag ``IO_ASYNCH_REPLY`` is set and no response APDU is sent. If the user 41 | approves the action, then the button push handler calls 42 | ``io_seproxyhal_touch_approve(...)`` which sends the response APDU using another 43 | call to ``io_exchange(...)`` with the ``IO_RETURN_AFTER_TX`` flag set (line 44 | 434). The same occurs if the user denies the action, in which case 45 | ``io_seproxyhal_touch_deny(...)`` is triggered. 46 | 47 | Protocols 48 | --------- 49 | 50 | It's important to understand that the APDU protocol used by most BOLOS 51 | applications is not implemented by BOLOS itself. Instead, the APDU 52 | interpretation is performed entirely by the SDK. This means that applications 53 | can choose to implement another protocol on top of the transport layer (USB HID, 54 | USB CCID, BLE, ...) instead of APDU. In fact, the same is true for the transport 55 | layer protocols. Applications can customize the way the application is 56 | enumerated as a USB device by the host. 57 | 58 | .. figure:: images/common_protocols.png 59 | :align: center 60 | 61 | Common protocols across BOLOS applications 62 | 63 | Unprocessed Events 64 | ------------------ 65 | 66 | APDU processing relies on the BOLOS way of framing / transporting APDU packets. 67 | All event processing related to transfer operations (including USB) is performed 68 | within ``io_exchange(...)``. Not considering customization of the transport, 69 | some Events are not automagically processed by ``io_exchange(...)`` (for 70 | example: Button Push Events, Display Processed Events, Ticker Events, ...). In 71 | order to handle these events that cannot be handled automagically, 72 | ``io_exchange(...)`` calls ``io_event(...)`` which is defined by the application 73 | (not by the SDK). 74 | 75 | Developers must take great care in the way they process Events. Events might 76 | occur in the middle of APDU transport (most likely Button Push or Ticker 77 | Events). As such, ``io_event(...)`` must return ``1`` if events are expected, 78 | otherwise the current APDU transport will be terminated (this feature could be 79 | used to implement a timeout, for example). 80 | 81 | Thanks to a hardware buffer in the SE, it is impossible to miss an Event packet. 82 | And, due to the E/Cs/S protocol design, no Event will be sent by the MCU until a 83 | new Status is sent by the application. 84 | -------------------------------------------------------------------------------- /source/userspace/debugging.rst: -------------------------------------------------------------------------------- 1 | Application Debug 2 | ================= 3 | 4 | .. note:: 5 | 6 | Ledger has developed its own emulator called `Speculos `_ . 7 | Feel free to checkout: 8 | 9 | 1. The `Speculos repo `_ . 10 | 2. The `Nano S SDK `_ and the `Nano X SDK `_ . 11 | 3. The :doc:`speculos` section which gives an overview of how to use speculos. 12 | 13 | 14 | .. warning:: 15 | 16 | The :doc:`BOLOS development environment ` is 17 | required for the following article. It applies only for the Nano S, with its 18 | SE firmware either in version 1.5.5 or 1.6.0. 19 | 20 | It is possible to install a debugging firmware on the device's MCU that will 21 | enable printing text outputs from the device to a terminal. To do so, follow 22 | these steps: 23 | 24 | 1. First, download the `updater 25 | `_ and the 26 | `debug firmware 27 | `_ and install the python module ledgerblue by running `pip3 install ledgerblue`. 28 | 29 | 2. Exit any instance of Ledger Live, Ledger Chrome App, or any other program 30 | able to communicate with a Ledger device. 31 | 32 | 3. Now, plug your Nano S to your computer while keeping the left button 33 | pressed. Keep it pressed until the screen displays ``BOOTLOADER``. 34 | 35 | 4. Fire a terminal and move to the directory containing the files downloaded at 36 | step 1. 37 | 38 | 5. Install the updater (only if you MCU firmware is not already in version 1.11, otherwise just go to step 6):: 39 | 40 | python3 -m ledgerblue.loadMCU --targetId 0x01000001 --fileName blup_0.11_misc_m1.hex --nocrc 41 | 42 | Wait until ``BOOTLOADER`` is displayed again on the device's screen. 43 | 44 | 6. Install the debug firmware:: 45 | 46 | python3 -m ledgerblue.loadMCU --targetId 0x01000001 --fileName mcu_1.11-printf_over_0.11.hex --reverse --nocrc 47 | 48 | 49 | If you can notice a small ``dbg`` block at the bottom of the screen, then it's 50 | a success ! 51 | 52 | .. figure:: images/debug_nano.jpg 53 | :align: center 54 | :scale: 50% 55 | 56 | A Nano S with special debug firmware 57 | 58 | Uninstalling this special firmware is also very easy, first you need to 59 | download the `normal firmware 60 | `_, 61 | then you can repeat the installation steps 2 to 5. 62 | 63 | Finally, flash the normal firmware with this command:: 64 | 65 | python3 -m ledgerblue.loadMCU --targetId 0x01000001 --fileName mcu_1.11_over_0.11.hex --reverse --nocrc 66 | 67 | The ``dbg`` block should now be gone. 68 | 69 | 70 | PRINTF macro 71 | ------------ 72 | 73 | The debug firmware enables the ``PRINTF`` macro, however you have to define it 74 | in your app's Makefile. To do so, add this line in your Makefile: ``DEFINES 75 | += HAVE_SPRINTF HAVE_PRINTF PRINTF=screen_printf`` 76 | 77 | Usually, ``PRINTF`` is already defined to void with this line ``DEFINES += 78 | PRINTF\(...\)=``. Check if ``PRINTF`` is already defined somewhere else in your 79 | Makefile, and comment out this definition so it doesn't override the one that 80 | we just set. 81 | 82 | .. warning:: 83 | 84 | The PRINTF macro is a debugging feature, and as such it is not intended for 85 | use in production. When compiling an application for release purpose, please 86 | verify that ``PRINTF`` is disabled in your Makefile. In other words, in case 87 | of release compilation, put back the line ``DEFINES += PRINTF\(...\)=`` 88 | and comment out the other one. 89 | 90 | .. warning:: 91 | The ``PRINTF`` macro can only be used in between successive calls to 92 | ``io_exchange``. Calling it outside of it will result in unexpected 93 | behavior. Behind the scene, ``PRINTF`` sends a status on the `SEPH 94 | `_. 95 | Only one status can be sent in a row, otherwise the SEPH crashes. For this 96 | reason, don't use ``PRINTF`` just after status-sending calls, such as 97 | ``UX_DISPLAY``. This macro packs a call to `io_seproxyhal_display` and is 98 | often the reason for application crashes. Then is no other work around than 99 | to move your call to ``PRINTF`` somewhere else in your code. 100 | 101 | This macro can be used in your code like a classical ``printf`` function from 102 | ``stdio.h``. However, it is improved with a neat feature to easily print byte 103 | arrays: 104 | 105 | .. code-block:: c++ 106 | 107 | uint8_t buffer[4] = {0xDE, 0xAD, 0xBE, 0xEF}; 108 | 109 | // PRINTF(string, array length, array); 110 | // .*H for uppercase, .*h for lowercase 111 | PRINTF("What a lovely buffer:\n %.*H \n\n", 4, buffer); 112 | PRINTF("I prefer it lower-cased:\n %.*h \n", 4, buffer); 113 | 114 | .. figure:: images/deadbeef.png 115 | :align: center 116 | :scale: 100% 117 | 118 | Result of the example code printed inside a terminal 119 | 120 | 121 | Console Printing 122 | ---------------- 123 | 124 | The ``PRINTF`` macro triggers messages from the MCU to the host computer 125 | through the USB link. We use `USBTool 126 | `_ to read 127 | these messages and print their payload in a terminal. 128 | 129 | Unzip the file and execute this command: ``./usbtool -v 0x2c97 log`` 130 | 131 | Now you can launch your app on your Nano S, and every ``PRINTF`` will end up 132 | printed on the host computer, allowing you to debug your program more easily. 133 | 134 | 135 | PIN bypass 136 | ---------- 137 | 138 | In Ledger app development, it is necessary to enter your PIN code each time you 139 | install an unsigned app. In order to do testing during development, this means 140 | developers wind up using many painful button presses entering a PIN code 141 | compared to relatively few testing their own application code. The Ledger OS 142 | (BOLOS) supports installing a custom developer certificate. By installing a 143 | custom certificate once on your device you can avoid having to retype your PIN 144 | each time you adjust your app. Here are the steps for the Ledger Nano S: 145 | 146 | 1. Generate a public / private keypair using the following command:: 147 | 148 | foo@bar:~$ python3 -m ledgerblue.genCAPair 149 | Public key : 0495331cb86e961fc9cb5792a97737e4204b58be99321dcec463cec3057b3304e9875614004e6e540ab0610a1339fae22df6f6f3ec594912b409d69b72f0eaf390 150 | Private key: 6c1f1df852255e113b23c2e977d6b5c3ea2aaf411f05a5fdab87a3e8f44468ee 151 | 152 | 2. Enter recovery mode on your Ledger Nano S. Do this by unplugging it then 153 | holding down the right button (near the hinge, away from USB port) while 154 | plugging it in again. ``recovery mode`` should then appear on the screen. 155 | Enter your pin and continue. 156 | 157 | 3. Load your public key onto the Ledger Nano S. Paste the public key generated 158 | at step 1 after ``--public``. You may need to adjust the ``--targetId`` 159 | constant to match your device. Find the right targetId for your device `here 160 | `_. 161 | Notice that we must include a ``--name`` parameter containing the name of the 162 | custom certificate (any string will do):: 163 | 164 | python3 -m ledgerblue.setupCustomCA --targetId 0x31100004 --public yourPublicKey --name dev 165 | 166 | If you receive the error ``Invalid status 6985`` then please review 167 | `this link 168 | `_ and then go 169 | back to step 2. The above command is the simplest that can work however some 170 | developers may wish to use the optional ``--rootPrivateKey`` option to specify 171 | a secure channel encryption key (which is the private key generated at step 1) 172 | or use the ``--name`` option for convenient labeling according to local 173 | convention. 174 | 175 | 4. Once you have loaded your custom certificate, you can try to load an app you 176 | compiled yourself onto your Ledger to see if you are able to bypass the PIN. 177 | Before you try it, set the ``SCP_PRIVKEY`` environment variable to contain the 178 | private key generated at step 1 in your shell or ``.bashrc``:: 179 | 180 | export SCP_PRIVKEY=yourPrivateKey 181 | 182 | and then rebuild/load your app. 183 | 184 | For more information see 185 | `loadApp-py 186 | `_ 187 | 188 | .. warning:: 189 | 190 | A side effect of installing a custom CA on your device is that it will from 191 | now on fail to pass the Ledger Genuine Check, which is required to install 192 | applications from the Ledger Live. To make it genuine again, you should 193 | uninstall your custom CA and all the applications installed through it. 194 | 195 | 196 | Uninstalling a custom CA is very quick: 197 | 198 | 1. Enter recovery mode on your Ledger Nano S. Do this by unplugging it then 199 | holding down the right button (near the hinge, away from USB port) while 200 | plugging it in again. ``recovery mode`` should then appear on the screen. 201 | Enter your pin and continue. 202 | 203 | 2. Type this command in your terminal:: 204 | 205 | foo@bar:~$ python3 -m ledgerblue.resetCustomCA --targetId 0x31100004 206 | 207 | Find the right targetId for your device `here 208 | `_. 209 | 210 | 211 | -------------------------------------------------------------------------------- /source/userspace/display_management.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Display Management 3 | ================== 4 | 5 | On-screen display 6 | ================= 7 | 8 | Screens and Flows 9 | ----------------- 10 | 11 | Displaying information on the devices is done by defining a :code:`flow`. 12 | Think of a flow as a **set of screens that will be displayed** to the user. 13 | The user will be able to navigate the flow using **left** and **right** buttons. 14 | 15 | The macro :code:`UX_FLOW` lets you define a flow. It first takes the **name of the flow** you are defining, and then the **different steps** of your flow. 16 | 17 | Here's an example: 18 | 19 | .. code-block:: c 20 | 21 | UX_FLOW(ux_sign_transaction, // Name of the flow 22 | &step_destination_address, // Reference to the first step 23 | &step_display_amount, // Reference to second step 24 | &step_display_transaction_fees, // etc... 25 | &step_display_approve_step, 26 | &step_display_reject_step 27 | ); 28 | 29 | "*But what are those steps? Where can I find them?*" you ask? Well, they're **yours to declare in your app**! Let's have a look at how you can declare those! 30 | 31 | Declaring steps 32 | --------------- 33 | 34 | A step is declared using one of the **macros provided by the SDK**. Here's a list of the **most used ones** (a more exhaustive list is available by looking at the SDK source code!): 35 | 36 | * :code:`UX_STEP_NOCB` : Your bread and butter step. A step that simply **displays information on-screen**, without having any callback function (hence the :code:`NOCB` annotation!). This is used to display information to the user (display a public key, display the network name...). 37 | * :code:`UX_STEP_CB` : Another widely used step declaration. You need to **associate a callback function** (hence the :code:`CB` annotation!) that will be called if the **user presses both buttons simultaneously**. This is used mainly at the end of a flow, to either APPROVE or REJECT a signature for example. 38 | * :code:`FLOW_LOOP` : This is a special macro that **doesn't take any arguments**. Put it as the last step of your :code:`UX_FLOW` declaration, and the flow will wrap around: pressing the left button on the first screen will display to the last screen, and pressing the right button on the last screen will jump right to the first screen! 39 | 40 | Looking back at our previous flow (the :code:`ux_display_pubkey_flow`), you can guess which steps were declared with :code:`UX_STEP_NOCB` and :code:`UX_STEP_CB`! 41 | 42 | .. list-table:: Previous example explained 43 | :widths: 20 20 60 44 | :header-rows: 1 45 | 46 | * - Step 47 | - STEP_MACRO 48 | - Note 49 | * - :code:`ux_display_destination_address` 50 | - :code:`UX_STEP_NOCB` 51 | - This step will just display the destination address to the user, **we're not expecting him to confirm or reject anything**. 52 | * - :code:`ux_display_amount` 53 | - :code:`UX_STEP_NOCB` 54 | - This step will just display the amount to the user, **we're not expecting him to confirm or reject**. 55 | * - :code:`ux_display_transaction_fees` 56 | - :code:`UX_STEP_NOCB` 57 | - This step will just display the transaction fees to the user, **we're not expecting him to confirm or reject**. 58 | * - :code:`ux_display_approve_step` 59 | - :code:`UX_STEP_CB` 60 | - This step will prompt the user to CONFIRM that he wishes to sign the transaction. If the user **presses both button**, the application will **call the callback function** associated with this step (the code to sign a transaction!). 61 | * - :code:`ux_display_reject_step` 62 | - :code:`UX_STEP_CB` 63 | - This step will prompt the user to REJECT the signature of the transaction. If the user **presses both button**, the application will **call the callback function** associated with this step (the code to reject the transaction signature). 64 | 65 | Here's how the first step is defined: 66 | 67 | .. code-block:: c 68 | 69 | UX_STEP_NOCB( 70 | step_destination_address, 71 | bnnn_paging, 72 | { 73 | .title = "Address", 74 | .text = g_address 75 | } 76 | ); 77 | 78 | * The first argument is the **name** that we are going to give to this step. 79 | * The second are what we call a :code:`layout` option. 80 | * The third argument goes hand-in-hand with the :code:`layout` option. 81 | 82 | It looks like the :code:`layout` is where the black-magic happens. Let's have a closer look at :code:`layout` s! 83 | 84 | Layouts 85 | ------- 86 | 87 | Layouts are nothing more than rules that specify the format / number of lines / fonts we are going to use on the screen. 88 | They are easy to remember once you understand that: 89 | 90 | * :code:`b` stands for **bold**. 91 | * :code:`n` stands for **normal**. 92 | * :code:`p` stands for **picture**. 93 | * :code:`paging` means that if the data doesn't fit on screen, user will be able to navigate through multiple screens to see the data (e.g a public key). 94 | * And the number of letters used stands for the **number of lines**! 95 | 96 | Note that **all combinations of letters are not possible**. For example :code:`paging` only exists with :code:`bnnn`. :code:`nnnn` only exists on NanoX, etc... 97 | 98 | Now that you know all that, here's a table with the **most commonly used layouts**: 99 | 100 | .. list-table:: Most commonly used layouts 101 | :widths: 5 55 40 102 | :header-rows: 1 103 | 104 | * - Denomination 105 | - Comment 106 | - Usage 107 | * - :code:`bn` 108 | - Bold font for the first line, normal font for the second line. 109 | - :code:`bn, {"BoldLine", "NormalLine"}` 110 | * - :code:`pb` 111 | - Picture for the first line, bold font for the second line. 112 | - :code:`pb, {&RefToPicture, "BoldLine"}` 113 | * - :code:`pnn` 114 | - Picture for the first line, normal font for the second line and third line. 115 | - :code:`pnn, {&RefToPicture, "NormalLine1", "NormalLine2"}` 116 | * - :code:`bnnn_paging` 117 | - Bold first line, normal fonts for the other lines. If the data to be displayed doesn't fit on a single screen, the user will be able to navigate through different screens to see the whole text. 118 | - :code:`bnnn_paging, {.title = "BoldLine", .text = "NormalLine"}` 119 | 120 | 121 | .. |nanos_bnnn_paging| image:: images/nanos/nanos_address_merged.png 122 | :scale: 100% 123 | .. |nanox_bnnn_paging| image:: images/nanox/nanox_address_merged.png 124 | :scale: 100% 125 | .. |nanos_bn| image:: images/nanos/nanos_amount.png 126 | :scale: 100% 127 | .. |nanox_bn| image:: images/nanox/nanox_amount.png 128 | :scale: 100% 129 | .. |nanos_pb| image:: images/nanos/nanos_approve.png 130 | :scale: 100% 131 | .. |nanox_pb| image:: images/nanox/nanox_approve.png 132 | :scale: 100% 133 | .. |nanos_pnn| image:: images/nanos/nanos_boilerplate.png 134 | :scale: 100% 135 | .. |nanox_pnn| image:: images/nanox/nanox_boilerplate.png 136 | :scale: 100% 137 | 138 | And here's a table that compares how those layouts are displayed on a Nano S and on a Nano X! 139 | 140 | Notice that the **Nano X can fit up to 4 lines**, whereas the **Nano S can only fit 2**! 141 | 142 | .. list-table:: Comparing end results on NanoS and NanoX 143 | :widths: 10 40 40 144 | :header-rows: 1 145 | 146 | * - LAYOUT 147 | - NANOS 148 | - NANOX 149 | * - :code:`pb` 150 | - |nanos_pb| 151 | - |nanox_pb| 152 | * - :code:`bn` 153 | - |nanos_bn| 154 | - |nanox_bn| 155 | * - :code:`pnn` 156 | - |nanos_pnn| 157 | - |nanox_pnn| 158 | * - :code:`bnnn_paging` 159 | - |nanos_bnnn_paging| 160 | - |nanox_bnnn_paging| 161 | 162 | You're now ready to go and fly on your owns wings! Flows, steps, and layouts are no mystery to you anymore! We've added a couple of examples just down below, because an example is worth 16x16 words... 163 | 164 | Examples 165 | ======== 166 | 167 | Menu 168 | ---- 169 | 170 | Here's a typical flow for any app that will display its name (along with its logo), then its version, then the settings and finally a quit (along with a icon). 171 | 172 | .. code-block:: c 173 | 174 | UX_STEP_NOCB(step_menu, pnn, {&C_app_logo, "App", "is ready"}); 175 | UX_STEP_NOCB(step_version, bn, {"Version", &g_version}); 176 | UX_STEP_CB(step_settings, pb, ui_settings_menu(), {&C_icon_settings, "Settings"}) 177 | UX_STEP_CB(step_exit_step, pb, os_sched_exit(-1), {&C_icon_dashboard_x, "Quit"}); 178 | 179 | UX_FLOW(ux_app_dashboard, 180 | &step_menu, 181 | &step_version, 182 | &step_settings, 183 | &step_exit_step, 184 | FLOW_LOOP 185 | ); 186 | 187 | You guessed it, pressing both buttons when on the `QUIT` screen will call :code:`os_sched_exit(-1)`, effectively quitting the app. Pressing both button while on the :code:`Settings` screen will call :code:`ui_settings_menu()`, another function that you need to define with :code:`UX_FLOW` ! 188 | We also added the :code:`FLOW_LOOP` step at the end to have the menu wrap around. Users can now indefinitely cycle through the menu, yay! 189 | 190 | Signing a transaction 191 | --------------------- 192 | 193 | Here's the example of a flow to sign a transaction. 194 | We first display "Confirm address" along with a picture, then use :code:`bnnn_paging` to 195 | display the address because it might not fit on a single screen. 196 | We then display the amount and the transactions fees, and finally add two callack steps: 197 | the first one to confirm, the second one to reject. 198 | 199 | .. code-block:: c 200 | 201 | UX_STEP_NO_CB(step_review, pn, {&C_icon_eye, "Confirm Address"}); 202 | UX_STEP_NO_CB(step_address, bnnn_paging, { .title = "Address", .text = &g_destination_address}); 203 | UX_STEP_NO_CB(step_amount, bn, {"Amount", &g_amount}); 204 | UX_STEP_NO_CB(step_fees, bn, {"Fees", &g_fees}); 205 | UX_STEP_CB(step_approve, pb, sign_transaction(), {&C_icon_validate_14, "Approve"}); 206 | UX_STEP_CB(step_reject, pb, reject_transaction(), {&C_icon_crossmark, "Reject"}); 207 | 208 | UX_FLOW(ux_sign_transaction, 209 | &step_review, 210 | &step_address, 211 | &step_amount, 212 | &step_fees, 213 | &step_approve, 214 | &step_reject 215 | ); 216 | 217 | Advanced display management 218 | ---------------------------- 219 | 220 | A special :doc:`advanced display management ` section has been written where we detail more advanced UX_FLOW delcaration. Another :doc:`low_level_display_management` ` has details about the inner-workings of flows, but definitely feel free to skip it as it is in no way required to be able to write new apps! 221 | -------------------------------------------------------------------------------- /source/userspace/images/common_protocols.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/common_protocols.png -------------------------------------------------------------------------------- /source/userspace/images/deadbeef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/deadbeef.png -------------------------------------------------------------------------------- /source/userspace/images/debug_nano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/debug_nano.jpg -------------------------------------------------------------------------------- /source/userspace/images/nanos/nanos_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanos/nanos_address.png -------------------------------------------------------------------------------- /source/userspace/images/nanos/nanos_address_merged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanos/nanos_address_merged.png -------------------------------------------------------------------------------- /source/userspace/images/nanos/nanos_amount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanos/nanos_amount.png -------------------------------------------------------------------------------- /source/userspace/images/nanos/nanos_approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanos/nanos_approve.png -------------------------------------------------------------------------------- /source/userspace/images/nanos/nanos_boilerplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanos/nanos_boilerplate.png -------------------------------------------------------------------------------- /source/userspace/images/nanox/nanox_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanox/nanox_address.png -------------------------------------------------------------------------------- /source/userspace/images/nanox/nanox_address_merged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanox/nanox_address_merged.png -------------------------------------------------------------------------------- /source/userspace/images/nanox/nanox_amount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanox/nanox_amount.png -------------------------------------------------------------------------------- /source/userspace/images/nanox/nanox_approve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanox/nanox_approve.png -------------------------------------------------------------------------------- /source/userspace/images/nanox/nanox_boilerplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LedgerHQ/ledger-dev-doc/6463636831f196ef8522bfe19d588f2f6d05e22a/source/userspace/images/nanox/nanox_boilerplate.png -------------------------------------------------------------------------------- /source/userspace/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | In this chapter we will provide a general tutorial for getting your BOLOS 5 | development environment set up, followed by some detailed explanations of the 6 | various components of the BOLOS SDKs and what userspace development entails. It 7 | is assumed that you have already read the :doc:`BOLOS Platform 8 | ` chapter and are somewhat familiar with the BOLOS 9 | architecture. 10 | -------------------------------------------------------------------------------- /source/userspace/low_level_display_management.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Low-level display management 3 | ============================ 4 | 5 | .. warning:: 6 | 7 | This article only concerns about 1% of users who wish to get a deeper understanding / design more advanced flows. Feel free to skip it! 8 | 9 | The BOLOS SDKs contain a toolkit for building GUIs called the BOLOS Application 10 | Graphics Library (BAGL). BAGL defines a few useful types, most notably 11 | ``bagl_element_t``. This type defines a single display element, such as a 12 | rectangle, a line of text, a touchable button (in the case of the Ledger Blue), 13 | et cetera. Therefore, an entire GUI consists of an entire array of such 14 | elements. As the device hardware, including the screen, is managed by the MCU, 15 | the BAGL elements need to be transported to the MCU over SEPROXYHAL in order to 16 | display them. This is done using a Display Status. 17 | 18 | A Display Status may be used to send a single BAGL element to the MCU. However, 19 | due to the design of the E/Cs/S protocol, in order to send a sequence of BAGL 20 | elements the application must asynchronously send Display Statuses and wait for 21 | Display Processed Events before sending the next one, as well as handling the 22 | other Events that are received from the MCU in the mean time. As this is 23 | something that must be done by every BOLOS application, a set of utilities have 24 | been defined in the SDK to facilitate this process. These utilities also 25 | simplify the process of handling user input events, such as button presses. 26 | 27 | Asynchronous Display and Interaction Helpers 28 | -------------------------------------------- 29 | 30 | To facilitate the process of implementing an asynchronous display manager loop, 31 | a set of macros have been defined in the BOLOS SDKs. All these macros have the 32 | prefix ``UX_``, and use a global variable of type ``ux_state_t`` called ``ux`` 33 | to maintain the user interface state. 34 | 35 | 36 | ``UX_INIT(...)`` 37 | This macro is to be called when initializing the application, prior to 38 | sending the first Display Status. 39 | 40 | ``UX_DISPLAY(...)`` 41 | This macro takes an array of BAGL elements to be displayed and renders them, 42 | asynchronously. It is to be called when a new screen is to be displayed over 43 | the current one. This macro only sends the first element of the given array 44 | using a Display Status. Therefore, further Commands and Statuses are 45 | prohibited until the Display Processed Event is sent by the MCU. 46 | 47 | ``UX_REDISPLAY()`` 48 | This macro restarts the process of drawing the current screen. It behaves 49 | like ``UX_DISPLAY(...)``, but takes no arguments. 50 | 51 | ``UX_DISPLAYED()`` 52 | This macro returns 0 when the array requested to be displayed by 53 | ``UX_DISPLAY(...)`` or ``UX_REDISPLAY()`` has not been displayed entirely, or 54 | a non-zero value when it has. 55 | 56 | ``UX_DISPLAYED_EVENT(...)`` 57 | This macro is to be called to handle Display Processed Events (generally in 58 | the ``io_event(...)`` function). It displays the next element in the array 59 | given as a parameter to ``UX_DISPLAY(...)``. This macro sends a Display 60 | Status if an element remains to be displayed in the given array. Therefore, 61 | further Commands and Statuses are prohibited until the Display Processed 62 | Event is sent by the MCU. 63 | 64 | ``UX_BUTTON_PUSH_EVENT(...)`` 65 | This macro facilitates handling of Button Push Events, by setting the button 66 | released flag and calling the button handler implicitly passed to 67 | ``UX_DISPLAY(...)``. 68 | 69 | See `the sample apps `_ for 70 | examples of how to use these macros. The main concept to remember is that after 71 | a Display Status has been sent, the application must wait, asynchronously, for 72 | the Display Processed Event before being able to continue to display more 73 | elements of the GUI. 74 | 75 | .. _bolos-ux: 76 | 77 | BOLOS UX 78 | -------- 79 | 80 | The BOLOS UX is the implementation of the device-wide user interface; it is a 81 | component of the :ref:`dashboard `. Applications delegate certain 82 | jobs to the BOLOS UX in order to retain consistency across all apps for certain 83 | UI components (like the status bar on the Ledger Blue), as well as to allow the 84 | operating system to override the application's UI when necessary (for example, 85 | when locking the screen). The application interfaces with the BOLOS UX using 86 | ``os_ux(...)``, which is a syscall. However, applications don't need to call 87 | this function directly as it is automatically called by the display interaction 88 | helpers (the ``UX_`` macros). 89 | 90 | Applications should delegate Events like Button Push Events to the BOLOS UX (in 91 | this case, using ``UX_BUTTON_PUSH_EVENT(...)``) instead of handling them 92 | directly in case the BOLOS UX needs to override the application's UI. If the 93 | event is consumed by the BOLOS UX (for example, a button press while the user is 94 | unlocking the screen) then the event is not passed on to the application. 95 | -------------------------------------------------------------------------------- /source/userspace/memory.rst: -------------------------------------------------------------------------------- 1 | Persistent Storage and PIC 2 | ========================== 3 | 4 | BOLOS applications have access to two different types of memory in the Secure 5 | Element: a small amount of RAM for the call stack and certain global variables, 6 | and a considerably larger amount of flash memory for persistent storage. Access 7 | to flash memory is regulated by the Memory Protection Unit which is configured 8 | by BOLOS to prevent applications from tampering with parts of flash memory that 9 | they shouldn't. However, applications are able to access the part of flash 10 | memory where their constant data and code is defined. This data includes code 11 | and ``const`` variables, but applications may also allocate extra space in NVRAM 12 | to be used at runtime for persistent storage. 13 | 14 | Types of Memory 15 | --------------- 16 | 17 | All global variables that are declared as ``const`` are stored in read-only 18 | flash memory, right next to code. All normal global variables that are declared 19 | as non-``const`` are stored in RAM. However, thanks to the link script 20 | (``script.ld``) in the SDK, global variables that are declared as non-``const`` 21 | and are given the prefix ``N_`` are placed in a special write-permitted location 22 | of NVRAM. This data can be read in the same way that regular global variables 23 | are read. However, writing to NVRAM variables must be done using the 24 | ``nvm_write(...)`` function defined by the SDK, which performs a syscall. When 25 | loading the app, NVRAM variables are initialized with data specified in the 26 | app's hex file (this is usually just zero bytes). 27 | 28 | .. warning:: 29 | 30 | Initializers of global non-``const`` variables (including NVRAM variables) 31 | are ignored. As such, this data must be initialized by application code. 32 | 33 | .. _flash-memory-endurance: 34 | 35 | Flash Memory Endurance 36 | ---------------------- 37 | 38 | The flash memory for the `ST31G480 39 | `_, which is the Secure Element 40 | used in the Ledger Blue, is rated for 500 000 erase / write cycles. This should 41 | be more than enough to last the expected lifetime of the device, but only if 42 | applications use it properly. Applications should avoid erasures as much as 43 | possible. Here are some techniques for avoiding wearing out the device's flash 44 | memory. 45 | 46 | Firstly, if you intend to be changing data in flash memory many times while an 47 | application is running, consider caching the data in RAM and then flushing to 48 | flash memory when the application has finished its operation. This of course has 49 | the downside of possible data loss if the user powers off the device (perhaps by 50 | unplugging it, in the case of the Nano S) before the data has been written to 51 | persistent storage. Secondly, developers should be aware that flash memory pages 52 | are aligned to 64-byte boundaries. The rating of 500 000 erase / write cycles 53 | mentioned earlier means that each page in flash memory is expected to survive 54 | 500 000 erasures. As such, one can develop an application that writes to as few 55 | pages as possible. For example, if you intend to store 32 bytes of data in flash 56 | memory, write amplification can be avoided by making sure that 32 bytes of data 57 | is contained entirely within a single page (and modified using only a single 58 | call to ``nvm_write(...)``). If the data crossed a 64-byte page boundary, then 59 | writing to it once may require two pages to be erased instead of just one. 60 | 61 | In the future, Ledger will provide various persistent storage utilities within 62 | BOLOS and the SDKs to simplify the process of using flash memory efficiently. 63 | 64 | PIC and Model Implications 65 | -------------------------- 66 | 67 | PIC stands for Position-Independent Code. The BOLOS toolchain produces PIC to 68 | allow for the code **Link address** to be different from the code **Execution 69 | address**. For example, the ``main`` function is linked in the generated 70 | application at address ``0xC0D00000``. However, the slot used when loaded into 71 | the Secure Element could be ``0x10E40400``. Therefore, if the code makes a 72 | reference to ``0xC0D00000``, even with an offset, it would be denied access as 73 | the application is locked by the Memory Protection Unit (not to mention, this is 74 | not the correct address of the ``main`` function at runtime). 75 | 76 | The PIC assembly generator makes sure every dereference is relative to the 77 | Program Counter, and never to an arbitrary address resolved during the link 78 | stage. This behavior is supported by clang versions 4.0.0 and later. 79 | 80 | Traditionally, PIC code implies the BSS segment (RAM variables) is at a constant 81 | offset of the code. For example, if code is at ``0xC0D00000``, then global vars 82 | may be at ``0xC2D00000``, so if loaded at ``0x10E00000`` then global vars would 83 | be at ``0x12E00000``. However, BOLOS uses a fixed address for global vars. The 84 | global variables start address and length are defined in the link script. Only 85 | the code is meant to be placed at different addresses (in flash memory, rather 86 | than RAM). 87 | 88 | The model we chose has limitations, which are related to the way ``const`` data 89 | and code is referenced in other ``const`` data. Here is a simple example: 90 | 91 | .. code-block:: c 92 | 93 | const char array1[] = {1, 2, 3, 4}; 94 | const char array2[] = {1, 2, 3, 4}; 95 | const char *array_2d[] = {array1, array2}; 96 | 97 | void main() { 98 | int sum, i, j; 99 | sum = 0; 100 | for (i = 0; i < 2; i++) { 101 | for (j = 0; j < 4; j++) { 102 | sum += array_2d[i][j]; // Segmentation Fault! 103 | } 104 | } 105 | } 106 | 107 | In the example above, when dereferencing ``array_2d``, the compiler uses a 108 | link-time address (in the ``0xC0D00000`` space, following the previous 109 | examples). This is not where the program is loaded in memory at runtime. 110 | Therefore, when the dereference is executed, it causes a segmentation fault that 111 | effectively stalls the SE. Luckily, the solution is pretty simple, thanks to a 112 | small piece of assembly provided with the SDKs which is invoked with the 113 | ``PIC(...)`` macro. ``PIC(...)`` uses the current load address to adjust the 114 | link-time address in order to acquire the correct runtime address of ``const`` 115 | data and code. The above examples can be corrected by modifying the line where 116 | ``array_2d`` is dereferenced to do the following: 117 | 118 | .. code-block:: c 119 | 120 | sum += ((const char*) PIC(array_2d[i]))[j]; 121 | 122 | The same mechanism must be applied when storing function pointers in ``const`` 123 | data. The PIC call cast is just different. Additionally, if a non-link-time 124 | address is passed to ``PIC(...)``, then it will be preserved. This is possible 125 | due to the wisely chosen link-time address which is beyond both real RAM and 126 | loadable addresses. For example, ``PIC(...)`` is used during a call to 127 | ``io_seproxyhal_display_default(...)``, all display elements can hold a 128 | reference to a string to be displayed with the element, and the string could be 129 | in RAM or code, and therefore ``PIC(...)`` is applied to acquire the correct 130 | runtime address of the string, even if it's in RAM. 131 | -------------------------------------------------------------------------------- /source/userspace/setup.rst: -------------------------------------------------------------------------------- 1 | Setup 2 | =============== 3 | 4 | .. warning:: 5 | 6 | Only Linux is supported as a development OS. For Windows and MacOS users, a Linux VM is recommended. 7 | 8 | Developing and / or compiling BOLOS applications requires the SDK matching the 9 | appropriate device (the Nano S, X SDK or the Blue SDK) as well as the following two 10 | compilers: 11 | 12 | * A standard ARM gcc to build the non-secure (STM32) firmware and link the 13 | secure (ST31) applications 14 | * A standard ARM clang `7.0.0 <= version < 10.0.0` with `ROPI support 15 | `_ 16 | to build the secure (ST31) applications, download it `here `_ 17 | * Download a prebuilt gcc from `here 18 | `_ 19 | 20 | 21 | Setting up the Toolchain 22 | ------------------------ 23 | 24 | The Makefiles used by our BOLOS applications look for gcc and clang 25 | installations using the ``PATH`` environment variable. 26 | 27 | If you don't want to install specific versions of clang and gcc directly on your system, 28 | simply prepend their location in your ``PATH`` environment variable. 29 | 30 | .. code-block:: bash 31 | 32 | # GCC 33 | PATH=~/bolos-devenv/gcc-arm-none-eabi-10-2020-q4-major-linux/bin:$PATH 34 | 35 | # Clang 36 | PATH=~/bolos-devenv/clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04/bin:$PATH 37 | 38 | 39 | Cross compilation headers are required and provided within the gcc-multilib and g++-multilib packages. 40 | To install them on a debian system: 41 | 42 | .. code-block:: bash 43 | 44 | sudo apt install gcc-multilib g++-multilib 45 | 46 | If you wish to load applications on your device, you will also need to add the appropriate :code:`udev` rules. 47 | 48 | .. code-block:: bash 49 | 50 | wget -q -O - https://raw.githubusercontent.com/LedgerHQ/udev-rules/master/add_udev_rules.sh | sudo bash 51 | 52 | Setting up the SDK 53 | ------------------ 54 | 55 | Now that you have your toolchain set up, you need to download / clone the SDK 56 | for the appropriate Ledger device you're working with. 57 | Make sure you checkout the tag matching your firmware version. 58 | 59 | Ledger Nano S SDK: https://github.com/LedgerHQ/nanos-secure-sdk 60 | 61 | Ledger Nano X SDK: https://github.com/LedgerHQ/nanox-secure-sdk 62 | 63 | Ledger Blue SDK: https://github.com/LedgerHQ/blue-secure-sdk 64 | 65 | 66 | Finally, link the environment variable ``BOLOS_SDK`` to the SDK you downloaded. 67 | 68 | .. code-block:: bash 69 | 70 | BOLOS_SDK='/path/to/sdk/' 71 | 72 | When using the Makefile for our BOLOS apps, the Makefile will use the contents 73 | of the SDK to determine your target device ID (Ledger Nano S, X or Ledger Blue). 74 | Even if you aren't building an app, loading an app with the Makefile still 75 | requires you to have the SDK for the appropriate device linked to by 76 | ``BOLOS_SDK``. 77 | 78 | Python Loader 79 | ------------- 80 | 81 | Most apps use the Python loader, a Ledger-made Python library to communicate with Ledger devices. 82 | 83 | To install it, you will need to add a couple of extra dependencies: 84 | 85 | .. code-block:: bash 86 | 87 | sudo apt install virtualenv libudev-dev libusb-1.0-0-dev 88 | 89 | You will also need the :code:`python-dev-tools` (aka :code:`python-dev` on Python 2) package 90 | 91 | .. code-block:: bash 92 | 93 | python3 -m pip install python-dev-tools --user --upgrade 94 | python3 -m pip install ledgerblue 95 | 96 | If you need more information about the Python loader, feel free to check out the github repo: https://github.com/LedgerHQ/blue-loader-python . 97 | You should find what you're looking for in the :code:`doc` folder and :code:`README.md` . 98 | 99 | Now that you're setup and ready to go, you can start looking at our :doc:`Writing Apps ` article! -------------------------------------------------------------------------------- /source/userspace/speculos.rst: -------------------------------------------------------------------------------- 1 | Emulating devices with Speculos 2 | =============================== 3 | 4 | Ledger has developed its own Ledger Nano S / Ledger Nano X / Ledger Blue emulator, called `Speculos `_. This emulator can be useful if you want to run tests, debug your app with GDB, or just try your app without having to physically plug-in your Ledger device. 5 | 6 | We will go over a quick guide to using speculos, but more information is available in `speculos dedicated documentation `_ or in the `docs section of the github page `_. 7 | 8 | Setup 9 | ----- 10 | 11 | 1. Start by cloning the `official Speculos repo `_:: 12 | 13 | git clone https://github.com/LedgerHQ/speculos 14 | 15 | 2. Make sure you have the appropriate packages installed on your machine:: 16 | 17 | sudo apt install qemu-user-static python3-pyqt5 python3-construct python3-jsonschema python3-mnemonic python3-pyelftools gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gdb-multiarch 18 | 19 | 3. Build:: 20 | 21 | cmake -Bbuild -H. 22 | make -C build/ 23 | 24 | Please note that the first build can take some time because a tarball of OpenSSL is downloaded (the integrity of the downloaded tarball is checked) before being built. Further invocations of ``make`` skip this step. 25 | 26 | The following command line can be used for a debug build:: 27 | 28 | cmake -Bbuild -DCMAKE_BUILD_TYPE=Debug -H. 29 | 30 | Usage 31 | ----- 32 | 33 | .. warning:: 34 | 35 | Only run Speculos on trusted apps, as a malicious app could exploit it and make arbitrary Linux system calls. 36 | 37 | To run your application, simply type in:: 38 | 39 | ./speculos.py /path/to/app.elf 40 | 41 | You can then use your left / right arrows to emulate the left and right buttons of your device. 42 | 43 | Communicating with the device 44 | ----------------------------- 45 | 46 | You can communicate with the emulated device using `APDUs `_. Speculos embbeds a TCP server (listening on ``127.0.0.1:9999``) to forwards APDUs to the target app. 47 | 48 | In this example we will use the `ledgerctl `_ client that you can install with ``pip``:: 49 | 50 | pip3 install ledgerwallet 51 | 52 | If the environment variables ``LEDGER_PROXY_ADDRESS`` and ``LEDGER_PROXY_PORT`` are set, the library ill try to use the device emulated by Speculos. For instance, the following command-line sends the APDU ``e0 c4 00 00 00`` (Bitcoin-app's APDU to request the version):: 53 | 54 | $ ./speculos.py /path/to/app.elf & # First start the app in the background 55 | $ echo 'e0c4000000' | LEDGER_PROXY_ADDRESS=127.0.0.1 LEDGER_PROXY_PORT=9999 ledgerctl send - 56 | 10:01:09.546:apdu: > e0c4000000 57 | 10:01:09.547:apdu: < 6d00 58 | 6d00 59 | 60 | Other clients are available (ledgerblue, btchip-python...) and you will find more information in `speculos' doc `_. 61 | 62 | Debugging with GDB 63 | ------------------ 64 | 65 | Speculos can also be used to debug your code with GDB:: 66 | 67 | ./speculos.py -d /path/to/app.elf & 68 | ./tools/debug.sh /path/to/app.elf 69 | 70 | This command should start a brand new gdb instance with your app already loaded ! 71 | 72 | Debugging inside Visual Studio Code 73 | ----------------------------------- 74 | 75 | Visual Studio Code users might be happy to learn that debugging through the usual VSCode interface is made possible using speculos. 76 | 77 | In your ``.vscode`` file, simply create a ``launch.json`` file containing this:: 78 | 79 | { 80 | "version": "0.2.0", 81 | "configurations": [ 82 | { 83 | "type": "gdb", 84 | "request": "attach", 85 | "name": "Attach to gdbserver", 86 | "executable": "${workspaceFolder}/bin/app.elf", 87 | "target": ":1234", 88 | "remote": true, 89 | "cwd": "${workspaceFolder}", 90 | "valuesFormatting": "parseText", 91 | "gdbpath": "gdb-multiarch", 92 | "autorun": [ 93 | "set architecture arm", 94 | "handle SIGILL nostop pass noprint", 95 | "add-symbol-file ${workspaceFolder}/bin/app.elf 0x40000000", 96 | "b *0x40000000", 97 | "c" 98 | ] 99 | } 100 | ] 101 | } 102 | 103 | Make sure you have `Native Debug's extension `_ installed. 104 | Then, follow these steps: 105 | 106 | 107 | 1. Set a breakpoint (click on the left-hand side of the line you want to set a breakpoint on). 108 | 2. In a new terminal, attach speculos (run ``./speculos.py -d /path/to/app.elf``). 109 | 3. In VSCode, press F5 to start the debugging session. You're good to go ! 110 | 111 | If your device is in a loop (if you get the error ``Cannot execute this command while the selected thread is running``), then you probably need to send an APDU to the device to actually reach the breakpoint you've set. Please refer to the `Communicating with the device`_ section. 112 | -------------------------------------------------------------------------------- /source/userspace/syscalls.rst: -------------------------------------------------------------------------------- 1 | Interaction Between BOLOS and Apps 2 | ================================== 3 | 4 | Since BOLOS is designed based on a single-task model where only a single app 5 | runs at any given time, an application is independently responsible for a lot of 6 | the things a typical OS would do. These things include managing hardware like 7 | the device screen, buttons, timer, etc. as well as handling all I/O with 8 | peripherals. However, there are many instances where a BOLOS application has to 9 | request the operating system to perform a certain operation. This is done using 10 | a syscall. 11 | 12 | When an application performs a syscall, the Secure Element switches to 13 | Supervisor mode and the OS performs the requested task before returning control 14 | back to the application, in User mode. All syscalls have a wrapper function in 15 | the SDK that can be used to invoke them. A syscall may be used to access 16 | hardware accelerated cryptographic primitives (most of these functions are 17 | defined in ``include/cx.h`` in the SDKs), to perform low-level I/O operations 18 | (like receiving / transmitting to the MCU), or to access cryptographic secrets 19 | managed by BOLOS (for example, to derive a node from the BIP 32 master node). 20 | 21 | Error Model 22 | ----------- 23 | 24 | If you are familiar with C programming, you will be used to error codes as the 25 | default error model. However, when programming in the embedded world, this 26 | traditional model reaches its limits, and can quickly overcomplicate large 27 | codebases. Therefore, we've implemented a try / catch system that supports 28 | nesting (direct or transitive) using the ``setjmp`` and ``longjmp`` API to 29 | facilitate writing robust code. 30 | 31 | Here is an example of a typical try / catch / finally construct: 32 | 33 | .. code-block:: c 34 | 35 | BEGIN_TRY { 36 | TRY { 37 | // Perform some operation that may throw an error using THROW(...) 38 | } CATCH_OTHER(e) { 39 | // Handle error 40 | } FINALLY { 41 | // Always executed before continuing control flow 42 | } 43 | } END_TRY; 44 | 45 | However there is a single constraint to be aware of with our try / catch system: 46 | a ``TRY`` clause must always be closed in the appropriate way. This means that 47 | if using a return, break, continue or goto statement that jumps out of the 48 | ``TRY`` clause you MUST manually close it, or it could lead to a crash of the 49 | application in a later ``THROW``. A ``TRY`` clause can be manually closed using 50 | ``CLOSE_TRY``. Using ``CLOSE_TRY`` is only necessary when jumping out of a 51 | ``TRY`` clause, jumping out of a ``CATCH`` or ``FINALLY`` clause is allowed (but 52 | still, be careful you're not in a ``CATCH`` nested in a ``TRY``). 53 | 54 | You should use the error codes defined in the SDKs wherever possible (see 55 | ``EXCEPTION``, ``INVALID_PARAMETER``, etc. in ``os.h``). If you decide to use 56 | custom error codes, never use an error code of ``0``. 57 | 58 | Developers should avoid creating a new try context wherever possible in order to 59 | reduce code size and stack usage. Preferably, an application should only have a 60 | single top-level try context at the application entry point (in ``main()``). 61 | 62 | Syscall Requirements 63 | -------------------- 64 | 65 | BOLOS is based on an exception model for error reporting, therefore, it expects 66 | the application to call the BOLOS API using this mechanism. If an API function 67 | is called from outside a ``TRY`` context, then the BOLOS call is denied. 68 | 69 | Here is a valid way to call a system entry point: 70 | 71 | .. code-block:: c 72 | 73 | BEGIN_TRY { 74 | TRY { 75 | cx_hash_sha512(...); 76 | } FINALLY {} 77 | } END_TRY; 78 | 79 | However, as mentioned above, it is preferred to use as few try contexts as 80 | possible (not one per syscall). A single, top-level try context can be used to 81 | catch any exception thrown by any syscall performed by the application. 82 | -------------------------------------------------------------------------------- /source/userspace/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | Common Pitfalls and Troubleshooting 2 | =================================== 3 | 4 | In this section, we'll walk you through a lot of concepts that are hard to grasp 5 | when developing on the BOLOS platform, and we'll provide some analysis of common 6 | failure scenarios that you might experience while developing applications. 7 | 8 | Not Enough RAM 9 | -------------- 10 | 11 | At the time of this writing, the default link script provided by the SDK for the 12 | Ledger Nano S allocates 4 KiB of RAM for applications to use. This 4 KiB has to 13 | be enough to store all global non-const and :doc:`non-NVRAM ` variables 14 | as well as the call stack (which is currently set to 768 bytes by default, also 15 | defined in the link script). 16 | 17 | This is the linker error you will experience if you declare too many global 18 | non-const and non-NVRAM variables to fit in RAM: 19 | 20 | .. code-block:: none 21 | 22 | bin/app.elf section `.bss' will not fit in region `SRAM' 23 | 24 | The only solution to this problem is, of course, using less RAM. You can 25 | accomplish this by making your application's memory layout more efficient. 26 | Alternatively, if you're feeling adventurous, you can attempt to modify the link 27 | script (``script.ld`` in the SDKs) to optimize the space allocated for the call 28 | stack. If you choose to pursue the latter option, we recommend you read the next 29 | section as well. 30 | 31 | Stack Overflows 32 | --------------- 33 | 34 | Determining the exact amount of the call stack used by your application can be 35 | difficult to do without simply running your application. The technique we 36 | recommend for avoiding stack overflows is using a stack canary. Creating a stack 37 | canary involves setting a magic value at the start of the stack area (the stack 38 | grows towards lower addresses, so a canary at the start of this region will be 39 | located at the top of the stack), and then the canary is checked regularly. If 40 | the canary was modified, then this means there was a stack overflow. 41 | 42 | In a future version of the BOLOS SDKs, this feature will be implemented 43 | automatically. Until then, this is the recommended way to implement a stack 44 | canary: 45 | 46 | .. code-block:: c 47 | 48 | // This symbol is defined by the link script to be at the start of the stack 49 | // area. 50 | extern unsigned long _stack; 51 | 52 | #define STACK_CANARY (*((volatile uint32_t*) &_stack)) 53 | 54 | void init_canary() { 55 | STACK_CANARY = 0xDEADBEEF; 56 | } 57 | 58 | void check_canary() { 59 | if (STACK_CANARY != 0xDEADBEEF) 60 | THROW(EXCEPTION_OVERFLOW); 61 | } 62 | 63 | The canary should be checked regularly. For example, you could run the check 64 | every time ``io_event(...)`` is called. 65 | 66 | Error Handling 67 | -------------- 68 | 69 | Error handling in C can sometimes be a bit counter-intuitive. With our error 70 | model, there are two common failure scenarios. 71 | 72 | Firstly, you must take care to always close a try context when jumping out of 73 | it. For example, in the block of code below, the ``CLOSE_TRY`` macro must be 74 | used to close the try context before returning from the function in the case 75 | that ``i > 0``. However, in the ``CATCH`` clause, the try has already been 76 | closed automatically so ``CLOSE_TRY`` is not necessary. 77 | 78 | .. code-block:: c 79 | 80 | bool is_positive(int8_t i) { 81 | BEGIN_TRY { 82 | TRY { 83 | if (i == 0) 84 | THROW(EXCEPTION); 85 | if (i > 0) { 86 | CLOSE_TRY; 87 | return true; 88 | } 89 | } CATCH_OTHER(e) { 90 | return false; 91 | } FINALLY {} 92 | } END_TRY; 93 | return false; 94 | } 95 | 96 | Another common failure scenario is caused by the compiler making invalid 97 | assumptions when optimizing your code because it doesn't understand how our 98 | exception model works. To avoid this problem, when modifying variables within a 99 | try / catch / finally context, always declare those variables ``volatile``. 100 | 101 | .. code-block:: c 102 | 103 | uint16_t multiply(uint8_t a, uint8_t b) { 104 | volatile uint16_t product = 0; 105 | volatile uint8_t multiplier = b; 106 | while (true) { 107 | BEGIN_TRY { 108 | TRY { 109 | if (multiplier == 0) 110 | THROW(1); 111 | multiplier--; 112 | product += a; 113 | THROW(2); 114 | } CATCH_OTHER(e) { 115 | if (e == 1) 116 | return product; 117 | } FINALLY {} 118 | } END_TRY; 119 | } 120 | // Suppress compiler warning 121 | return 0; 122 | } 123 | 124 | In the above example, ``a`` does not need to be declared ``volatile`` because it 125 | is never modified. 126 | 127 | On another note, you should use the error codes defined in the SDKs wherever 128 | possible (see ``EXCEPTION``, ``INVALID_PARAMETER``, etc. in ``os.h``). If you 129 | decide to use custom error codes, never use an error code of ``0``. 130 | 131 | Application Stalled 132 | ------------------- 133 | 134 | An application stalling when run on the device (the device's screen freezes and 135 | stops responding to APDU) could be caused by a number of issues from the SE 136 | being isolated due to invalid handling of SEPROXYHAL packets, to a core fault on 137 | the device (perhaps due to a misaligned memory access or an attempt to access 138 | restricted memory). If this occurs, it is best to attempt to simplify the app 139 | and strip away as much code as possible until the problem can be isolated. 140 | 141 | Unaligned RAM access 142 | -------------------- 143 | 144 | .. code-block:: c 145 | 146 | uint16_t *ptr16 = &tmp_ctx.signing_context.buffer[processed]; 147 | PRINTF("uint16_t: %d", ptr16[0]); 148 | 149 | ``ptr16[0]`` access can be stalling the app, even though ``tmp_ctx.signing_context.buffer[processed]`` (``unsigned char*``) can be accessed alright. This happens when pointer isn't word-aligned, but word is access in RAM. Workaround is copying buffer into another location which is properly aligned (e.g. using `os_memmove`). 150 | 151 | Please refer to the :ref:`alignment ` page for further information. 152 | -------------------------------------------------------------------------------- /source/userspace/writing_apps.rst: -------------------------------------------------------------------------------- 1 | Writing Apps 2 | ============ 3 | 4 | Not much documentation has been written yet (work in progress!) regarding the exact steps to follow to write apps. However, very good codebases are available for you to learn from. 5 | 6 | * The `app-boilerplate `_ is a thoroughly documented app that was specifically designed for developers to play around with and read the code. 7 | * The `app-sia `_ is also a thoroughly documented app written by the community. If you wish to study a fully-fledged app, this is the one for you! 8 | 9 | Cloning and Making 10 | ------------------ 11 | 12 | Applications that support multiple BOLOS devices are 13 | typically contained within a single repository, so you can use the same 14 | repository to build an app for different Ledger devices. Just make sure that 15 | you've set ``BOLOS_SDK`` to the appropriate SDK for the device you're using. The 16 | Makefiles used by our apps use the contents of the SDK to determine which device 17 | you're using. 18 | 19 | First, download the boilerplate app. 20 | 21 | .. code-block:: bash 22 | 23 | git clone https://github.com/LedgerHQ/ledger-app-boilerplate.git 24 | 25 | Now you can let the Makefile do all the work. The ``load`` target will build the 26 | app if necessary and load it onto your device over USB. 27 | 28 | .. code-block:: bash 29 | 30 | cd ledger-app-boilerplate/ 31 | make load 32 | 33 | And you're done! After confirming the installation on your device, you should 34 | see an app named "Boilerplate". The app can be deleted like so: 35 | 36 | .. code-block:: bash 37 | 38 | make delete 39 | 40 | Display Management 41 | ------------------ 42 | 43 | The doc covered the art of displaying information on screen, go and check it out: :doc:`Display Management ` --------------------------------------------------------------------------------