Skip to content

Commit

Permalink
[ESP32] encrypted_ota: Call abort API when aborting OTA and some refa…
Browse files Browse the repository at this point in the history
…ctoring (#28778)

* [ESP32] encrypted_ota: Call abort API when aborting and some refactoring

* Make DecryptEnd return an error and honour it

* Restyled by clang-format

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Feb 14, 2024
1 parent ca5c210 commit 1252592
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 82 deletions.
3 changes: 2 additions & 1 deletion config/esp32/components/chip/idf_component.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ dependencies:
- if: "idf_version >=4.3"

espressif/esp_encrypted_img:
version: "2.0.3"
version: "2.1.0"
require: public
rules:
- if: "idf_version >=4.4"

Expand Down
175 changes: 95 additions & 80 deletions src/platform/ESP32/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,6 @@ void PostOTAStateChangeEvent(DeviceLayer::OtaState newState)

} // namespace

#if CONFIG_ENABLE_ENCRYPTED_OTA
void OTAImageProcessorImpl::EndDecryption()
{
VerifyOrReturn(mEncryptedOTAEnabled);

esp_err_t err = esp_encrypted_img_decrypt_end(mOTADecryptionHandle);
if (err != ESP_OK)
{
ChipLogError(SoftwareUpdate, "Failed to end pre encrypted OTA esp_err:%d", err);
}
mOTADecryptionHandle = nullptr;
}
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

bool OTAImageProcessorImpl::IsFirstImageRun()
{
OTARequestorInterface * requestor = GetRequestorInstance();
Expand Down Expand Up @@ -165,26 +151,11 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context)
}

#if CONFIG_ENABLE_ENCRYPTED_OTA
if (imageProcessor->mEncryptedOTAEnabled == false)
CHIP_ERROR chipError = imageProcessor->DecryptStart();
if (chipError != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Encrypted OTA is not initialized");
imageProcessor->mDownloader->OnPreparedForDownload(ESP32Utils::MapError(err));
return;
}

// This struct takes in private key but arguments are named as pub_key
// This is the issue in the esp_encrypted_img component
// https://github.com/espressif/idf-extra-components/blob/791d506/esp_encrypted_img/include/esp_encrypted_img.h#L47
const esp_decrypt_cfg_t decryptionConfig = {
.rsa_pub_key = imageProcessor->mKey.data(),
.rsa_pub_key_len = imageProcessor->mKey.size(),
};

imageProcessor->mOTADecryptionHandle = esp_encrypted_img_decrypt_start(&decryptionConfig);
if (imageProcessor->mOTADecryptionHandle == nullptr)
{
ChipLogError(SoftwareUpdate, "Failed to initialize encrypted OTA");
imageProcessor->mDownloader->OnPreparedForDownload(ESP32Utils::MapError(ESP_FAIL));
ChipLogError(SoftwareUpdate, "Failed to start decryption process, err:%" CHIP_ERROR_FORMAT, chipError.Format());
imageProcessor->mDownloader->OnPreparedForDownload(chipError);
return;
}
#endif // CONFIG_ENABLE_ENCRYPTED_OTA
Expand All @@ -196,15 +167,19 @@ void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context)

void OTAImageProcessorImpl::HandleFinalize(intptr_t context)
{
auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context);
if (imageProcessor == nullptr)
DeviceLayer::OtaState otaState = DeviceLayer::kOtaDownloadFailed;
auto * imageProcessor = reinterpret_cast<OTAImageProcessorImpl *>(context);
VerifyOrReturn(imageProcessor, ChipLogError(SoftwareUpdate, "ImageProcessor context is null"));

#if CONFIG_ENABLE_ENCRYPTED_OTA
if (CHIP_NO_ERROR != imageProcessor->DecryptEnd())
{
ChipLogError(SoftwareUpdate, "ImageProcessor context is null");
ChipLogError(SoftwareUpdate, "Failed to end pre encrypted OTA");
esp_ota_abort(imageProcessor->mOTAUpdateHandle);
imageProcessor->ReleaseBlock();
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
return;
}

#if CONFIG_ENABLE_ENCRYPTED_OTA
imageProcessor->EndDecryption();
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle);
Expand All @@ -218,12 +193,15 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context)
{
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
}
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
return;
}
else
{
ChipLogProgress(SoftwareUpdate, "OTA image downloaded to offset 0x%" PRIx32, imageProcessor->mOTAUpdatePartition->address);
otaState = DeviceLayer::kOtaDownloadComplete;
}

imageProcessor->ReleaseBlock();
ChipLogProgress(SoftwareUpdate, "OTA image downloaded to offset 0x%" PRIx32, imageProcessor->mOTAUpdatePartition->address);
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete);
PostOTAStateChangeEvent(otaState);
}

void OTAImageProcessorImpl::HandleAbort(intptr_t context)
Expand All @@ -236,7 +214,7 @@ void OTAImageProcessorImpl::HandleAbort(intptr_t context)
}

#if CONFIG_ENABLE_ENCRYPTED_OTA
imageProcessor->EndDecryption();
imageProcessor->DecryptAbort();
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

if (esp_ota_abort(imageProcessor->mOTAUpdateHandle) != ESP_OK)
Expand Down Expand Up @@ -276,53 +254,20 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context)
ByteSpan blockToWrite = block;

#if CONFIG_ENABLE_ENCRYPTED_OTA
if (imageProcessor->mEncryptedOTAEnabled == false)
{
ChipLogError(SoftwareUpdate, "Encrypted OTA is not initialized");
imageProcessor->mDownloader->EndDownload(CHIP_ERROR_INCORRECT_STATE);
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
return;
}

if (imageProcessor->mOTADecryptionHandle == nullptr)
{
ChipLogError(SoftwareUpdate, "OTA decryption handle is nullptr");
imageProcessor->mDownloader->EndDownload(CHIP_ERROR_INCORRECT_STATE);
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
return;
}

pre_enc_decrypt_arg_t preEncOtaDecryptArgs = {
.data_in = reinterpret_cast<const char *>(block.data()),
.data_in_len = block.size(),
.data_out = nullptr,
.data_out_len = 0,
};

err = esp_encrypted_img_decrypt_data(imageProcessor->mOTADecryptionHandle, &preEncOtaDecryptArgs);
if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED)
error = imageProcessor->DecryptBlock(block, blockToWrite);
if (error != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "esp_encrypted_img_decrypt_data failed err:%d", err);
imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED);
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadFailed);
return;
}

ChipLogDetail(SoftwareUpdate, "data_in_len:%u, data_out_len:%u", preEncOtaDecryptArgs.data_in_len,
preEncOtaDecryptArgs.data_out_len);

if (preEncOtaDecryptArgs.data_out == nullptr || preEncOtaDecryptArgs.data_out_len <= 0)
{
ChipLogProgress(SoftwareUpdate, "Decrypted data is null or out len is zero");
}

blockToWrite = ByteSpan(reinterpret_cast<const uint8_t *>(preEncOtaDecryptArgs.data_out), preEncOtaDecryptArgs.data_out_len);
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

err = esp_ota_write(imageProcessor->mOTAUpdateHandle, blockToWrite.data(), blockToWrite.size());

#if CONFIG_ENABLE_ENCRYPTED_OTA
free(preEncOtaDecryptArgs.data_out);
free((void *) (blockToWrite.data()));
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

if (err != ESP_OK)
Expand Down Expand Up @@ -427,6 +372,76 @@ CHIP_ERROR OTAImageProcessorImpl::InitEncryptedOTA(const CharSpan & key)
mEncryptedOTAEnabled = true;
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::DecryptStart()
{
VerifyOrReturnError(mEncryptedOTAEnabled, CHIP_ERROR_INCORRECT_STATE);

const esp_decrypt_cfg_t decryptionConfig = {
.rsa_priv_key = mKey.data(),
.rsa_priv_key_len = mKey.size(),
};

mOTADecryptionHandle = esp_encrypted_img_decrypt_start(&decryptionConfig);
VerifyOrReturnError(mOTADecryptionHandle, CHIP_ERROR_INCORRECT_STATE);
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::DecryptEnd()
{
VerifyOrReturnError(mEncryptedOTAEnabled, CHIP_ERROR_INCORRECT_STATE);

esp_err_t err = esp_encrypted_img_decrypt_end(mOTADecryptionHandle);
if (err != ESP_OK)
{
ChipLogError(SoftwareUpdate, "Failed to end pre encrypted OTA esp_err:%d", err);
}
mOTADecryptionHandle = nullptr;
return ESP32Utils::MapError(err);
}

void OTAImageProcessorImpl::DecryptAbort()
{
VerifyOrReturn(mEncryptedOTAEnabled);

esp_err_t err = esp_encrypted_img_decrypt_abort(mOTADecryptionHandle);
if (err != ESP_OK)
{
ChipLogError(SoftwareUpdate, "Failed to abort pre encrypted OTA esp_err:%d", err);
}
mOTADecryptionHandle = nullptr;
}

CHIP_ERROR OTAImageProcessorImpl::DecryptBlock(const ByteSpan & blockToDecrypt, ByteSpan & decryptedBlock)
{
VerifyOrReturnError(mEncryptedOTAEnabled, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(mOTADecryptionHandle, CHIP_ERROR_INCORRECT_STATE);

pre_enc_decrypt_arg_t preEncOtaDecryptArgs = {
.data_in = reinterpret_cast<const char *>(blockToDecrypt.data()),
.data_in_len = blockToDecrypt.size(),
.data_out = nullptr,
.data_out_len = 0,
};

esp_err_t err = esp_encrypted_img_decrypt_data(mOTADecryptionHandle, &preEncOtaDecryptArgs);
if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED)
{
ChipLogError(SoftwareUpdate, "esp_encrypted_img_decrypt_data failed err:%d", err);
return ESP32Utils::MapError(err);
}

ChipLogDetail(SoftwareUpdate, "esp_encrypted_img_decrypt_data data_in_len:%u, data_out_len:%u",
preEncOtaDecryptArgs.data_in_len, preEncOtaDecryptArgs.data_out_len);

if (preEncOtaDecryptArgs.data_out == nullptr || preEncOtaDecryptArgs.data_out_len <= 0)
{
ChipLogProgress(SoftwareUpdate, "Decrypted data is null or out len is zero");
}

decryptedBlock = ByteSpan(reinterpret_cast<const uint8_t *>(preEncOtaDecryptArgs.data_out), preEncOtaDecryptArgs.data_out_len);
return CHIP_NO_ERROR;
}
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

} // namespace chip
9 changes: 8 additions & 1 deletion src/platform/ESP32/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,14 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface
OTAImageHeaderParser mHeaderParser;

#if CONFIG_ENABLE_ENCRYPTED_OTA
void EndDecryption();
CHIP_ERROR DecryptStart();
CHIP_ERROR DecryptEnd();
void DecryptAbort();

// This API decrypts the blockToDecrypt, dynamically allocates the memory for storing the
// plain text, and return that in decryptedBlock.
// Caller shall free the memory after use by calling free() on decryptedBlock.data()
CHIP_ERROR DecryptBlock(const ByteSpan & blockToDecrypt, ByteSpan & decryptedBlock);

CharSpan mKey;
bool mEncryptedOTAEnabled = false;
Expand Down

0 comments on commit 1252592

Please sign in to comment.