LCOV - code coverage report
Current view: top level - powhsm/src - attestation.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 0 90 0.0 %
Date: 2025-07-10 13:49:13 Functions: 0 6 0.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/seed.h"
      28             : #include "hal/endorsement.h"
      29             : #include "hal/platform.h"
      30             : #include "hal/exceptions.h"
      31             : 
      32             : #include "attestation.h"
      33             : #include "apdu.h"
      34             : #include "defs.h"
      35             : #include "pathAuth.h"
      36             : #include "bc_state.h"
      37             : #include "bc_hash.h"
      38             : #include "mem.h"
      39             : #include "memutil.h"
      40             : #include "util.h"
      41             : 
      42             : // Attestation message prefix
      43             : const char att_msg_prefix[ATT_MSG_PREFIX_LENGTH] = ATT_MSG_PREFIX;
      44             : 
      45             : // Utility macros for message gathering paging
      46             : // Maximum page size is APDU data part size minus one
      47             : // byte (first byte of the response), which is used to indicate
      48             : // whether there is a next page or not.
      49             : #define MIN(x, y) ((x) < (y) ? (x) : (y))
      50             : #define MAX_PAGESIZE (APDU_TOTAL_DATA_SIZE_OUT - 1)
      51             : #define PAGECOUNT(itemcount) (((itemcount) + MAX_PAGESIZE - 1) / MAX_PAGESIZE)
      52             : #define CURPAGESIZE(itemcount, page) (MIN(MAX_PAGESIZE, (itemcount) - ((page) * MAX_PAGESIZE)))
      53             : 
      54           0 : static void reset_attestation(att_t* att_ctx) {
      55           0 :     explicit_bzero(att_ctx, sizeof(att_t));
      56           0 :     att_ctx->state = STATE_ATTESTATION_WAIT_SIGN;
      57           0 : }
      58             : 
      59           0 : static void check_state(att_t* att_ctx,
      60             :                         state_attestation_t expected) {
      61           0 :     if (att_ctx->state != expected) {
      62           0 :         reset_attestation(att_ctx);
      63           0 :         THROW(ERR_ATT_PROT_INVALID);
      64             :     }
      65           0 : }
      66             : 
      67           0 : static void hash_public_key(const char* path,
      68             :                             size_t path_size,
      69             :                             att_t* att_ctx) {
      70             :     // Derive public key
      71             : 
      72             :     // Skip first byte of path when copying (path size byte)
      73           0 :     SAFE_MEMMOVE(att_ctx->path,
      74             :                  sizeof(att_ctx->path),
      75             :                  MEMMOVE_ZERO_OFFSET,
      76             :                  (unsigned int*)path,
      77             :                  path_size,
      78             :                  1,
      79             :                  sizeof(att_ctx->path),
      80             :                  { goto hash_public_key_error; });
      81             : 
      82           0 :     att_ctx->pubkey_length = sizeof(att_ctx->pubkey);
      83           0 :     if (!seed_derive_pubkey(att_ctx->path,
      84             :                             sizeof(att_ctx->path) / sizeof(att_ctx->path[0]),
      85           0 :                             att_ctx->pubkey,
      86             :                             &att_ctx->pubkey_length)) {
      87           0 :         goto hash_public_key_error;
      88             :     }
      89             : 
      90             :     // Hash
      91           0 :     SHA256_UPDATE(&att_ctx->hash_ctx, att_ctx->pubkey, att_ctx->pubkey_length);
      92             : 
      93             :     // Cleanup public key
      94           0 :     explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
      95           0 :     att_ctx->pubkey_length = 0;
      96             : 
      97           0 :     return;
      98             : 
      99           0 : hash_public_key_error:
     100             :     // Cleanup public key
     101           0 :     explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
     102           0 :     att_ctx->pubkey_length = 0;
     103           0 :     THROW(ERR_ATT_INTERNAL);
     104             : }
     105             : 
     106           0 : static void write_uint64_be(uint8_t *out, uint64_t in) {
     107           0 :     out[0] = (uint8_t)(in >> 56);
     108           0 :     out[1] = (uint8_t)(in >> 48);
     109           0 :     out[2] = (uint8_t)(in >> 40);
     110           0 :     out[3] = (uint8_t)(in >> 32);
     111           0 :     out[4] = (uint8_t)(in >> 24);
     112           0 :     out[5] = (uint8_t)(in >> 16);
     113           0 :     out[6] = (uint8_t)(in >> 8);
     114           0 :     out[7] = (uint8_t)in;
     115           0 : }
     116             : 
     117             : /*
     118             :  * Generate the attestation message.
     119             :  *
     120             :  * @arg[in] att_ctx attestation context
     121             :  * @arg[in] ud_value pointer to the user-defined value
     122             :  */
     123           0 : static void generate_message_to_sign(att_t* att_ctx, unsigned char* ud_value) {
     124             : 
     125             :     // Initialize message
     126           0 :     explicit_bzero(att_ctx->msg, sizeof(att_ctx->msg));
     127           0 :     att_ctx->msg_length = 0;
     128             : 
     129             :     // Copy the message prefix
     130           0 :     SAFE_MEMMOVE(att_ctx->msg,
     131             :                  sizeof(att_ctx->msg),
     132             :                  att_ctx->msg_length,
     133             :                  (void*)PIC(ATT_MSG_PREFIX),
     134             :                  ATT_MSG_PREFIX_LENGTH,
     135             :                  MEMMOVE_ZERO_OFFSET,
     136             :                  ATT_MSG_PREFIX_LENGTH,
     137             :                  THROW(ERR_ATT_INTERNAL));
     138           0 :     att_ctx->msg_length += ATT_MSG_PREFIX_LENGTH;
     139             : 
     140             :     // Copy the platform id
     141           0 :     SAFE_MEMMOVE(att_ctx->msg,
     142             :                  sizeof(att_ctx->msg),
     143             :                  att_ctx->msg_length,
     144             :                  (void*)PIC(platform_get_id()),
     145             :                  PLATFORM_ID_LENGTH,
     146             :                  MEMMOVE_ZERO_OFFSET,
     147             :                  PLATFORM_ID_LENGTH,
     148             :                  THROW(ERR_ATT_INTERNAL));
     149           0 :     att_ctx->msg_length += PLATFORM_ID_LENGTH;
     150             : 
     151             :     // Copy the UD value
     152           0 :     SAFE_MEMMOVE(att_ctx->msg,
     153             :                  sizeof(att_ctx->msg),
     154             :                  att_ctx->msg_length,
     155             :                  (void*)PIC(ud_value),
     156             :                  ATT_UD_VALUE_SIZE,
     157             :                  MEMMOVE_ZERO_OFFSET,
     158             :                  ATT_UD_VALUE_SIZE,
     159             :                  THROW(ERR_ATT_INTERNAL));
     160           0 :     att_ctx->msg_length += ATT_UD_VALUE_SIZE;
     161             : 
     162             :     // Prepare the digest
     163           0 :     SHA256_INIT(&att_ctx->hash_ctx);
     164             : 
     165             :     // Retrieve and hash the public keys in order
     166           0 :     for (unsigned int i = 0; i < KEY_PATH_COUNT(); i++) {
     167           0 :         hash_public_key(get_ordered_path(i), SINGLE_PATH_SIZE_BYTES, att_ctx);
     168             :     }
     169             : 
     170             :     // Finalise the public keys hash straight into the message
     171           0 :     SHA256_FINAL(&att_ctx->hash_ctx, &att_ctx->msg[att_ctx->msg_length]);
     172           0 :     att_ctx->msg_length += HASH_LENGTH;
     173             : 
     174             :     // Copy the current best block
     175           0 :     SAFE_MEMMOVE(att_ctx->msg,
     176             :                  sizeof(att_ctx->msg),
     177             :                  att_ctx->msg_length,
     178             :                  N_bc_state.best_block,
     179             :                  sizeof(N_bc_state.best_block),
     180             :                  MEMMOVE_ZERO_OFFSET,
     181             :                  sizeof(N_bc_state.best_block),
     182             :                  THROW(ERR_ATT_INTERNAL));
     183           0 :     att_ctx->msg_length += sizeof(N_bc_state.best_block);
     184             : 
     185             :     // Copy the leading bytes of the last authorised signed tx
     186           0 :     SAFE_MEMMOVE(att_ctx->msg,
     187             :                  sizeof(att_ctx->msg),
     188             :                  att_ctx->msg_length,
     189             :                  N_bc_state.last_auth_signed_btc_tx_hash,
     190             :                  sizeof(N_bc_state.last_auth_signed_btc_tx_hash),
     191             :                  MEMMOVE_ZERO_OFFSET,
     192             :                  ATT_LAST_SIGNED_TX_BYTES,
     193             :                  THROW(ERR_ATT_INTERNAL));
     194           0 :     att_ctx->msg_length += ATT_LAST_SIGNED_TX_BYTES;
     195             : 
     196             :     // Copy the current timestamp
     197           0 :     write_uint64_be(&att_ctx->msg[att_ctx->msg_length], platform_get_timestamp());
     198           0 :     att_ctx->msg_length += sizeof(uint64_t);
     199           0 : }
     200             : 
     201             : // -----------------------------------------------------------------------
     202             : // Protocol implementation
     203             : // -----------------------------------------------------------------------
     204             : 
     205             : /*
     206             :  * Implement the attestation protocol.
     207             :  *
     208             :  * @arg[in] rx      number of received bytes from the Host
     209             :  * @arg[in] att_ctx attestation context
     210             :  * @ret             number of transmited bytes to the host
     211             :  */
     212           0 : unsigned int get_attestation(volatile unsigned int rx, att_t* att_ctx) {
     213             :     size_t buf_length;
     214             :     uint8_t* buf;
     215             : 
     216           0 :     switch (APDU_OP()) {
     217           0 :     case OP_ATT_GET:
     218             :         // Should receive a user-defined value
     219           0 :         if (APDU_DATA_SIZE(rx) != ATT_UD_VALUE_SIZE) {
     220           0 :             reset_attestation(att_ctx);
     221           0 :             THROW(ERR_ATT_PROT_INVALID);
     222             :         }
     223             : 
     224             :         // Generate the message to attest
     225           0 :         generate_message_to_sign(att_ctx, APDU_DATA_PTR);
     226             : 
     227             :         // Attest message
     228           0 :         uint8_t endorsement_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     229           0 :         if (!endorsement_sign(
     230           0 :                 att_ctx->msg, att_ctx->msg_length, APDU_DATA_PTR, &endorsement_size)) {
     231           0 :             THROW(ERR_ATT_INTERNAL);
     232             :         }
     233             : 
     234             :         // Ready
     235           0 :         att_ctx->state = STATE_ATTESTATION_READY;
     236             : 
     237           0 :         return TX_FOR_DATA_SIZE(endorsement_size);
     238           0 :     case OP_ATT_GET_ENVELOPE:
     239             :     case OP_ATT_GET_MESSAGE:
     240           0 :         check_state(att_ctx, STATE_ATTESTATION_READY);
     241             : 
     242             :         // Should receive a page index
     243           0 :         if (APDU_DATA_SIZE(rx) != 1)
     244           0 :             THROW(ERR_ATT_PROT_INVALID);
     245             : 
     246             :         // Get the envelope or message
     247           0 :         buf = endorsement_get_envelope();
     248           0 :         buf_length = endorsement_get_envelope_length();
     249           0 :         if (!buf || APDU_OP() == OP_ATT_GET_MESSAGE) {
     250           0 :             buf = att_ctx->msg;
     251           0 :             buf_length = att_ctx->msg_length;
     252             :         }
     253             : 
     254             :         // Check page index within range (page index is zero based)
     255           0 :         if (APDU_DATA_PTR[0] >= PAGECOUNT(buf_length)) {
     256           0 :             THROW(ERR_ATT_PROT_INVALID);
     257             :         }
     258           0 :         uint8_t page = APDU_DATA_PTR[0];
     259             : 
     260             :         // Copy the page into the APDU buffer (no need to check for limits since
     261             :         // the chunk size is based directly on the APDU size)        
     262           0 :         SAFE_MEMMOVE(APDU_DATA_PTR,
     263             :                      APDU_TOTAL_DATA_SIZE_OUT,
     264             :                      1,
     265             :                      buf,
     266             :                      buf_length,
     267             :                      APDU_DATA_PTR[0] * MAX_PAGESIZE,
     268             :                      CURPAGESIZE(buf_length, page),
     269             :                      THROW(ERR_ATT_INTERNAL));
     270           0 :         APDU_DATA_PTR[0] = page < (PAGECOUNT(buf_length) - 1);
     271             : 
     272           0 :         return TX_FOR_DATA_SIZE(
     273             :             CURPAGESIZE(buf_length, page) + 1);
     274           0 :     case OP_ATT_APP_HASH:
     275           0 :         check_state(att_ctx, STATE_ATTESTATION_READY);
     276             :         
     277           0 :         buf_length = MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
     278           0 :         if (!endorsement_get_code_hash(APDU_DATA_PTR, (uint8_t*)&buf_length)) {
     279           0 :             THROW(ERR_ATT_INTERNAL);
     280             :         }
     281           0 :         return TX_FOR_DATA_SIZE(buf_length);
     282           0 :     default:
     283           0 :         THROW(ERR_ATT_PROT_INVALID);
     284             :         break;
     285             :     }
     286             :     return 0;
     287             : }

Generated by: LCOV version 1.16