LCOV - code coverage report
Current view: top level - powhsm/src - auth.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 38 43 88.4 %
Date: 2025-07-10 13:49:13 Functions: 2 2 100.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 <string.h>
      26             : 
      27             : #include "hal/platform.h"
      28             : #include "hal/exceptions.h"
      29             : 
      30             : #include "auth.h"
      31             : #include "err.h"
      32             : #include "mem.h"
      33             : #include "compiletime.h"
      34             : #include "util.h"
      35             : 
      36             : #include "hal/log.h"
      37             : 
      38             : /*
      39             :  * Transition to the given state, performing corresponding
      40             :  * initializations.
      41             :  *
      42             :  * @arg[in] state   the state to transition to
      43             :  */
      44         230 : void auth_transition_to(uint8_t state) {
      45         230 :     if (state == STATE_AUTH_START)
      46          40 :         memset(&auth, 0, sizeof(auth));
      47             : 
      48         230 :     auth.state = state;
      49             : 
      50             :     // Init shared state
      51         230 :     memset(&auth.tx, 0, sizeof(auth.tx));
      52         230 :     memset(&auth.receipt, 0, sizeof(auth.receipt));
      53         230 :     memset(&auth.trie, 0, sizeof(auth.trie));
      54         230 : }
      55             : 
      56             : /*
      57             :  * Implement the signing authorization protocol.
      58             :  *
      59             :  * @arg[in] rx      number of received bytes from the host
      60             :  * @ret             number of transmited bytes to the host
      61             :  */
      62        2682 : unsigned int auth_sign(volatile unsigned int rx) {
      63             :     unsigned int tx;
      64             :     uint8_t sig_size;
      65             : 
      66             :     // Sanity check: tx hash size and
      67             :     // last auth signed tx hash size
      68             :     // must match
      69             :     COMPILE_TIME_ASSERT(sizeof(N_bc_state.last_auth_signed_btc_tx_hash) ==
      70             :                         sizeof(auth.tx_hash));
      71             : 
      72             :     // Check we receive the amount of bytes we requested
      73             :     // (this is an extra check on the legacy protocol, not
      74             :     // really adding much validation)
      75        2682 :     if (auth.state != STATE_AUTH_START &&
      76        2604 :         auth.state != STATE_AUTH_MERKLEPROOF &&
      77        2522 :         APDU_DATA_SIZE(rx) != auth.expected_bytes)
      78           0 :         THROW(ERR_AUTH_INVALID_DATA_SIZE);
      79             : 
      80        2682 :     switch (APDU_OP() & 0xF) {
      81          78 :     case P1_PATH:
      82          78 :         if ((tx = auth_sign_handle_path(rx)) == 0)
      83           8 :             break;
      84          58 :         return tx;
      85        2184 :     case P1_BTC:
      86        2184 :         return auth_sign_handle_btctx(rx);
      87         338 :     case P1_RECEIPT:
      88         338 :         return auth_sign_handle_receipt(rx);
      89          82 :     case P1_MERKLEPROOF:
      90          82 :         if ((tx = auth_sign_handle_merkleproof(rx)) == 0)
      91          32 :             break;
      92          40 :         return tx;
      93           0 :     default:
      94             :         // Invalid OP
      95           0 :         THROW(ERR_AUTH_INVALID_DATA_SIZE);
      96             :     }
      97             : 
      98          40 :     if (auth.state != STATE_AUTH_SIGN)
      99           0 :         THROW(ERR_AUTH_INVALID_STATE); // Invalid state
     100             : 
     101          40 :     sig_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     102          40 :     if (!seed_sign(auth.path,
     103             :                    sizeof(auth.path) / sizeof(auth.path[0]),
     104             :                    auth.sig_hash,
     105          40 :                    APDU_DATA_PTR,
     106             :                    &sig_size)) {
     107           0 :         THROW(ERR_INTERNAL);
     108             :     }
     109          40 :     tx = sig_size;
     110             : 
     111             :     // Save the BTC tx hash to NVM if this signature required authorization
     112          40 :     if (auth.auth_required) {
     113             :         // Avoid rewriting the same value to NVM multiple times
     114          32 :         if (memcmp(N_bc_state.last_auth_signed_btc_tx_hash,
     115             :                    auth.tx_hash,
     116             :                    sizeof(auth.tx_hash))) {
     117          13 :             NVM_WRITE(N_bc_state.last_auth_signed_btc_tx_hash,
     118             :                       auth.tx_hash,
     119             :                       sizeof(N_bc_state.last_auth_signed_btc_tx_hash));
     120             : 
     121             :             // Log hash for debugging purposes
     122          13 :             LOG_HEX("Saved BTC tx hash: ", auth.tx_hash, sizeof(auth.tx_hash));
     123             :         } else {
     124             :             // Log (already saved) hash for debugging purposes
     125          19 :             LOG_HEX("Did not rewrite already saved BTC tx hash: ",
     126             :                     auth.tx_hash,
     127             :                     sizeof(auth.tx_hash));
     128             :         }
     129             :     }
     130             : 
     131          40 :     SET_APDU_OP(P1_SUCCESS);
     132          40 :     auth_transition_to(STATE_AUTH_START);
     133          40 :     return TX_FOR_DATA_SIZE(tx);
     134             : }

Generated by: LCOV version 1.16