blob: 91c33cdb858ed44d06c5dcee10b47433cfdec872 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2025 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 <pw_unit_test/framework.h>
#include <controller/AutoCommissioner.h>
#include <controller/CommissioningDelegate.h>
#include <controller/tests/AutoCommissionerTestAccess.h>
#include <crypto/CHIPCryptoPAL.h>
#include <cstring>
#include <lib/core/StringBuilderAdapters.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/Span.h>
#include <memory>
using namespace chip;
using namespace chip::Dnssd;
using namespace chip::Controller;
using namespace chip::Test;
namespace {
constexpr uint64_t epochJanFirst2000 = 946695600; // Monday, January 1, 2000 12:00 AM
constexpr uint64_t epochJanFirst2001 = 978318000; // Monday, January 1, 2001 12:00 AM
class AutoCommissionerTest : public ::testing::Test
{
protected:
AutoCommissioner mCommissioner{};
CommissioningParameters mParams{};
};
TEST_F(AutoCommissionerTest, DetectsThreadOperationalDatasetExceedsBuffer)
{
auto up = std::make_unique<uint8_t[]>(CommissioningParameters::kMaxThreadDatasetLen + 1);
ASSERT_TRUE(up);
std::memset(up.get(), 0x00, CommissioningParameters::kMaxThreadDatasetLen + 1);
mParams.SetThreadOperationalDataset(ByteSpan{ up.get(), CommissioningParameters::kMaxThreadDatasetLen + 1 });
auto r = mCommissioner.SetCommissioningParameters(mParams);
ASSERT_EQ(r, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(AutoCommissionerTest, DetectsWifiCredentialsExceedBuffer)
{
auto ssid_buffer_up = std::make_unique<uint8_t[]>(CommissioningParameters::kMaxSsidLen + 1);
auto creds_buffer_up = std::make_unique<uint8_t[]>(CommissioningParameters::kMaxCredentialsLen + 1);
mParams.SetWiFiCredentials(WiFiCredentials{
ByteSpan{ ssid_buffer_up.get(), CommissioningParameters::kMaxSsidLen + 1 },
ByteSpan{ creds_buffer_up.get(), CommissioningParameters::kMaxCredentialsLen + 1 },
});
auto r = mCommissioner.SetCommissioningParameters(mParams);
ASSERT_EQ(r, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(AutoCommissionerTest, DetectsCountryCodeExceedsBuffer)
{
mParams.SetCountryCode("012"_span);
auto r = mCommissioner.SetCommissioningParameters(mParams);
ASSERT_EQ(r, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(AutoCommissionerTest, DetectsAttestationNonceExceedsBuffer)
{
auto attestation_nonce_buffer_up = std::make_unique<uint8_t[]>(kAttestationNonceLength + 1);
mParams.SetAttestationNonce(ByteSpan{ attestation_nonce_buffer_up.get(), kAttestationNonceLength + 1 });
auto r = mCommissioner.SetCommissioningParameters(mParams);
ASSERT_EQ(r, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(AutoCommissionerTest, DetectsCSRNonceExceedsBuffer)
{
auto csr_nonce_buffer_up = std::make_unique<uint8_t[]>(kCSRNonceLength + 1);
mParams.SetCSRNonce(ByteSpan{ csr_nonce_buffer_up.get(), kCSRNonceLength + 1 });
auto r = mCommissioner.SetCommissioningParameters(mParams);
ASSERT_EQ(r, CHIP_ERROR_INVALID_ARGUMENT);
}
TEST_F(AutoCommissionerTest, FeaturesPassedDSTOffsetsValue)
{
app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type sDSTBuf;
sDSTBuf.offset = int32_t{ 10 };
sDSTBuf.validStarting = epochJanFirst2000;
sDSTBuf.validUntil = epochJanFirst2001;
app::DataModel::List<app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type> list(&sDSTBuf, 1);
mParams.SetDSTOffsets(list);
auto r = mCommissioner.SetCommissioningParameters(mParams);
auto commissioning_params = mCommissioner.GetCommissioningParameters();
ASSERT_EQ(r, CHIP_NO_ERROR);
ASSERT_TRUE(commissioning_params.GetDSTOffsets().HasValue());
ASSERT_EQ(commissioning_params.GetDSTOffsets().Value().size(), size_t{ 1 });
ASSERT_EQ(commissioning_params.GetDSTOffsets().Value()[0].offset, 10);
ASSERT_EQ(commissioning_params.GetDSTOffsets().Value()[0].validStarting, epochJanFirst2000);
ASSERT_EQ(commissioning_params.GetDSTOffsets().Value()[0].validUntil, epochJanFirst2001);
}
TEST_F(AutoCommissionerTest, FeaturesPassedTimeZoneValue)
{
app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type sTimeZoneBuf;
constexpr CharSpan countryName = "ARG"_span;
sTimeZoneBuf.offset = int32_t{ 10 };
sTimeZoneBuf.validAt = epochJanFirst2000; // Monday, January 1, 2000 12:00 AM
sTimeZoneBuf.name.SetValue(chip::CharSpan{ countryName });
app::DataModel::List<app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type> list(&sTimeZoneBuf, 1);
mParams.SetTimeZone(list);
auto r = mCommissioner.SetCommissioningParameters(mParams);
auto commissioning_params = mCommissioner.GetCommissioningParameters();
ASSERT_EQ(r, CHIP_NO_ERROR);
ASSERT_TRUE(commissioning_params.GetTimeZone().HasValue());
ASSERT_EQ(commissioning_params.GetTimeZone().Value().size(), size_t{ 1 });
ASSERT_EQ(commissioning_params.GetTimeZone().Value()[0].offset, 10);
ASSERT_EQ(commissioning_params.GetTimeZone().Value()[0].validAt, epochJanFirst2000);
ASSERT_TRUE(commissioning_params.GetTimeZone().Value()[0].name.HasValue());
ASSERT_TRUE(commissioning_params.GetTimeZone().Value()[0].name.Value().data_equal("ARG"_span));
}
TEST_F(AutoCommissionerTest, FeaturesPassedNTPValue)
{
constexpr CharSpan defaultNTPBuffer = "default"_span;
mParams.SetDefaultNTP(chip::app::DataModel::MakeNullable(defaultNTPBuffer));
auto r = mCommissioner.SetCommissioningParameters(mParams);
auto commissioning_params = mCommissioner.GetCommissioningParameters();
ASSERT_EQ(r, CHIP_NO_ERROR);
ASSERT_TRUE(commissioning_params.GetDefaultNTP().HasValue());
ASSERT_TRUE(commissioning_params.GetDefaultNTP().Value().Value().data_equal("default"_span));
}
TEST_F(AutoCommissionerTest, FeaturesPassedICDRegistrationKey)
{
mParams.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete);
uint8_t symmetric_key_buffer[Crypto::kAES_CCM128_Key_Length];
std::memset(symmetric_key_buffer, 0x00, Crypto::kAES_CCM128_Key_Length);
mParams.SetICDSymmetricKey(ByteSpan{ symmetric_key_buffer, Crypto::kAES_CCM128_Key_Length });
mParams.SetICDCheckInNodeId(NodeId{ 10000 });
mParams.SetICDMonitoredSubject(uint64_t{ 9999 });
mParams.SetICDClientType(app::Clusters::IcdManagement::ClientTypeEnum::kPermanent);
auto r = mCommissioner.SetCommissioningParameters(mParams);
auto commissioning_params = mCommissioner.GetCommissioningParameters();
ASSERT_EQ(r, CHIP_NO_ERROR);
ASSERT_TRUE(commissioning_params.GetICDSymmetricKey().HasValue());
ASSERT_EQ(commissioning_params.GetICDRegistrationStrategy(), ICDRegistrationStrategy::kBeforeComplete);
ASSERT_TRUE(commissioning_params.GetICDSymmetricKey().HasValue());
ASSERT_EQ(commissioning_params.GetICDSymmetricKey().Value().size(), Crypto::kAES_CCM128_Key_Length);
ASSERT_TRUE(commissioning_params.GetICDSymmetricKey().Value().data_equal(ByteSpan{ symmetric_key_buffer }));
ASSERT_TRUE(commissioning_params.GetICDCheckInNodeId().HasValue());
ASSERT_EQ(commissioning_params.GetICDCheckInNodeId().Value(), NodeId{ 10000 });
ASSERT_TRUE(commissioning_params.GetICDMonitoredSubject().HasValue());
ASSERT_EQ(commissioning_params.GetICDMonitoredSubject().Value(), uint64_t{ 9999 });
ASSERT_TRUE(commissioning_params.GetICDClientType().HasValue());
ASSERT_EQ(commissioning_params.GetICDClientType().Value(), app::Clusters::IcdManagement::ClientTypeEnum::kPermanent);
}
TEST_F(AutoCommissionerTest, FeaturesPassedExtraReadPaths)
{
chip::app::AttributePathParams attributes[1];
constexpr uint32_t endpointId = 1;
constexpr uint32_t clusterId = 2;
constexpr uint32_t attributeId = 3;
attributes[0] = chip::app::AttributePathParams{ endpointId, clusterId, attributeId };
mParams.SetExtraReadPaths(Span<const app::AttributePathParams>{ attributes, 1 });
auto pathParams = mParams.GetExtraReadPaths();
ASSERT_EQ(pathParams.size(), size_t{ 1 });
ASSERT_EQ(pathParams[0].mEndpointId, endpointId);
ASSERT_EQ(pathParams[0].mClusterId, clusterId);
ASSERT_EQ(pathParams[0].mAttributeId, attributeId);
}
// kStages are enumerators from enum type name CommissioningStage
struct StageTransition
{
CommissioningStage currentStage;
CommissioningStage nextStage;
};
const std::vector<StageTransition> kStagePairs = {
// Only linear transitions are tested here;
// Branching cases (like kReadCommissioningInfo, kConfigureTCAcknowledgments, etc.) are tested separately
{ kSecurePairing, kReadCommissioningInfo },
{ kArmFailsafe, kConfigRegulatory },
{ kConfigRegulatory, kConfigureTCAcknowledgments },
{ kConfigureDefaultNTP, kSendPAICertificateRequest },
{ kSendPAICertificateRequest, kSendDACCertificateRequest },
{ kSendDACCertificateRequest, kSendAttestationRequest },
{ kSendAttestationRequest, kAttestationVerification },
{ kAttestationVerification, kAttestationRevocationCheck },
{ kJCMTrustVerification, kSendOpCertSigningRequest },
{ kSendOpCertSigningRequest, kValidateCSR },
{ kValidateCSR, kGenerateNOCChain },
{ kGenerateNOCChain, kSendTrustedRootCert },
{ kSendTrustedRootCert, kSendNOC },
{ kICDGetRegistrationInfo, kICDRegistration },
{ kScanNetworks, kNeedsNetworkCreds },
{ kWiFiNetworkSetup, kFailsafeBeforeWiFiEnable },
{ kThreadNetworkSetup, kFailsafeBeforeThreadEnable },
{ kFailsafeBeforeWiFiEnable, kWiFiNetworkEnable },
{ kFailsafeBeforeThreadEnable, kThreadNetworkEnable },
{ kEvictPreviousCaseSessions, kFindOperationalForStayActive },
{ kFindOperationalForStayActive, kICDSendStayActive },
{ kICDSendStayActive, kFindOperationalForCommissioningComplete },
{ kFindOperationalForCommissioningComplete, kSendComplete },
{ kSendComplete, kCleanup },
{ kCleanup, kError },
{ kError, kError },
{ static_cast<CommissioningStage>(250), kError }, // triggers default case in switch statement
};
// Test each case pair for the next commissioning stage
TEST_F(AutoCommissionerTest, NextCommissioningStage)
{
// Accessor class used due to private/protected members.
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = CHIP_NO_ERROR;
for (const auto & stagePair : kStagePairs)
{
CommissioningStage nextStage =
privateConfigCommissioner.AccessGetNextCommissioningStageInternal(stagePair.currentStage, err);
EXPECT_EQ(nextStage, stagePair.nextStage);
}
}
// if commissioning is manually stopped, the next stage should be kCleanup
TEST_F(AutoCommissionerTest, NextStageStopCommissioning)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
mCommissioner.StopCommissioning();
CHIP_ERROR err = CHIP_ERROR_INTERNAL;
CommissioningStage stage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSecurePairing, err);
EXPECT_EQ(stage, kCleanup);
}
// if commissioning failed, then the next stage should be cleanup
TEST_F(AutoCommissionerTest, NextCommissioningStageAfterError)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = CHIP_ERROR_INTERNAL;
CommissioningStage stage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSecurePairing, err);
EXPECT_EQ(stage, kCleanup);
}
// Verifies that the commissioner proceeds to ConfigureTCAcknowledgments under the correct conditions.
TEST_F(AutoCommissionerTest, NextStageReadCommissioningInfo)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = CHIP_NO_ERROR;
privateConfigCommissioner.SetBreadcrumb(0);
CommissioningStage nextStage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kReadCommissioningInfo, err);
EXPECT_EQ(nextStage, kArmFailsafe);
// if breadcrumb > 0, the stage changes to kSendNOC; subsequent stages progress accordingly.
privateConfigCommissioner.SetBreadcrumb(1);
CommissioningStage nextStageReadCommissioningInfo =
privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kReadCommissioningInfo, err);
CommissioningStage nextStageSendNOC = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSendNOC, err);
EXPECT_EQ(nextStageReadCommissioningInfo, nextStageSendNOC);
}
// Ensures TCAcknowledgment stage is triggered only under expected commissioning conditions.
TEST_F(AutoCommissionerTest, NextStageConfigureTCAcknowledgments)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = CHIP_NO_ERROR;
privateConfigCommissioner.SetUTCRequirements(true);
CommissioningStage nextStage =
privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kConfigureTCAcknowledgments, err);
EXPECT_EQ(nextStage, kConfigureUTCTime);
privateConfigCommissioner.SetUTCRequirements(false);
nextStage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kConfigureTCAcknowledgments, err);
EXPECT_EQ(nextStage, kSendPAICertificateRequest);
}
namespace TestCerts {
/*
* Test certificates and keys used for AutoCommissioner tests only.
* These are “real” certificates (not arbitrary numbers) to ensure that
* NOCChainGenerated calls ConvertX509CertToChipCert correctly.
*
* These certificates were generated using the CHIP cert tool.
*
* Example command:
* ./chip-cert gen-cert \
* --type -- \
* --subject-chip-id -- \
* --valid-from -- \
* --lifetime -- \
* --out-key -- \
* --out -- \
* --out-format --
*
* # Converted PEM to DER
* openssl x509 -in out.pem -outform DER -out out.der
*
* # Convert DER to C array for inclusion in test
* xxd -i out.der > out.cpp
*
* Arrays below (kTestRCAC, kTestICAC, kTestIcacNOC) represent the DER bytes
* of the certificates. kTestIPK is a symmetric key used in tests.
*
* See more in Matter documentation: tools/matter/chip/certificate-tool
*/
constexpr uint8_t kTestRCAC[] = {
0x30, 0x82, 0x01, 0x9d, 0x30, 0x82, 0x01, 0x43, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x03, 0x98, 0x46, 0xb6, 0xd0, 0x8f,
0x11, 0x88, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x22, 0x31, 0x20, 0x30, 0x1e, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32,
0x33, 0x34, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32, 0x33, 0x34, 0x32, 0x5a, 0x30, 0x22,
0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x43, 0x41, 0x43,
0x41, 0x43, 0x41, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x1b, 0x71,
0x65, 0x37, 0xe3, 0xa1, 0xe7, 0xdb, 0x11, 0x5f, 0xd0, 0xd3, 0x4b, 0xda, 0xf7, 0xd2, 0x85, 0x7c, 0xdc, 0xfd, 0x68, 0xcc, 0x6d,
0xfa, 0x91, 0xab, 0xa8, 0x7c, 0xfd, 0x70, 0x5a, 0x4a, 0x23, 0x7b, 0x2c, 0x54, 0x43, 0xa0, 0x9a, 0x00, 0xb6, 0xdd, 0xbb, 0xc4,
0xdc, 0xcd, 0x2b, 0x0c, 0x01, 0xfe, 0xa6, 0x01, 0x2e, 0xc6, 0x39, 0x21, 0x89, 0x28, 0xfa, 0x14, 0x65, 0x53, 0xd7, 0x85, 0xa3,
0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
0x0e, 0x04, 0x16, 0x04, 0x14, 0xa4, 0xd4, 0xe6, 0x34, 0x79, 0x07, 0xa0, 0x6f, 0xab, 0xe7, 0x2a, 0xd0, 0x51, 0x26, 0xe0, 0x59,
0x85, 0xb7, 0x08, 0x0d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa4, 0xd4, 0xe6, 0x34,
0x79, 0x07, 0xa0, 0x6f, 0xab, 0xe7, 0x2a, 0xd0, 0x51, 0x26, 0xe0, 0x59, 0x85, 0xb7, 0x08, 0x0d, 0x30, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xff, 0x03, 0x62, 0x9f, 0xd7, 0x49,
0xbf, 0x17, 0xf1, 0x45, 0x97, 0x33, 0x0d, 0x4b, 0xb0, 0x9a, 0xe9, 0xc8, 0x80, 0x25, 0xcc, 0x6c, 0x9b, 0x50, 0x1b, 0xbe, 0xd9,
0xd0, 0x75, 0xb7, 0x45, 0x02, 0x02, 0x20, 0x57, 0xe5, 0xe2, 0x79, 0x40, 0xc7, 0x0b, 0xb9, 0x78, 0x9e, 0x9a, 0xdf, 0x51, 0xa7,
0x44, 0x92, 0x6a, 0x2b, 0xf8, 0x67, 0x01, 0x86, 0x1e, 0xa3, 0xc3, 0xeb, 0xfc, 0x13, 0x7b, 0x2f, 0x75, 0x42
};
const uint8_t kTestICAC[] = {
0x30, 0x82, 0x01, 0x9d, 0x30, 0x82, 0x01, 0x43, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x75, 0x57, 0x30, 0xd4, 0xc5, 0xf0,
0x65, 0xb6, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x22, 0x31, 0x20, 0x30, 0x1e, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x04, 0x0c, 0x10, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32,
0x33, 0x34, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32, 0x33, 0x34, 0x32, 0x5a, 0x30, 0x22,
0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x03, 0x0c, 0x10, 0x43, 0x41, 0x43,
0x41, 0x43, 0x41, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x76, 0xd9,
0xb1, 0xd3, 0xed, 0x44, 0xba, 0x51, 0x86, 0x83, 0x1e, 0xf7, 0x41, 0xba, 0x70, 0x7f, 0xfe, 0x1c, 0x1b, 0xbb, 0x94, 0x53, 0x4b,
0x4c, 0x65, 0x6e, 0x1c, 0x39, 0xdd, 0xe7, 0xa8, 0xf7, 0x3e, 0x9c, 0xc9, 0xb5, 0x82, 0x86, 0x14, 0xb0, 0xc0, 0xb3, 0x40, 0x2a,
0xf9, 0x2d, 0x62, 0x03, 0x65, 0x4f, 0x15, 0xa9, 0x53, 0x0a, 0x79, 0xaa, 0xe5, 0xa9, 0x3c, 0x3a, 0xbf, 0xed, 0x6e, 0xd2, 0xa3,
0x63, 0x30, 0x61, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
0x0e, 0x04, 0x16, 0x04, 0x14, 0x74, 0xa6, 0x08, 0xd0, 0x78, 0xc2, 0x5c, 0x3c, 0x31, 0xf1, 0x78, 0x08, 0x3f, 0x9d, 0x37, 0x7e,
0xf5, 0x73, 0x79, 0x61, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa4, 0xd4, 0xe6, 0x34,
0x79, 0x07, 0xa0, 0x6f, 0xab, 0xe7, 0x2a, 0xd0, 0x51, 0x26, 0xe0, 0x59, 0x85, 0xb7, 0x08, 0x0d, 0x30, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xe4, 0x44, 0xed, 0x33, 0x8a, 0x6c,
0xf5, 0x90, 0xfa, 0xd1, 0xbe, 0x6e, 0x79, 0xfe, 0x2f, 0x5d, 0x4d, 0x09, 0x39, 0xae, 0x63, 0x0d, 0xe8, 0xd1, 0x41, 0x3b, 0x64,
0x3c, 0x8a, 0x05, 0x76, 0xaa, 0x02, 0x20, 0x17, 0x34, 0xbd, 0x91, 0xef, 0xcd, 0x16, 0x60, 0x48, 0xac, 0xb0, 0x0a, 0xcf, 0x2b,
0xea, 0x0c, 0x91, 0xe9, 0xeb, 0xc6, 0xcd, 0xe7, 0x4b, 0x1c, 0x24, 0x2c, 0xff, 0xd8, 0x3a, 0x86, 0x32, 0xbc
};
const uint8_t kTestIcacNOC[] = {
0x30, 0x82, 0x01, 0xe1, 0x30, 0x82, 0x01, 0x86, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x2b, 0x15, 0x4b, 0x87, 0x6a, 0x57,
0xf7, 0x50, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x22, 0x31, 0x20, 0x30, 0x1e, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x03, 0x0c, 0x10, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41, 0x43, 0x41,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32,
0x33, 0x34, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x30, 0x31, 0x30, 0x31, 0x35, 0x31, 0x34, 0x32, 0x33, 0x34, 0x32, 0x5a, 0x30, 0x44,
0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x01, 0x0c, 0x10, 0x44, 0x45, 0x44,
0x45, 0x44, 0x45, 0x44, 0x45, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x44, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x0a, 0x2b, 0x06,
0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x01, 0x05, 0x0c, 0x10, 0x46, 0x41, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x31, 0x44, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xe9, 0x00, 0x43, 0x2f, 0x2d, 0x50, 0x42, 0xab, 0xdc, 0xac,
0x21, 0xec, 0x59, 0xc6, 0x81, 0xfe, 0x2e, 0x3e, 0x68, 0x0b, 0xf9, 0x07, 0x02, 0x56, 0x34, 0x1c, 0x13, 0x6e, 0x8f, 0x89, 0x80,
0xe4, 0xdd, 0xa1, 0x85, 0x74, 0x57, 0x7b, 0xeb, 0x34, 0x2e, 0x33, 0x2b, 0xed, 0xe1, 0x75, 0xa3, 0x48, 0x54, 0x2e, 0x91, 0x43,
0xb2, 0xa5, 0x5e, 0x3e, 0x44, 0x15, 0xa9, 0x1c, 0x6b, 0x3c, 0x14, 0x31, 0xa3, 0x81, 0x83, 0x30, 0x81, 0x80, 0x30, 0x0c, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06,
0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1d,
0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x7c, 0x8d, 0xf2, 0x93, 0x8b, 0x96, 0xac, 0xc9, 0xab, 0x49, 0x92, 0xc5,
0x66, 0xef, 0xf1, 0xfe, 0x09, 0x3e, 0x57, 0x4b, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
0x74, 0xa6, 0x08, 0xd0, 0x78, 0xc2, 0x5c, 0x3c, 0x31, 0xf1, 0x78, 0x08, 0x3f, 0x9d, 0x37, 0x7e, 0xf5, 0x73, 0x79, 0x61, 0x30,
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xb7, 0x35,
0x48, 0x18, 0x05, 0xed, 0xe5, 0x3a, 0xea, 0x64, 0x9b, 0x30, 0x26, 0x8e, 0xc4, 0x8c, 0x0b, 0x55, 0x92, 0xaa, 0xc0, 0xc4, 0xac,
0x0b, 0xa7, 0xf3, 0x85, 0x4a, 0x14, 0x92, 0x03, 0xa4, 0x02, 0x21, 0x00, 0xde, 0x84, 0xa6, 0x86, 0x3c, 0x2f, 0x2b, 0x74, 0xf6,
0xc6, 0xf2, 0x75, 0x87, 0xe2, 0x64, 0x1f, 0x41, 0xd9, 0x2f, 0xf9, 0x1e, 0xa7, 0x15, 0x3a, 0x0e, 0xf2, 0xb6, 0x61, 0xec, 0x62,
0xc2, 0x32
};
const uint8_t kTestIPK[chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00 };
} // namespace TestCerts
namespace {
const ByteSpan kValidRCAC(TestCerts::kTestRCAC);
const ByteSpan kValidNOC(TestCerts::kTestICAC);
const ByteSpan kValidICAC(TestCerts::kTestIcacNOC);
const Crypto::IdentityProtectionKeySpan kValidIpk(TestCerts::kTestIPK);
const NodeId kValidNodeId = 0x000;
// Invalid buffers
const ByteSpan kInvalidEmptyRCAC;
const ByteSpan kInvalidEmptyNOC;
uint8_t buffer[10];
ByteSpan kCoruptedBufferInvalidRCAC(buffer, static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1);
ByteSpan kCoruptedBufferInvalidNOC(buffer, static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1);
} // namespace
// Happy paths and valid arguments are thoroughly checked with the Python integration test in
// src/controller/python/OpCredsBinding.cpp
// Ensures empty RCAC certificates aren't admitted
TEST_F(AutoCommissionerTest, NOCChainGenerated_EmptyRCACReturnsInvalidArgument)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = privateConfigCommissioner.NOCChainGenerated(kValidNOC, kValidICAC, kInvalidEmptyRCAC, kValidIpk, kValidNodeId);
EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT);
}
// On 32-bit systems, NOCChainGenerated cannot fail due to size_t being 32 bits and never exceeding uint32_t,
// therefore we skip some tests.
#if SIZE_MAX > UINT32_MAX
// Ensures extra checks are done with RCAC buffer size
TEST_F(AutoCommissionerTest, NOCChainGenerated_CorruptedRCACLengthReturnsError)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err =
privateConfigCommissioner.NOCChainGenerated(kValidNOC, kValidICAC, kCoruptedBufferInvalidRCAC, kValidIpk, kValidNodeId);
EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT);
}
// Ensures extra checks are done with NOC buffer size
TEST_F(AutoCommissionerTest, NOCChainGenerated_CorruptedNOCLengthReturnsError)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err =
privateConfigCommissioner.NOCChainGenerated(kCoruptedBufferInvalidNOC, kValidICAC, kValidRCAC, kValidIpk, kValidNodeId);
EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT);
}
#endif
// Ensures empty NOC certificates aren't admitted
TEST_F(AutoCommissionerTest, NOCChainGenerated_EmptyNOCReturnsInvalidArgument)
{
AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
CHIP_ERROR err = privateConfigCommissioner.NOCChainGenerated(kInvalidEmptyNOC, kValidICAC, kValidRCAC, kValidIpk, kValidNodeId);
EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT);
}
} // namespace