Files
esp-matter/examples/common/manufacturing_data_provider/ESP32ManufacturingDataProvider.cpp
Shubham Patil 6985d49f6e examples/common: manufacturing data provider implementation
Introduce a precedence-based implementation for reading manufacturing
data.

Manufacturing data can reside in either the secure-cert partition or the
fctry partition. To ensure backward compatibility with older modules
(where manufacturing data was stored in the fctry partition), this implementation
supports setting precedence between the available storage options.

Default precedence is factory first, i.e. implementation checks the data
in factory partition first and if not found falls back to check secure
cert partition.

This allows newer modules using secure-cert to coexist seamlessly with legacy ones.
2025-08-22 11:15:21 +05:30

189 lines
7.3 KiB
C++

/*
*
* Copyright (c) 2025 Project CHIP Authors
*
* 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 <crypto/CHIPCryptoPAL.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/ConfigurationManager.h>
#include <platform/ESP32/ESP32Config.h>
#include <platform/internal/GenericDeviceInstanceInfoProvider.h>
#include <ESP32ManufacturingDataProvider.h>
namespace chip {
namespace DeviceLayer {
const char * ESP32ManufacturingDataProvider::PrecedenceToString(Precedence precedence)
{
switch (precedence)
{
case Precedence::kFactoryFirst:
return "FactoryFirst";
case Precedence::kSecureCertFirst:
return "SecureCertFirst";
default:
return "Unknown";
}
}
ESP32ManufacturingDataProvider::ESP32ManufacturingDataProvider(Precedence precedence)
: CommissionableDataProvider()
#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER
, Internal::GenericDeviceInstanceInfoProvider<Internal::ESP32Config>(ConfigurationManagerImpl::GetDefaultInstance())
#endif
, mPrecedence(precedence)
{
// check data integrity of both factory and secure cert data, we should have at least one valid data provider
mFactoryDataValid = CheckFactoryDataIntegrity();
mSecureCertDataValid = CheckSecureCertDataIntegrity();
// should we really die here? can the non-Matter functionality still work?
VerifyOrReturn(mFactoryDataValid || mSecureCertDataValid,
ChipLogError(DeviceLayer, "No valid data found in factory or secure cert partition"));
SetProvidersAsPerPrecedence();
ChipLogDetail(DeviceLayer, "ESP32ManufacturingDataProvider initialized with precedence:%s",
PrecedenceToString(precedence));
}
ESP32ManufacturingDataProvider::Precedence ESP32ManufacturingDataProvider::GetPrecedence() const
{
return mPrecedence;
}
// check if the factory has valid data, if not, return false
bool ESP32ManufacturingDataProvider::CheckFactoryDataIntegrity()
{
uint16_t setupDiscriminator;
uint32_t iterationCount;
uint8_t saltBuf[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length];
uint8_t verifierBuf[chip::Crypto::kSpake2p_VerifierSerialized_Length];
uint8_t uniqueIdSpan[ConfigurationManager::kRotatingDeviceIDUniqueIDLength];
MutableByteSpan salt(saltBuf);
MutableByteSpan verifier(verifierBuf);
size_t verifierLen;
MutableByteSpan uniqueId(uniqueIdSpan);
VerifyOrReturnValue(mPrecedence == Precedence::kFactoryFirst, false);
VerifyOrReturnValue(mFactoryDataProvider.GetSetupDiscriminator(setupDiscriminator) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mFactoryDataProvider.GetSpake2pIterationCount(iterationCount) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mFactoryDataProvider.GetSpake2pSalt(salt) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mFactoryDataProvider.GetSpake2pVerifier(verifier, verifierLen) == CHIP_NO_ERROR, false);
#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
VerifyOrReturnValue(mFactoryDataProvider.GetRotatingDeviceIdUniqueId(uniqueId) == CHIP_NO_ERROR, false);
#endif // CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
return true;
}
// check if the secure cert has valid data, if not, return false
bool ESP32ManufacturingDataProvider::CheckSecureCertDataIntegrity()
{
uint16_t setupDiscriminator;
uint32_t iterationCount;
uint8_t saltBuf[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length];
uint8_t verifierBuf[chip::Crypto::kSpake2p_VerifierSerialized_Length];
uint8_t uniqueIdSpan[ConfigurationManager::kRotatingDeviceIDUniqueIDLength];
MutableByteSpan salt(saltBuf);
MutableByteSpan verifier(verifierBuf);
size_t verifierLen;
MutableByteSpan uniqueId(uniqueIdSpan);
VerifyOrReturnValue(mSecureCertDataProvider.GetSetupDiscriminator(setupDiscriminator) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mSecureCertDataProvider.GetSpake2pIterationCount(iterationCount) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mSecureCertDataProvider.GetSpake2pSalt(salt) == CHIP_NO_ERROR, false);
VerifyOrReturnValue(mSecureCertDataProvider.GetSpake2pVerifier(verifier, verifierLen) == CHIP_NO_ERROR, false);
#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
VerifyOrReturnValue(mSecureCertDataProvider.GetRotatingDeviceIdUniqueId(uniqueId) == CHIP_NO_ERROR, false);
#endif // CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
return true;
}
CHIP_ERROR ESP32ManufacturingDataProvider::SetProvidersAsPerPrecedence()
{
bool useFactoryData = false;
// we performed CheckFactoryDataIntegrity() and CheckSecureCertDataIntegrity() in constructor,
// so we can use the result here
switch (mPrecedence)
{
case Precedence::kFactoryFirst:
{
useFactoryData = mFactoryDataValid;
break;
}
case Precedence::kSecureCertFirst:
{
useFactoryData = !mSecureCertDataValid;
break;
}
default:
{
ChipLogError(DeviceLayer, "Invalid precedence");
return CHIP_ERROR_INVALID_ARGUMENT;
}
}
ChipLogProgress(DeviceLayer, "Using commissionable and device instance info providers from %s",
useFactoryData ? "factory" : "secure cert");
mCommissionableDataProvider = useFactoryData ? &mFactoryDataProvider : &mSecureCertDataProvider;
mDeviceInstanceInfoProvider = useFactoryData ? &mFactoryDataProvider : &mSecureCertDataProvider;
return CHIP_NO_ERROR;
}
CHIP_ERROR ESP32ManufacturingDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator)
{
return mCommissionableDataProvider->GetSetupDiscriminator(setupDiscriminator);
}
CHIP_ERROR ESP32ManufacturingDataProvider::GetSpake2pIterationCount(uint32_t & iterationCount)
{
return mCommissionableDataProvider->GetSpake2pIterationCount(iterationCount);
}
CHIP_ERROR ESP32ManufacturingDataProvider::GetSpake2pSalt(MutableByteSpan & saltBuf)
{
return mCommissionableDataProvider->GetSpake2pSalt(saltBuf);
}
CHIP_ERROR ESP32ManufacturingDataProvider::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen)
{
return mCommissionableDataProvider->GetSpake2pVerifier(verifierBuf, verifierLen);
}
CHIP_ERROR ESP32ManufacturingDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan)
{
#if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
return mDeviceInstanceInfoProvider->GetRotatingDeviceIdUniqueId(uniqueIdSpan);
#else
return CHIP_ERROR_NOT_IMPLEMENTED;
#endif // CHIP_DEVICE_CONFIG_ENABLE_DEVICE_INSTANCE_INFO_PROVIDER && CHIP_ENABLE_ROTATING_DEVICE_ID
}
} // namespace DeviceLayer
} // namespace chip