Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IDF 5.x migration: Need for public function esp_secure_boot_verify_rsa_signature_block for bundle verification (IDFGH-11599) #12717

Closed
M-Bab opened this issue Dec 4, 2023 · 3 comments
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Feature Request Feature request for IDF

Comments

@M-Bab
Copy link
Contributor

M-Bab commented Dec 4, 2023

Is your feature request related to a problem?

During our migration to IDF 5.x we recognized that the function esp_secure_boot_verify_rsa_signature_block has been removed without replacement which is also stated in the migration guide: https://docs.espressif.com/projects/esp-idf/en/v5.1.2/esp32/migration-guides/release-5.x/5.0/system.html?highlight=signature_block#bootloader-support . But the migration guide also encourages to open a feature request explaining the use case of this function which I will try to do in the following.

We use an ESP32 as a frontend and service interface in a network of multiple embedded controllers. As update path the ESP32 gets a "software bundle" uploaded which also comprises the firmwares of the other embedded controllers. Because of certain cybersecurity requirements we use secure boot (v2) and flash encryption. But we also want to protect the attached controller binaries against manipulation and for this reason we sign the whole bundle with same certificate after concatenating the binaries. A full bundle looks like this:

esp-bundle

The Update is a multi-stage process where the external controller binaries are stored in the PSRAM first while the ESP firmware is flashed to the other slot. During this process the bundle signature is verified with esp_secure_boot_verify_rsa_signature_block and the external controller binaries are CRC checked. If the bootslot update succeeds, the external controllers are updated from PSRAM and the whole update process is successful.

esp_secure_boot_verify_rsa_signature_block is therefore a very helpful function and eases the process of bundle verification.

Describe the solution you'd like.

I would love to see the bootloader functions, especially esp_secure_boot_verify_rsa_signature_block made available again for user code usage. The effort for this "feature" should be quite low.

Describe alternatives you've considered.

Otherwise we would need to re-implement esp_secure_boot_verify_rsa_signature_block in our own code. Probably by copying it from previous IDF versions.

Additional context.

No response

@M-Bab M-Bab added the Type: Feature Request Feature request for IDF label Dec 4, 2023
@espressif-bot espressif-bot added the Status: Opened Issue is new label Dec 4, 2023
@github-actions github-actions bot changed the title IDF 5.x migration: Need for public function esp_secure_boot_verify_rsa_signature_block for bundle verification IDF 5.x migration: Need for public function esp_secure_boot_verify_rsa_signature_block for bundle verification (IDFGH-11599) Dec 4, 2023
@Harshal5
Copy link
Collaborator

Harshal5 commented Dec 6, 2023

Hello @M-Bab,

Thanks for the report!
Could you check out the function esp_secure_boot_verify_signature() (reference)? I think it should satisfy your use case.

Thank you!

@M-Bab
Copy link
Contributor Author

M-Bab commented Dec 6, 2023

Thanks for your reply @Harshal5. Unfortunately this is not enough to verify a bundle. In fact the full bundle never exists in its full size on the flash (which would also not be possible). As described above we have it split in flash and RAM and we do a SHA256 calculation of the whole bundle while streaming through the data.

After this the checksum digest is used is used to compare it to the secure boot keys in the efuse. Here is an extract of the code for a better understanding:

esp_err_t VERIFY_BUNDLE_verify(mbedtls_sha256_context* sha256Ctx, ets_secure_boot_sig_block_t* signatureBlock)
{
  unsigned char imageDigest[ESP_SECURE_BOOT_DIGEST_LEN];
  // retrieve the sha256 of the bundle
  mbedtls_sha256_finish_ret(sha256Ctx, imageDigest);

  uint8_t trustedKey[ESP_SECURE_BOOT_DIGEST_LEN]      = {0};
  uint8_t pubKeyAppDigest[ESP_SECURE_BOOT_DIGEST_LEN] = {0};

  // get public key digest from eFuse
  if (ESP_OK != VERIFY_BUNDLE_getSecureBootKeyDigests(trustedKey, ESP_SECURE_BOOT_DIGEST_LEN))
  {
    return ESP_ERR_NOT_FOUND;
  }

  // Calculate public key digest from public key
  mbedtls_sha256_context publicContext;
  mbedtls_sha256_init(&publicContext);
  // check of return value is omitted - the result will be checked anyway
  mbedtls_sha256_starts_ret(&publicContext, 0);
  mbedtls_sha256_update_ret(&publicContext, (unsigned char*)(signatureBlock->key), sizeof(signatureBlock->key));
  mbedtls_sha256_finish_ret(&publicContext, pubKeyAppDigest);
  mbedtls_sha256_free(&publicContext);

  /*
   * compare the calculated public key digest with public key digest from efuse
   * they need to be equal otherwise we have a faulty bundle
   */
  if (0 != memcmp(trustedKey, pubKeyAppDigest, ESP_SECURE_BOOT_DIGEST_LEN))
  {
    return ESP_FAIL;
  }

  ets_secure_boot_signature_t sigBlk = {0};
  // copy the signature block into the right structure for further processing
  memcpy(sigBlk.block, &signatureBlock, sizeof(ets_secure_boot_sig_block_t));

  /*
   * verify the signature - this includes:
   * - compare the calculated image sha256 of the image (var imageDigest) with the one on the signature block
   * - verify the actual signature in the signatur block with public key from signature block
   * - check the crc32 of the signature block (calculate and compare with the one in the signature block)
   * - check magic byte and version of secure boot signature block
   */
  if (ESP_OK != esp_secure_boot_verify_rsa_signature_block(&sigBlk, imageDigest, trustedKey))
  {
    return ESP_FAIL;
  }

  return ESP_OK;
}

As you can see esp_secure_boot_verify_rsa_signature_block is quite an all-in-one convenience function for us.

@Harshal5
Copy link
Collaborator

Harshal5 commented Dec 7, 2023

Right, esp_secure_boot_verify_signature() would be helpful only when the signature is located in flash. If the signature is already loaded in RAM, I think we would require esp_secure_boot_verify_sbv2_signature_block() to be publicly available.

esp_secure_boot_verify_rsa_signature_block() is a legacy function now, it internally calls esp_secure_boot_verify_sbv2_signature_block()

Taking up this task internally!

@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Opened Issue is new labels Dec 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Feature Request Feature request for IDF
Projects
None yet
Development

No branches or pull requests

3 participants