LCOV - code coverage report
Current view: top level - ledger/ui/src - bootloader.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 83 105 79.0 %
Date: 2025-07-10 13:49:13 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /**
       2             :  * The MIT License (MIT)
       3             :  *
       4             :  * Copyright (c) 2021 RSK Labs Ltd
       5             :  *
       6             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       7             :  * of this software and associated documentation files (the "Software"), to
       8             :  * deal in the Software without restriction, including without limitation the
       9             :  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      10             :  * sell copies of the Software, and to permit persons to whom the Software is
      11             :  * furnished to do so, subject to the following conditions:
      12             :  *
      13             :  * The above copyright notice and this permission notice shall be included in
      14             :  * all copies or substantial portions of the Software.
      15             :  *
      16             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      19             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      21             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      22             :  * IN THE SOFTWARE.
      23             :  */
      24             : 
      25             : #include "bolos_ux_common.h"
      26             : 
      27             : #include "apdu.h"
      28             : #include "ux_handlers.h"
      29             : #include "bootloader.h"
      30             : #include "ui_instructions.h"
      31             : #include "defs.h"
      32             : #include "ui_err.h"
      33             : #include "ui_comm.h"
      34             : #include "unlock.h"
      35             : 
      36             : // Attestation context shorthand
      37             : #define attestation_ctx (G_bolos_ux_context.attestation)
      38             : 
      39             : // Signer authorization context shorthand
      40             : #define sigaut_ctx (G_bolos_ux_context.sigaut)
      41             : 
      42             : // Onboard context shorthand
      43             : #define onboard_ctx (G_bolos_ux_context.onboard)
      44             : 
      45             : // Operation being currently executed
      46             : static unsigned char current_cmd;
      47             : // Flag used to prevent executing commands after the onboard is performed
      48             : static bool onboard_performed = false;
      49             : 
      50             : // Macro that throws an error unless
      51             : // the device is not onboarded
      52             : #define REQUIRE_NOT_ONBOARDED()      \
      53             :     if (os_perso_isonboarded() == 1) \
      54             :         THROW(ERR_UI_DEVICE_ONBOARDED);
      55             : 
      56             : /*
      57             :  * Reset all reseteable operations, only if the given operation is starting.
      58             :  *
      59             :  * @arg[in] cmd operation code
      60             :  */
      61          16 : static void reset_if_starting(unsigned char cmd) {
      62             :     // Reset only if starting new operation (cmd != current_cmd).
      63             :     // Otherwise we already reset when current_cmd started.
      64          16 :     if (cmd != current_cmd) {
      65          16 :         current_cmd = cmd;
      66          16 :         reset_attestation(&attestation_ctx);
      67          16 :         reset_signer_authorization(&sigaut_ctx);
      68          16 :         reset_onboard_ctx(&onboard_ctx);
      69             :     }
      70          16 : }
      71             : 
      72           0 : static void reset_state() {
      73           0 :     reset_if_starting(0);
      74           0 : }
      75             : 
      76          20 : void bootloader_init() {
      77          20 :     current_cmd = 0;
      78          20 :     onboard_performed = false;
      79             : 
      80          20 :     reset_attestation(&attestation_ctx);
      81          20 :     reset_signer_authorization(&sigaut_ctx);
      82          20 :     reset_onboard_ctx(&onboard_ctx);
      83          20 : }
      84             : 
      85          24 : unsigned int bootloader_process_apdu(volatile unsigned int rx,
      86             :                                      bootloader_mode_t mode) {
      87          24 :     unsigned int tx = 0;
      88             : 
      89             :     // no apdu received, or bigger-than-apdu-buffer bytes received =>
      90             :     // well, reset the session, and reset the bootloader configuration
      91          24 :     if (rx == 0 || rx > APDU_TOTAL_SIZE) {
      92           2 :         THROW(ERR_INVALID_BUFFER);
      93             :     }
      94             : 
      95          22 :     if (APDU_CLA() != CLA) {
      96           1 :         THROW(ERR_UI_INVALID_CLA);
      97             :     }
      98             : 
      99             :     // We don't accept any command after onboard is performed in
     100             :     // onboard mode, the user is required to unplug the device
     101             :     // before proceeding
     102          21 :     if (mode == BOOTLOADER_MODE_ONBOARD && onboard_performed) {
     103           1 :         THROW(ERR_INS_NOT_SUPPORTED);
     104             :     }
     105             : 
     106             :     // unauthenticated instruction
     107          20 :     switch (APDU_CMD()) {
     108           2 :     case RSK_SEED_CMD: // Send wordlist
     109           2 :         REQUIRE_NOT_ONBOARDED();
     110           1 :         reset_if_starting(RSK_META_CMD_UIOP);
     111           1 :         tx = set_host_seed(rx, &onboard_ctx);
     112           1 :         break;
     113           1 :     case RSK_PIN_CMD: // Send pin_buffer
     114           1 :         reset_if_starting(RSK_META_CMD_UIOP);
     115           1 :         tx = update_pin_buffer(rx);
     116           1 :         break;
     117           2 :     case RSK_IS_ONBOARD: // Wheter it's onboarded or not
     118           2 :         reset_if_starting(RSK_IS_ONBOARD);
     119           2 :         tx = is_onboarded();
     120           2 :         break;
     121           5 :     case RSK_WIPE: //--- wipe and onboard device ---
     122           5 :         REQUIRE_NOT_ONBOARDED();
     123           3 :         reset_if_starting(RSK_META_CMD_UIOP);
     124           3 :         tx = onboard_device(&onboard_ctx);
     125           3 :         clear_pin();
     126           3 :         onboard_performed = true;
     127           3 :         break;
     128           1 :     case RSK_NEWPIN:
     129           1 :         reset_if_starting(RSK_META_CMD_UIOP);
     130           1 :         tx = set_pin();
     131           1 :         clear_pin();
     132           1 :         break;
     133           1 :     case RSK_ECHO_CMD: // echo
     134           1 :         reset_if_starting(RSK_ECHO_CMD);
     135           1 :         tx = echo(rx);
     136           1 :         break;
     137           1 :     case RSK_MODE_CMD: // print mode
     138           1 :         reset_if_starting(RSK_MODE_CMD);
     139           1 :         tx = get_mode_bootloader();
     140           1 :         break;
     141           1 :     case INS_ATTESTATION:
     142           1 :         reset_if_starting(INS_ATTESTATION);
     143           1 :         tx = get_attestation(rx, &attestation_ctx);
     144           1 :         break;
     145           1 :     case INS_SIGNER_AUTHORIZATION:
     146           1 :         reset_if_starting(INS_SIGNER_AUTHORIZATION);
     147           1 :         tx = do_authorize_signer(rx, &sigaut_ctx);
     148           1 :         break;
     149           1 :     case RSK_RETRIES:
     150           1 :         reset_if_starting(RSK_RETRIES);
     151           1 :         tx = get_retries();
     152           1 :         break;
     153           1 :     case RSK_UNLOCK_CMD: // Unlock
     154           1 :         reset_if_starting(RSK_META_CMD_UIOP);
     155           1 :         tx = unlock();
     156             :         // The pin value could also be used in
     157             :         // BOLOS_UX_CONSENT_APP_ADD command, so we can't wipe the
     158             :         // pin buffer here
     159           1 :         break;
     160           1 :     case RSK_END_CMD: // return to dashboard and run the app
     161           1 :         reset_if_starting(RSK_END_CMD);
     162           1 :         set_dashboard_action(DASHBOARD_ACTION_APP);
     163           1 :         THROW(EX_BOOTLOADER_RSK_END);
     164           1 :     case RSK_END_CMD_NOSIG: // return to dashboard
     165           1 :         reset_if_starting(RSK_END_CMD_NOSIG);
     166           1 :         set_dashboard_action(DASHBOARD_ACTION_DASHBOARD);
     167           1 :         THROW(EX_BOOTLOADER_RSK_END);
     168           1 :     default:
     169           1 :         THROW(ERR_INS_NOT_SUPPORTED);
     170             :         break;
     171             :     }
     172             : 
     173          14 :     return tx;
     174             : }
     175             : 
     176             : // Main function for the bootloader. If mode == BOOTLOADER_MODE_ONBOARD,
     177             : // commands are not accepted after the onboard is performed.
     178           0 : void bootloader_main(bootloader_mode_t mode) {
     179           0 :     volatile unsigned int rx = 0;
     180           0 :     volatile unsigned int tx = 0;
     181             : 
     182             :     // Initialize current operation
     183           0 :     current_cmd = 0; // 0 = no operation being executed
     184             : 
     185             :     // Initialize signer authorization
     186           0 :     init_signer_authorization();
     187             : 
     188             :     // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only
     189             :     // goal is to retrieve APDU.
     190             :     // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make
     191             :     // sure the io_event is called with a
     192             :     // switch event, before the apdu is replied to the bootloader. This avoid
     193             :     // APDU injection faults.
     194             :     for (;;) {
     195           0 :         BEGIN_TRY {
     196           0 :             TRY {
     197           0 :                 rx = tx;
     198           0 :                 tx = 0; // ensure no race in catch_other if io_exchange throws
     199             :                         // an error
     200           0 :                 rx = io_exchange(CHANNEL_APDU, rx);
     201             : 
     202           0 :                 tx = bootloader_process_apdu(rx, mode);
     203           0 :                 THROW(APDU_OK);
     204             :             }
     205           0 :             CATCH(EX_BOOTLOADER_RSK_END) {
     206           0 :                 break;
     207             :             }
     208           0 :             CATCH_OTHER(e) {
     209           0 :                 tx = ui_process_exception(e, tx, &reset_state);
     210             :             }
     211           0 :             FINALLY {
     212             :             }
     213             :         }
     214           0 :         END_TRY;
     215             :     }
     216           0 : }

Generated by: LCOV version 1.16