LCOV - code coverage report
Current view: top level - AP_CheckFirmware - AP_CheckFirmware.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 5 5 100.0 %
Date: 2026-09-09 11:02:08 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /*
       2             :   support checking board ID and firmware CRC in the bootloader
       3             :  */
       4             : #include "AP_CheckFirmware.h"
       5             : #include <AP_HAL/HAL.h>
       6             : #include <AP_Math/crc.h>
       7             : 
       8             : #if AP_CHECK_FIRMWARE_ENABLED
       9             : 
      10             : #if defined(HAL_BOOTLOADER_BUILD)
      11             : 
      12             : #if AP_SIGNED_FIRMWARE
      13             : #include "../../Tools/AP_Bootloader/support.h"
      14             : #include <string.h>
      15             : #include "monocypher.h"
      16             : 
      17             : const struct ap_secure_data public_keys __attribute__((section(".apsec_data")));
      18             : 
      19             : /*
      20             :   return true if all public keys are zero. We allow boot of an
      21             :   unsigned firmware in that case
      22             :  */
      23             : static bool all_zero_public_keys(void)
      24             : {
      25             :     /*
      26             :       look over all public keys, if one matches then we are OK
      27             :      */
      28             :     const uint8_t zero_key[AP_PUBLIC_KEY_LEN] {};
      29             :     for (const auto &public_key : public_keys.public_key) {
      30             :         if (memcmp(public_key.key, zero_key, AP_PUBLIC_KEY_LEN) != 0) {
      31             :             return false;
      32             :         }
      33             :     }
      34             :     return true;
      35             : }
      36             : 
      37             : /*
      38             :   check a signature against bootloader keys
      39             :  */
      40             : static check_fw_result_t check_firmware_signature(const app_descriptor_signed *ad,
      41             :                                                   const uint8_t *flash1, uint32_t len1,
      42             :                                                   const uint8_t *flash2, uint32_t len2)
      43             : {
      44             :     if (all_zero_public_keys()) {
      45             :         return check_fw_result_t::CHECK_FW_OK;
      46             :     }
      47             : 
      48             :     // 8 byte signature version
      49             :     static const uint64_t sig_version = 30437LLU;
      50             :     if (ad->signature_length != 72) {
      51             :         return check_fw_result_t::FAIL_REASON_BAD_FIRMWARE_SIGNATURE;
      52             :     }
      53             :     if (memcmp((const uint8_t*)&sig_version, ad->signature, sizeof(sig_version)) != 0) {
      54             :         return check_fw_result_t::FAIL_REASON_BAD_FIRMWARE_SIGNATURE;
      55             :     }
      56             : 
      57             :     /*
      58             :       look over all public keys, if one matches then we are OK
      59             :      */
      60             :     for (const auto &public_key : public_keys.public_key) {
      61             :         crypto_check_ctx ctx {};
      62             :         crypto_check_ctx_abstract *actx = (crypto_check_ctx_abstract*)&ctx;
      63             :         crypto_check_init(actx, &ad->signature[sizeof(sig_version)], public_key.key);
      64             : 
      65             :         crypto_check_update(actx, flash1, len1);
      66             :         crypto_check_update(actx, flash2, len2);
      67             :         if (crypto_check_final(actx) == 0) {
      68             :             // good signature
      69             :             return check_fw_result_t::CHECK_FW_OK;
      70             :         }
      71             :     }
      72             : 
      73             :     // none of the public keys matched
      74             :     return check_fw_result_t::FAIL_REASON_VERIFICATION;
      75             : }
      76             : #endif // AP_SIGNED_FIRMWARE
      77             : 
      78             : /*
      79             :   check firmware CRC and board ID to see if it matches
      80             :  */
      81             : static check_fw_result_t check_good_firmware_signed(void)
      82             : {
      83             :     const uint8_t sig[8] = AP_APP_DESCRIPTOR_SIGNATURE_SIGNED;
      84             :     const uint8_t *flash1 = (const uint8_t *)(FLASH_LOAD_ADDRESS + (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB)*1024);
      85             :     const uint32_t flash_size = (BOARD_FLASH_SIZE - (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB))*1024;
      86             :     const app_descriptor_signed *ad = (const app_descriptor_signed *)memmem(flash1, flash_size-sizeof(app_descriptor_signed), sig, sizeof(sig));
      87             :     if (ad == nullptr) {
      88             :         // no application signature
      89             :         return check_fw_result_t::FAIL_REASON_NO_APP_SIG;
      90             :     }
      91             :     // check length
      92             :     if (ad->image_size > flash_size) {
      93             :         return check_fw_result_t::FAIL_REASON_BAD_LENGTH_APP;
      94             :     }
      95             : 
      96             :     bool id_ok = (ad->board_id == APJ_BOARD_ID);
      97             : #ifdef ALT_BOARD_ID
      98             :     id_ok |= (ad->board_id == ALT_BOARD_ID);
      99             : #endif
     100             : 
     101             :     if (!id_ok) {
     102             :         return check_fw_result_t::FAIL_REASON_BAD_BOARD_ID;
     103             :     }
     104             : 
     105             :     const uint8_t *flash2 = (const uint8_t *)&ad->version_major;
     106             :     const uint8_t desc_len = offsetof(app_descriptor_signed, version_major) - offsetof(app_descriptor_signed, image_crc1);
     107             :     const uint32_t len1 = ((const uint8_t *)&ad->image_crc1) - flash1;
     108             : 
     109             :     if ((len1 + desc_len) > ad->image_size) {
     110             :         return check_fw_result_t::FAIL_REASON_BAD_LENGTH_DESCRIPTOR;
     111             :     }
     112             : 
     113             :     const uint32_t len2 = ad->image_size - (len1 + desc_len);
     114             :     uint32_t crc1 = crc32_small(0, flash1, len1);
     115             :     uint32_t crc2 = crc32_small(0, flash2, len2);
     116             :     if (crc1 != ad->image_crc1 || crc2 != ad->image_crc2) {
     117             :         return check_fw_result_t::FAIL_REASON_BAD_CRC;
     118             :     }
     119             : 
     120             :     check_fw_result_t ret = check_fw_result_t::CHECK_FW_OK;
     121             : 
     122             : #if AP_SIGNED_FIRMWARE
     123             :     ret = check_firmware_signature(ad, flash1, len1, flash2, len2);
     124             : #endif
     125             : 
     126             :     return ret;
     127             : }
     128             : 
     129             : /*
     130             :   check firmware CRC and board ID to see if it matches, using unsigned
     131             :   signature
     132             :  */
     133             : static check_fw_result_t check_good_firmware_unsigned(void)
     134             : {
     135             :     const uint8_t sig[8] = AP_APP_DESCRIPTOR_SIGNATURE_UNSIGNED;
     136             :     const uint8_t *flash1 = (const uint8_t *)(FLASH_LOAD_ADDRESS + (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB)*1024);
     137             :     const uint32_t flash_size = (BOARD_FLASH_SIZE - (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB))*1024;
     138             :     const app_descriptor_unsigned *ad = (const app_descriptor_unsigned *)memmem(flash1, flash_size-sizeof(app_descriptor_unsigned), sig, sizeof(sig));
     139             :     if (ad == nullptr) {
     140             :         // no application signature
     141             :         return check_fw_result_t::FAIL_REASON_NO_APP_SIG;
     142             :     }
     143             :     // check length
     144             :     if (ad->image_size > flash_size) {
     145             :         return check_fw_result_t::FAIL_REASON_BAD_LENGTH_APP;
     146             :     }
     147             : 
     148             :     bool id_ok = (ad->board_id == APJ_BOARD_ID);
     149             : #ifdef ALT_BOARD_ID
     150             :     id_ok |= (ad->board_id == ALT_BOARD_ID);
     151             : #endif
     152             : 
     153             :     if (!id_ok) {
     154             :         return check_fw_result_t::FAIL_REASON_BAD_BOARD_ID;
     155             :     }
     156             : 
     157             :     const uint8_t *flash2 = (const uint8_t *)&ad->version_major;
     158             :     const uint8_t desc_len = offsetof(app_descriptor_unsigned, version_major) - offsetof(app_descriptor_unsigned, image_crc1);
     159             :     const uint32_t len1 = ((const uint8_t *)&ad->image_crc1) - flash1;
     160             : 
     161             :     if ((len1 + desc_len) > ad->image_size) {
     162             :         return check_fw_result_t::FAIL_REASON_BAD_LENGTH_DESCRIPTOR;
     163             :     }
     164             : 
     165             :     const uint32_t len2 = ad->image_size - (len1 + desc_len);
     166             :     uint32_t crc1 = crc32_small(0, flash1, len1);
     167             :     uint32_t crc2 = crc32_small(0, flash2, len2);
     168             :     if (crc1 != ad->image_crc1 || crc2 != ad->image_crc2) {
     169             :         return check_fw_result_t::FAIL_REASON_BAD_CRC;
     170             :     }
     171             : 
     172             :     return check_fw_result_t::CHECK_FW_OK;
     173             : }
     174             : 
     175             : check_fw_result_t check_good_firmware(void)
     176             : {
     177             : #if AP_SIGNED_FIRMWARE
     178             :     // allow unsigned format if we have no public keys. This allows
     179             :     // for use of SECURE_COMMAND to remove all public keys and then
     180             :     // load of unsigned firmware
     181             :     const auto ret = check_good_firmware_signed();
     182             :     if (ret != check_fw_result_t::CHECK_FW_OK &&
     183             :         all_zero_public_keys() &&
     184             :         check_good_firmware_unsigned() == check_fw_result_t::CHECK_FW_OK) {
     185             :         return check_fw_result_t::CHECK_FW_OK;
     186             :     }
     187             :     return ret;
     188             : #else
     189             :     const auto ret = check_good_firmware_unsigned();
     190             :     if (ret != check_fw_result_t::CHECK_FW_OK) {
     191             :         // allow for signed format, not checking public keys. This
     192             :         // allows for booting of a signed firmware with an unsigned
     193             :         // bootloader, which allows for bootstrapping a system up from
     194             :         // unsigned to signed
     195             :         const auto ret2 = check_good_firmware_signed();
     196             :         if (ret2 == check_fw_result_t::CHECK_FW_OK) {
     197             :             return check_fw_result_t::CHECK_FW_OK;
     198             :         }
     199             :     }
     200             :     return ret;
     201             : #endif
     202             : }
     203             : 
     204             : const app_descriptor_t *get_app_descriptor(void)
     205             : {
     206             : #if AP_SIGNED_FIRMWARE
     207             :     const uint8_t sig[8] = AP_APP_DESCRIPTOR_SIGNATURE_SIGNED;
     208             : #else
     209             :     const uint8_t sig[8] = AP_APP_DESCRIPTOR_SIGNATURE_UNSIGNED;
     210             : #endif
     211             :     const uint8_t *flash1 = (const uint8_t *)(FLASH_LOAD_ADDRESS + (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB)*1024);
     212             :     const uint32_t flash_size = (BOARD_FLASH_SIZE - (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB))*1024;
     213             :     const app_descriptor_t *ad = (const app_descriptor_t *)memmem(flash1, flash_size-sizeof(app_descriptor_t), sig, sizeof(sig));
     214             :     return ad;
     215             : }
     216             : 
     217             : #endif // HAL_BOOTLOADER_BUILD
     218             : 
     219             : #if !defined(HAL_BOOTLOADER_BUILD)
     220             : extern const AP_HAL::HAL &hal;
     221             : extern const app_descriptor_t app_descriptor;
     222             : 
     223             : /*
     224             :   this is needed to ensure we don't elide the app_descriptor
     225             :  */
     226        2094 : void check_firmware_print(void)
     227             : {
     228        2094 :     hal.console->printf("Booting %u/%u\n",
     229        2094 :                         app_descriptor.version_major,
     230        2094 :                         app_descriptor.version_minor);
     231        2094 : }
     232             : #endif
     233             : 
     234             : 
     235             : #endif // AP_CHECK_FIRMWARE_ENABLED

Generated by: LCOV version 1.14