blob: a5da7eaba00c10928d1be8d80fb9f97fc0e37f5b [file] [log] [blame]
/*
*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <lib/core/TLV.h>
#include <lib/support/BufferReader.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/silabs/multi-ota/OTAMultiImageProcessorImpl.h>
#include <platform/silabs/multi-ota/OTATlvProcessor.h>
#if OTA_ENCRYPTION_ENABLE
#include "OtaUtils.h"
#include "rom_aes.h"
#endif
namespace chip {
#if OTA_ENCRYPTION_ENABLE
constexpr uint8_t au8Iv[] = { 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00 };
#endif
CHIP_ERROR OTATlvProcessor::Process(ByteSpan & block)
{
CHIP_ERROR status = CHIP_NO_ERROR;
uint32_t bytes = chip::min(mLength - mProcessedLength, static_cast<uint32_t>(block.size()));
ByteSpan relevantData = block.SubSpan(0, bytes);
status = ProcessInternal(relevantData);
if (!IsError(status))
{
mProcessedLength += bytes;
block = block.SubSpan(bytes);
if (mProcessedLength == mLength)
{
status = ExitAction();
if (!IsError(status))
{
// If current block was processed fully and the block still contains data, it
// means that the block contains another TLV's data and the current processor
// should be changed by OTAMultiImageProcessorImpl.
return CHIP_OTA_CHANGE_PROCESSOR;
}
}
}
return status;
}
void OTATlvProcessor::ClearInternal()
{
mLength = 0;
mProcessedLength = 0;
mWasSelected = false;
#if OTA_ENCRYPTION_ENABLE
mIVOffset = 0;
#endif
}
bool OTATlvProcessor::IsError(CHIP_ERROR & status)
{
return status != CHIP_NO_ERROR && status != CHIP_ERROR_BUFFER_TOO_SMALL && status != CHIP_OTA_FETCH_ALREADY_SCHEDULED;
}
void OTADataAccumulator::Init(uint32_t threshold)
{
mThreshold = threshold;
mBufferOffset = 0;
mBuffer.Alloc(mThreshold);
}
void OTADataAccumulator::Clear()
{
mThreshold = 0;
mBufferOffset = 0;
mBuffer.Free();
}
CHIP_ERROR OTADataAccumulator::Accumulate(ByteSpan & block)
{
uint32_t numBytes = chip::min(mThreshold - mBufferOffset, static_cast<uint32_t>(block.size()));
memcpy(&mBuffer[mBufferOffset], block.data(), numBytes);
mBufferOffset += numBytes;
block = block.SubSpan(numBytes);
if (mBufferOffset < mThreshold)
{
return CHIP_ERROR_BUFFER_TOO_SMALL;
}
return CHIP_NO_ERROR;
}
#if OTA_ENCRYPTION_ENABLE
CHIP_ERROR OTATlvProcessor::vOtaProcessInternalEncryption(MutableByteSpan & block)
{
uint8_t iv[16];
uint8_t key[kOTAEncryptionKeyLength];
uint8_t dataOut[16] = { 0 };
uint32_t u32IVCount;
uint32_t Offset = 0;
uint8_t data;
tsReg128 sKey;
aesContext_t Context;
memcpy(iv, au8Iv, sizeof(au8Iv));
u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]);
u32IVCount += (mIVOffset >> 4);
iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
iv[15] = (uint8_t) (u32IVCount & 0xff);
if (Encoding::HexToBytes(OTA_ENCRYPTION_KEY, strlen(OTA_ENCRYPTION_KEY), key, kOTAEncryptionKeyLength) !=
kOTAEncryptionKeyLength)
{
// Failed to convert the OTAEncryptionKey string to octstr type value
return CHIP_ERROR_INVALID_STRING_LENGTH;
}
ByteSpan KEY = ByteSpan(key);
Encoding::LittleEndian::Reader reader_key(KEY.data(), KEY.size());
ReturnErrorOnFailure(reader_key.Read32(&sKey.u32register0)
.Read32(&sKey.u32register1)
.Read32(&sKey.u32register2)
.Read32(&sKey.u32register3)
.StatusCode());
while (Offset + 16 <= block.size())
{
/*Encrypt the IV*/
Context.mode = AES_MODE_ECB_ENCRYPT;
Context.pSoftwareKey = (uint32_t *) &sKey;
AES_128_ProcessBlocks(&Context, (uint32_t *) &iv[0], (uint32_t *) &dataOut[0], 1);
/* Decrypt a block of the buffer */
for (uint8_t i = 0; i < 16; i++)
{
data = block[Offset + i] ^ dataOut[i];
memcpy(&block[Offset + i], &data, sizeof(uint8_t));
}
/* increment the IV for the next block */
u32IVCount++;
iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff);
iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff);
iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff);
iv[15] = (uint8_t) (u32IVCount & 0xff);
Offset += 16; /* increment the buffer offset */
mIVOffset += 16;
}
return CHIP_NO_ERROR;
}
#endif
} // namespace chip