| /* |
| * |
| * Copyright (c) 2022 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 <crypto/CHIPCryptoPAL.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| |
| #include "CommissionableInit.h" |
| |
| namespace chip { |
| namespace examples { |
| |
| using namespace chip::DeviceLayer; |
| using namespace chip::DeviceLayer::Internal; |
| |
| namespace { |
| |
| bool IsNotFound(CHIP_ERROR err) |
| { |
| // PosixConfig should probably return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND, but some implementations use other error codes. |
| return (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND || |
| err == CHIP_ERROR_NOT_FOUND || err == CHIP_ERROR_KEY_NOT_FOUND); |
| } |
| |
| template <typename T> |
| CHIP_ERROR ReadOptionalConfigValue(PosixConfig::Key key, Optional<T> & outValue) |
| { |
| CHIP_ERROR err = PosixConfig::ReadConfigValue(key, outValue.Emplace()); |
| if (err != CHIP_NO_ERROR) |
| { |
| outValue.ClearValue(); |
| if (IsNotFound(err)) |
| { |
| err = CHIP_NO_ERROR; // value is optional, not found is OK |
| } |
| } |
| return err; |
| } |
| |
| CHIP_ERROR ReadOptionalConfigValueBin(PosixConfig::Key key, size_t bufSize, chip::Optional<std::vector<uint8_t>> & outValue) |
| { |
| size_t length; |
| outValue.Emplace(bufSize); |
| CHIP_ERROR err = PosixConfig::ReadConfigValueBin(key, outValue.Value().data(), outValue.Value().size(), length); |
| if (err == CHIP_NO_ERROR) |
| { |
| outValue.Value().resize(length); |
| } |
| else |
| { |
| outValue.ClearValue(); |
| if (IsNotFound(err)) |
| { |
| err = CHIP_NO_ERROR; // value is optional, not found is OK |
| } |
| } |
| return err; |
| } |
| |
| CHIP_ERROR GetPinCodeAndVerifier(const LinuxDeviceOptions & options, chip::Optional<uint32_t> & outPinCode, |
| chip::Optional<std::vector<uint8_t>> & outVerifier) |
| { |
| // Command line options take precedence |
| outPinCode = (options.payload.setUpPINCode != 0 ? MakeOptional(options.payload.setUpPINCode) : NullOptional); |
| outVerifier = options.spake2pVerifier; |
| if (outPinCode.HasValue() || outVerifier.HasValue()) |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| // Read from PosixConfig |
| ReturnErrorOnFailure(ReadOptionalConfigValue(PosixConfig::kConfigKey_SetupPinCode, outPinCode)); |
| ReturnErrorOnFailure(ReadOptionalConfigValueBin(PosixConfig::kConfigKey_Spake2pVerifier, |
| Crypto::kSpake2p_VerifierSerialized_Length, outVerifier)); |
| if (outPinCode.HasValue() || outVerifier.HasValue()) |
| { |
| return CHIP_NO_ERROR; |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS |
| // Fall back to test parameters. Note: CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER is not supported. |
| outPinCode.SetValue(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE); |
| ChipLogError(NotSpecified, |
| "*** WARNING: Using temporary passcode %u due to no neither --passcode or --spake2p-verifier-base64 " |
| "given on command line or factory configuration. This is temporary and will disappear. " |
| "Please update your scripts to explicitly configure onboarding credentials. ***", |
| static_cast<unsigned>(outPinCode.Value())); |
| return CHIP_NO_ERROR; |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS |
| |
| ChipLogError(NotSpecified, "Unable to initialize commissionable device, no passcode or verifier configured"); |
| return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; |
| } |
| |
| CHIP_ERROR GetSpake2pSalt(const LinuxDeviceOptions & options, chip::Optional<std::vector<uint8_t>> & outSalt) |
| { |
| // Command line options take precedence |
| if (options.spake2pSalt.HasValue()) |
| { |
| outSalt = options.spake2pSalt; |
| return CHIP_NO_ERROR; |
| } |
| |
| // Read from PosixConfig. If not set a random salt will be generated by LinuxCommissionableDataProvider. |
| // Note: CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT is no longer supported. |
| return ReadOptionalConfigValueBin(PosixConfig::kConfigKey_Spake2pSalt, Crypto::kSpake2p_Max_PBKDF_Salt_Length, outSalt); |
| } |
| |
| CHIP_ERROR GetIterationCount(const LinuxDeviceOptions & options, uint32_t & outIterationCount) |
| { |
| // Command line options take precedence |
| if (options.spake2pIterations != 0) |
| { |
| outIterationCount = options.spake2pIterations; |
| return CHIP_NO_ERROR; |
| } |
| |
| // Read from PosixConfig |
| CHIP_ERROR err = PosixConfig::ReadConfigValue(PosixConfig::kConfigKey_Spake2pIterationCount, outIterationCount); |
| VerifyOrReturnError(IsNotFound(err), err); |
| |
| // CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT is no longer supported, default to minimum PBKDF iterations |
| outIterationCount = Crypto::kSpake2p_Min_PBKDF_Iterations; |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR GetDiscriminator(const LinuxDeviceOptions & options, uint16_t & outDiscriminator) |
| { |
| // Command line options take precedence |
| if (options.discriminator.HasValue()) |
| { |
| outDiscriminator = options.discriminator.Value(); |
| return CHIP_NO_ERROR; |
| } |
| |
| // Read from PosixConfig |
| CHIP_ERROR err = PosixConfig::ReadConfigValue(PosixConfig::kConfigKey_SetupDiscriminator, outDiscriminator); |
| VerifyOrReturnError(IsNotFound(err), err); |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS |
| // Fall back to test parameters |
| outDiscriminator = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; |
| ChipLogError(NotSpecified, |
| "*** WARNING: Using temporary test discriminator %u due to --discriminator not " |
| "given on command line or factory configuration. This is temporary and will disappear. " |
| "Please update your scripts to explicitly configure onboarding credentials. ***", |
| static_cast<unsigned>(outDiscriminator)); |
| return CHIP_NO_ERROR; |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS |
| |
| ChipLogError(NotSpecified, "Unable to initialize commissionable device, no discriminator configured"); |
| return CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; |
| } |
| |
| } // namespace |
| |
| CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & provider, const LinuxDeviceOptions & options) |
| { |
| chip::Optional<uint32_t> setupPasscode; |
| chip::Optional<std::vector<uint8_t>> spake2pVerifier; |
| ReturnErrorOnFailure(GetPinCodeAndVerifier(options, setupPasscode, spake2pVerifier)); |
| |
| chip::Optional<std::vector<uint8_t>> spake2pSalt; |
| ReturnErrorOnFailure(GetSpake2pSalt(options, spake2pSalt)); |
| |
| uint32_t spake2pIterationCount; |
| ReturnErrorOnFailure(GetIterationCount(options, spake2pIterationCount)); |
| |
| uint16_t discriminator; |
| ReturnErrorOnFailure(GetDiscriminator(options, discriminator)); |
| |
| return provider.Init(spake2pVerifier, spake2pSalt, spake2pIterationCount, setupPasscode, discriminator); |
| } |
| |
| CHIP_ERROR InitConfigurationManager(ConfigurationManagerImpl & configManager, const LinuxDeviceOptions & options) |
| { |
| if (options.payload.vendorID != 0) |
| { |
| configManager.StoreVendorId(options.payload.vendorID); |
| } |
| |
| if (options.payload.productID != 0) |
| { |
| configManager.StoreProductId(options.payload.productID); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| } // namespace examples |
| } // namespace chip |