LCOV - code coverage report
Current view: top level - powhsm/src - heartbeat.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 39 53 73.6 %
Date: 2025-07-10 13:49:13 Functions: 2 3 66.7 %

          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/endorsement.h"
      28             : #include "hal/platform.h"
      29             : #include "hal/exceptions.h"
      30             : 
      31             : #include "heartbeat.h"
      32             : #include "apdu.h"
      33             : #include "defs.h"
      34             : #include "memutil.h"
      35             : #include "bc_state.h"
      36             : #include "compiletime.h"
      37             : #include "util.h"
      38             : 
      39             : /*
      40             :  * Reset the given heartbeat context
      41             :  */
      42           0 : static void reset_heartbeat(heartbeat_t* heartbeat_ctx) {
      43           0 :     explicit_bzero(heartbeat_ctx, sizeof(heartbeat_t));
      44           0 :     heartbeat_ctx->state = STATE_HEARTBEAT_WAIT_UD_VALUE;
      45           0 : }
      46             : 
      47             : /*
      48             :  * Check that the SM for the heartbeat generation
      49             :  * matches the expected state.
      50             :  *
      51             :  * Reset the state and throw a protocol error
      52             :  * otherwise.
      53             :  */
      54           8 : static void check_state(heartbeat_t* heartbeat_ctx,
      55             :                         state_heartbeat_t expected) {
      56           8 :     if (heartbeat_ctx->state != expected) {
      57           0 :         reset_heartbeat(heartbeat_ctx);
      58           0 :         THROW(ERR_HBT_PROT_INVALID);
      59             :     }
      60           8 : }
      61             : 
      62             : // -----------------------------------------------------------------------
      63             : // Protocol implementation
      64             : // -----------------------------------------------------------------------
      65             : 
      66             : /*
      67             :  * Implement the heartbeat protocol.
      68             :  *
      69             :  * @arg[in] rx      number of received bytes from the Host
      70             :  * @arg[in] heartbeat_ctx heartbeat context
      71             :  * @ret             number of transmited bytes to the host
      72             :  */
      73          20 : unsigned int get_heartbeat(volatile unsigned int rx,
      74             :                            heartbeat_t* heartbeat_ctx) {
      75             :     // Build should fail when more bytes than available are tried to be copied
      76             :     // from the last signed BTC tx hash
      77             :     COMPILE_TIME_ASSERT(LAST_SIGNED_TX_BYTES <=
      78             :                         sizeof(N_bc_state.last_auth_signed_btc_tx_hash));
      79             : 
      80          20 :     COMPILE_TIME_ASSERT(MAX_HEARTBEAT_MESSAGE_SIZE <= APDU_TOTAL_DATA_SIZE_OUT);
      81             : 
      82             :     uint8_t out_size;
      83             : 
      84          20 :     switch (APDU_OP()) {
      85           4 :     case OP_HBT_UD_VALUE:
      86             :         // Should receive a user-defined value
      87           4 :         if (APDU_DATA_SIZE(rx) != UD_VALUE_SIZE) {
      88           0 :             reset_heartbeat(heartbeat_ctx);
      89           0 :             THROW(ERR_HBT_PROT_INVALID);
      90             :         }
      91             : 
      92             :         // Initialize message
      93           4 :         explicit_bzero(heartbeat_ctx->msg, sizeof(heartbeat_ctx->msg));
      94           4 :         heartbeat_ctx->msg_offset = 0;
      95             : 
      96             :         // Copy the message prefix
      97           8 :         SAFE_MEMMOVE(heartbeat_ctx->msg,
      98             :                      sizeof(heartbeat_ctx->msg),
      99             :                      heartbeat_ctx->msg_offset,
     100             :                      (void*)PIC(HEARTBEAT_MSG_PREFIX),
     101             :                      HEARTBEAT_MSG_PREFIX_LENGTH,
     102             :                      MEMMOVE_ZERO_OFFSET,
     103             :                      HEARTBEAT_MSG_PREFIX_LENGTH,
     104             :                      THROW(ERR_HBT_INTERNAL));
     105           4 :         heartbeat_ctx->msg_offset += HEARTBEAT_MSG_PREFIX_LENGTH;
     106             : 
     107             :         // Copy the current best block
     108           8 :         SAFE_MEMMOVE(heartbeat_ctx->msg,
     109             :                      sizeof(heartbeat_ctx->msg),
     110             :                      heartbeat_ctx->msg_offset,
     111             :                      N_bc_state.best_block,
     112             :                      sizeof(N_bc_state.best_block),
     113             :                      MEMMOVE_ZERO_OFFSET,
     114             :                      sizeof(N_bc_state.best_block),
     115             :                      THROW(ERR_HBT_INTERNAL));
     116           4 :         heartbeat_ctx->msg_offset += sizeof(N_bc_state.best_block);
     117             : 
     118             :         // Copy the last LAST_SIGNED_TX_BYTES bytes of the last auth signed tx
     119           8 :         SAFE_MEMMOVE(heartbeat_ctx->msg,
     120             :                      sizeof(heartbeat_ctx->msg),
     121             :                      heartbeat_ctx->msg_offset,
     122             :                      N_bc_state.last_auth_signed_btc_tx_hash,
     123             :                      sizeof(N_bc_state.last_auth_signed_btc_tx_hash),
     124             :                      MEMMOVE_ZERO_OFFSET,
     125             :                      LAST_SIGNED_TX_BYTES,
     126             :                      THROW(ERR_HBT_INTERNAL));
     127           4 :         heartbeat_ctx->msg_offset += LAST_SIGNED_TX_BYTES;
     128             : 
     129             :         // Copy the UD value from the APDU
     130           8 :         SAFE_MEMMOVE(heartbeat_ctx->msg,
     131             :                      sizeof(heartbeat_ctx->msg),
     132             :                      heartbeat_ctx->msg_offset,
     133             :                      APDU_DATA_PTR,
     134             :                      APDU_TOTAL_DATA_SIZE,
     135             :                      MEMMOVE_ZERO_OFFSET,
     136             :                      UD_VALUE_SIZE,
     137             :                      THROW(ERR_HBT_INTERNAL));
     138           4 :         heartbeat_ctx->msg_offset += UD_VALUE_SIZE;
     139             : 
     140           4 :         heartbeat_ctx->state = STATE_HEARTBEAT_READY;
     141             : 
     142           4 :         return TX_FOR_DATA_SIZE(0);
     143           4 :     case OP_HBT_GET:
     144           4 :         check_state(heartbeat_ctx, STATE_HEARTBEAT_READY);
     145             : 
     146             :         // Sign message
     147           4 :         uint8_t endorsement_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     148           4 :         if (!endorsement_sign(heartbeat_ctx->msg,
     149           4 :                               heartbeat_ctx->msg_offset,
     150           4 :                               APDU_DATA_PTR,
     151             :                               &endorsement_size)) {
     152           0 :             THROW(ERR_HBT_INTERNAL);
     153             :         }
     154             : 
     155           4 :         return TX_FOR_DATA_SIZE(endorsement_size);
     156           4 :     case OP_HBT_GET_MESSAGE:
     157           4 :         check_state(heartbeat_ctx, STATE_HEARTBEAT_READY);
     158             : 
     159           8 :         SAFE_MEMMOVE(APDU_DATA_PTR,
     160             :                      APDU_TOTAL_DATA_SIZE,
     161             :                      MEMMOVE_ZERO_OFFSET,
     162             :                      heartbeat_ctx->msg,
     163             :                      sizeof(heartbeat_ctx->msg),
     164             :                      MEMMOVE_ZERO_OFFSET,
     165             :                      heartbeat_ctx->msg_offset,
     166             :                      THROW(ERR_HBT_INTERNAL));
     167             : 
     168           4 :         return TX_FOR_DATA_SIZE(heartbeat_ctx->msg_offset);
     169           4 :     case OP_HBT_APP_HASH:
     170           4 :         out_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     171           4 :         if (!endorsement_get_code_hash(APDU_DATA_PTR, &out_size)) {
     172           0 :             THROW(ERR_HBT_INTERNAL);
     173             :         }
     174           4 :         return TX_FOR_DATA_SIZE(out_size);
     175           4 :     case OP_HBT_PUBKEY:
     176           4 :         out_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     177           4 :         if (!endorsement_get_public_key(APDU_DATA_PTR, &out_size)) {
     178           0 :             THROW(ERR_HBT_INTERNAL);
     179             :         }
     180           4 :         return TX_FOR_DATA_SIZE(out_size);
     181           0 :     default:
     182           0 :         reset_heartbeat(heartbeat_ctx);
     183           0 :         THROW(ERR_HBT_PROT_INVALID);
     184             :         break;
     185             :     }
     186             :     return 0;
     187             : }

Generated by: LCOV version 1.16