blob: 30732ae7e0a0344328e44de4ed4a84609d227ba1 [file] [log] [blame]
/*
*
* Copyright (c) 2020 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 <errno.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "Options.h"
#include <app/server/OnboardingCodesUtil.h>
#include <crypto/CHIPCryptoPAL.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/support/Base64.h>
#include <lib/support/BytesToHex.h>
#include <lib/support/CHIPMemString.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#if ENABLE_TRACING
#include <TracingCommandLineArgument.h> // nogncheck
#endif
#if CHIP_WITH_NLFAULTINJECTION
#include <inet/InetFaultInjection.h>
#include <lib/support/CHIPFaultInjection.h>
#include <system/SystemFaultInjection.h>
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
#include <messaging/ReliableMessageProtocolConfig.h>
#endif
using namespace chip;
using namespace chip::ArgParser;
using namespace chip::Platform;
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
using namespace chip::Access;
#endif
namespace {
LinuxDeviceOptions gDeviceOptions;
// Follow the code style of command line arguments in case we need to add more options in the future.
enum
{
kDeviceOption_BleDevice = 0x1000,
kDeviceOption_WiFi,
kDeviceOption_Thread,
kDeviceOption_Version,
kDeviceOption_VendorID,
kDeviceOption_ProductID,
kDeviceOption_CustomFlow,
kDeviceOption_Capabilities,
kDeviceOption_Discriminator,
kDeviceOption_Passcode,
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
kDeviceOption_SecuredDevicePort,
kDeviceOption_UnsecuredCommissionerPort,
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
kDeviceOption_SecuredCommissionerPort,
kCommissionerOption_FabricID,
#endif
kDeviceOption_Command,
kDeviceOption_PICS,
kDeviceOption_KVS,
kDeviceOption_InterfaceId,
kDeviceOption_Spake2pVerifierBase64,
kDeviceOption_Spake2pSaltBase64,
kDeviceOption_Spake2pIterations,
kDeviceOption_TraceFile,
kDeviceOption_TraceLog,
kDeviceOption_TraceDecode,
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
kDeviceOption_CommissioningArlEntries,
kDeviceOption_ArlEntries,
#endif
kOptionCSRResponseCSRIncorrectType,
kOptionCSRResponseCSRNonceIncorrectType,
kOptionCSRResponseCSRNonceTooLong,
kOptionCSRResponseCSRNonceInvalid,
kOptionCSRResponseNOCSRElementsTooLong,
kOptionCSRResponseAttestationSignatureIncorrectType,
kOptionCSRResponseAttestationSignatureInvalid,
kOptionCSRResponseCSRExistingKeyPair,
kDeviceOption_TestEventTriggerEnableKey,
kTraceTo,
kOptionSimulateNoInternalTime,
#if defined(PW_RPC_ENABLED)
kOptionRpcServerPort,
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
kDeviceOption_SubscriptionCapacity,
#endif
kDeviceOption_WiFiSupports5g,
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
kDeviceOption_SubscriptionResumptionRetryIntervalSec,
kDeviceOption_IdleRetransmitTimeout,
kDeviceOption_ActiveRetransmitTimeout,
kDeviceOption_ActiveThresholdTime,
#endif
#if CHIP_WITH_NLFAULTINJECTION
kDeviceOption_FaultInjection,
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
kDeviceOption_WiFi_PAF,
#endif
};
constexpr unsigned kAppUsageLength = 64;
OptionDef sDeviceOptionDefs[] = {
#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
{ "ble-device", kArgumentRequired, kDeviceOption_BleDevice },
#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
{ "wifi", kNoArgument, kDeviceOption_WiFi },
{ "wifi-supports-5g", kNoArgument, kDeviceOption_WiFiSupports5g },
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
{ "wifipaf", kArgumentRequired, kDeviceOption_WiFi_PAF },
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
#if CHIP_ENABLE_OPENTHREAD
{ "thread", kNoArgument, kDeviceOption_Thread },
#endif // CHIP_ENABLE_OPENTHREAD
{ "version", kArgumentRequired, kDeviceOption_Version },
{ "vendor-id", kArgumentRequired, kDeviceOption_VendorID },
{ "product-id", kArgumentRequired, kDeviceOption_ProductID },
{ "custom-flow", kArgumentRequired, kDeviceOption_CustomFlow },
{ "capabilities", kArgumentRequired, kDeviceOption_Capabilities },
{ "discriminator", kArgumentRequired, kDeviceOption_Discriminator },
{ "passcode", kArgumentRequired, kDeviceOption_Passcode },
{ "spake2p-verifier-base64", kArgumentRequired, kDeviceOption_Spake2pVerifierBase64 },
{ "spake2p-salt-base64", kArgumentRequired, kDeviceOption_Spake2pSaltBase64 },
{ "spake2p-iterations", kArgumentRequired, kDeviceOption_Spake2pIterations },
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
{ "secured-device-port", kArgumentRequired, kDeviceOption_SecuredDevicePort },
{ "unsecured-commissioner-port", kArgumentRequired, kDeviceOption_UnsecuredCommissionerPort },
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
{ "secured-commissioner-port", kArgumentRequired, kDeviceOption_SecuredCommissionerPort },
{ "commissioner-fabric-id", kArgumentRequired, kCommissionerOption_FabricID },
#endif
{ "command", kArgumentRequired, kDeviceOption_Command },
{ "PICS", kArgumentRequired, kDeviceOption_PICS },
{ "KVS", kArgumentRequired, kDeviceOption_KVS },
{ "interface-id", kArgumentRequired, kDeviceOption_InterfaceId },
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
{ "trace_file", kArgumentRequired, kDeviceOption_TraceFile },
{ "trace_log", kArgumentRequired, kDeviceOption_TraceLog },
{ "trace_decode", kArgumentRequired, kDeviceOption_TraceDecode },
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
{ "commissioning-arl-entries", kArgumentRequired, kDeviceOption_CommissioningArlEntries },
{ "arl-entries", kArgumentRequired, kDeviceOption_ArlEntries },
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
{ "cert_error_csr_incorrect_type", kNoArgument, kOptionCSRResponseCSRIncorrectType },
{ "cert_error_csr_existing_keypair", kNoArgument, kOptionCSRResponseCSRExistingKeyPair },
{ "cert_error_csr_nonce_incorrect_type", kNoArgument, kOptionCSRResponseCSRNonceIncorrectType },
{ "cert_error_csr_nonce_too_long", kNoArgument, kOptionCSRResponseCSRNonceTooLong },
{ "cert_error_csr_nonce_invalid", kNoArgument, kOptionCSRResponseCSRNonceInvalid },
{ "cert_error_nocsrelements_too_long", kNoArgument, kOptionCSRResponseNOCSRElementsTooLong },
{ "cert_error_attestation_signature_incorrect_type", kNoArgument, kOptionCSRResponseAttestationSignatureIncorrectType },
{ "cert_error_attestation_signature_invalid", kNoArgument, kOptionCSRResponseAttestationSignatureInvalid },
{ "enable-key", kArgumentRequired, kDeviceOption_TestEventTriggerEnableKey },
#if ENABLE_TRACING
{ "trace-to", kArgumentRequired, kTraceTo },
#endif
{ "simulate-no-internal-time", kNoArgument, kOptionSimulateNoInternalTime },
#if defined(PW_RPC_ENABLED)
{ "rpc-server-port", kArgumentRequired, kOptionRpcServerPort },
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
{ "subscription-capacity", kArgumentRequired, kDeviceOption_SubscriptionCapacity },
{ "subscription-resumption-retry-interval", kArgumentRequired, kDeviceOption_SubscriptionResumptionRetryIntervalSec },
{ "idle-retransmit-timeout", kArgumentRequired, kDeviceOption_IdleRetransmitTimeout },
{ "active-retransmit-timeout", kArgumentRequired, kDeviceOption_ActiveRetransmitTimeout },
{ "active-threshold-time", kArgumentRequired, kDeviceOption_ActiveThresholdTime },
#endif
#if CHIP_WITH_NLFAULTINJECTION
{ "faults", kArgumentRequired, kDeviceOption_FaultInjection },
#endif
{}
};
const char * sDeviceOptionHelp =
#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
" --ble-device <number>\n"
" The device number for CHIPoBLE, without 'hci' prefix, can be found by hciconfig.\n"
#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
"\n"
" --wifi\n"
" Enable Wi-Fi management via wpa_supplicant.\n"
#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
"\n"
" --wifi-supports-5g\n"
" Indicate that local Wi-Fi hardware should report 5GHz support.\n"
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
"\n"
" --wifipaf freq_list=<freq_1>,<freq_2>... \n"
" Enable Wi-Fi PAF via wpa_supplicant.\n"
" Give an empty string if not setting freq_list: \"\"\n"
#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFIPAFs
#if CHIP_ENABLE_OPENTHREAD
"\n"
" --thread\n"
" Enable Thread management via ot-agent.\n"
#endif // CHIP_ENABLE_OPENTHREAD
"\n"
" --version <version>\n"
" The version indication provides versioning of the setup payload.\n"
"\n"
" --vendor-id <id>\n"
" The Vendor ID is assigned by the Connectivity Standards Alliance.\n"
"\n"
" --product-id <id>\n"
" The Product ID is specified by vendor.\n"
"\n"
" --custom-flow <Standard = 0 | UserActionRequired = 1 | Custom = 2>\n"
" A 2-bit unsigned enumeration specifying manufacturer-specific custom flow options.\n"
"\n"
" --capabilities <None = 0, SoftAP = 1 << 0, BLE = 1 << 1, OnNetwork = 1 << 2>\n"
" Discovery Capabilities Bitmask which contains information about Device’s available technologies for device discovery.\n"
"\n"
" --discriminator <discriminator>\n"
" A 12-bit unsigned integer match the value which a device advertises during commissioning.\n"
"\n"
" --passcode <passcode>\n"
" A 27-bit unsigned integer, which serves as proof of possession during commissioning. \n"
" If not provided to compute a verifier, the --spake2p-verifier-base64 must be provided. \n"
"\n"
" --spake2p-verifier-base64 <PASE verifier as base64>\n"
" A raw concatenation of 'W0' and 'L' (67 bytes) as base64 to override the verifier\n"
" auto-computed from the passcode, if provided.\n"
"\n"
" --spake2p-salt-base64 <PASE salt as base64>\n"
" 16-32 bytes of salt to use for the PASE verifier, as base64. If omitted, will be generated\n"
" randomly. If a --spake2p-verifier-base64 is passed, it must match against the salt otherwise\n"
" failure will arise.\n"
"\n"
" --spake2p-iterations <PASE PBKDF iterations>\n"
" Number of PBKDF iterations to use. If omitted, will be 1000. If a --spake2p-verifier-base64 is\n"
" passed, the iteration counts must match that used to generate the verifier otherwise failure will\n"
" arise.\n"
"\n"
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
" --secured-device-port <port>\n"
" A 16-bit unsigned integer specifying the listen port to use for secure device messages (default is 5540).\n"
"\n"
" --unsecured-commissioner-port <port>\n"
" A 16-bit unsigned integer specifying the port to use for unsecured commissioner messages (default is 5550).\n"
"\n"
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
" --secured-commissioner-port <port>\n"
" A 16-bit unsigned integer specifying the listen port to use for secure commissioner messages (default is 5552). Only "
"valid when app is both device and commissioner\n"
"\n"
" --commissioner-fabric-id <fabricid>\n"
" The fabric ID to be used when this device is a commissioner (default in code is 1).\n"
"\n"
#endif
" --command <command-name>\n"
" A name for a command to execute during startup.\n"
"\n"
" --PICS <filepath>\n"
" A file containing PICS items.\n"
"\n"
" --KVS <filepath>\n"
" A file to store Key Value Store items.\n"
"\n"
" --interface-id <interface>\n"
" A interface id to advertise on.\n"
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
"\n"
" --trace_file <file>\n"
" Output trace data to the provided file.\n"
" --trace_log <1/0>\n"
" A value of 1 enables traces to go to the log, 0 disables this (default 0).\n"
" --trace_decode <1/0>\n"
" A value of 1 enables traces decoding, 0 disables this (default 0).\n"
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
" --commissioning-arl-entries <CommissioningARL JSON>\n"
" Enable ACL cluster access restrictions used during commissioning with the provided JSON. Example:\n"
" \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n"
" --arl-entries <ARL JSON>\n"
" Enable ACL cluster access restrictions applied to fabric index 1 with the provided JSON. Example:\n"
" \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n"
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
" --cert_error_csr_incorrect_type\n"
" Configure the CSRResponse to be built with an invalid CSR type.\n"
" --cert_error_csr_existing_keypair\n"
" Configure the CSRResponse to be built with a CSR where the keypair already exists.\n"
" --cert_error_csr_nonce_incorrect_type\n"
" Configure the CSRResponse to be built with an invalid CSRNonce type.\n"
" --cert_error_csr_nonce_too_long\n"
" Configure the CSRResponse to be built with a CSRNonce that is longer than expected.\n"
" --cert_error_csr_nonce_invalid\n"
" Configure the CSRResponse to be built with a CSRNonce that does not match the CSRNonce from the CSRRequest.\n"
" --cert_error_nocsrelements_too_long\n"
" Configure the CSRResponse to contains an NOCSRElements larger than the allowed RESP_MAX.\n"
" --cert_error_attestation_signature_incorrect_type\n"
" Configure the CSRResponse to be build with an invalid AttestationSignature type.\n"
" --cert_error_attestation_signature_invalid\n"
" Configure the CSRResponse to be build with an AttestationSignature that does not match what is expected.\n"
" --enable-key <key>\n"
" A 16-byte, hex-encoded key, used to validate TestEventTrigger command of Generial Diagnostics cluster\n"
#if ENABLE_TRACING
" --trace-to <destination>\n"
" Trace destinations, comma separated (" SUPPORTED_COMMAND_LINE_TRACING_TARGETS ")\n"
#endif
" --simulate-no-internal-time\n"
" Time cluster does not use internal platform time\n"
#if defined(PW_RPC_ENABLED)
" --rpc-server-port\n"
" Start RPC server on specified port\n"
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
" --subscription-capacity\n"
" Max number of subscriptions the device will allow\n"
" --subscription-resumption-retry-interval\n"
" subscription timeout resumption retry interval in seconds\n"
" --idle-retransmit-timeout <timeout>\n"
" Sets the MRP idle retry interval (in milliseconds).\n"
" This interval is used by the peer to calculate the retransmission timeout when the current device is considered idle.\n"
"\n"
" --active-retransmit-timeout <timeout>\n"
" Sets the MRP active retry interval (in milliseconds).\n"
" This interval is used by the peer to calculate the retransmission timeout when the current device is considered "
"active.\n"
"\n"
" --active-threshold-time <time>\n"
" Sets the MRP active threshold (in milliseconds).\n"
" Specifies the time after which the device transitions from active to idle.\n"
"\n"
#endif
#if CHIP_WITH_NLFAULTINJECTION
" --faults <fault-string,...>\n"
" Inject specified fault(s) at runtime.\n"
#endif
"\n";
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
bool ParseAccessRestrictionEntriesFromJson(const char * jsonString, std::vector<AccessRestrictionProvider::Entry> & entries)
{
Json::Value root;
Json::Reader reader;
VerifyOrReturnValue(reader.parse(jsonString, root), false);
for (Json::Value::const_iterator eIt = root.begin(); eIt != root.end(); eIt++)
{
AccessRestrictionProvider::Entry entry;
entry.endpointNumber = static_cast<EndpointId>((*eIt)["endpoint"].asUInt());
entry.clusterId = static_cast<ClusterId>((*eIt)["cluster"].asUInt());
Json::Value restrictions = (*eIt)["restrictions"];
for (Json::Value::const_iterator rIt = restrictions.begin(); rIt != restrictions.end(); rIt++)
{
AccessRestrictionProvider::Restriction restriction;
restriction.restrictionType = static_cast<AccessRestrictionProvider::Type>((*rIt)["type"].asUInt());
if ((*rIt).isMember("id"))
{
restriction.id.SetValue((*rIt)["id"].asUInt());
}
entry.restrictions.push_back(restriction);
}
entries.push_back(entry);
}
return true;
}
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
bool Base64ArgToVector(const char * arg, size_t maxSize, std::vector<uint8_t> & outVector)
{
size_t maxBase64Size = BASE64_ENCODED_LEN(maxSize);
outVector.resize(maxSize);
size_t argLen = strlen(arg);
VerifyOrReturnValue(argLen <= maxBase64Size, false);
VerifyOrReturnValue(chip::CanCastTo<uint32_t>(argLen), false);
size_t decodedLen = chip::Base64Decode32(arg, static_cast<uint32_t>(argLen), reinterpret_cast<uint8_t *>(outVector.data()));
VerifyOrReturnValue(decodedLen != 0, false);
outVector.resize(decodedLen);
return true;
}
bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
{
bool retval = true;
switch (aIdentifier)
{
case kDeviceOption_BleDevice:
if (!ParseInt(aValue, LinuxDeviceOptions::GetInstance().mBleDevice))
{
PrintArgError("%s: invalid value specified for ble device number: %s\n", aProgram, aValue);
retval = false;
}
break;
case kDeviceOption_WiFi:
LinuxDeviceOptions::GetInstance().mWiFi = true;
break;
case kDeviceOption_WiFiSupports5g:
LinuxDeviceOptions::GetInstance().wifiSupports5g = true;
break;
case kDeviceOption_Thread:
LinuxDeviceOptions::GetInstance().mThread = true;
break;
case kDeviceOption_Version:
LinuxDeviceOptions::GetInstance().payload.version = static_cast<uint8_t>(strtoul(aValue, nullptr, 0));
break;
case kDeviceOption_VendorID:
LinuxDeviceOptions::GetInstance().payload.vendorID = static_cast<uint16_t>(strtoul(aValue, nullptr, 0));
break;
case kDeviceOption_ProductID:
LinuxDeviceOptions::GetInstance().payload.productID = static_cast<uint16_t>(strtoul(aValue, nullptr, 0));
break;
case kDeviceOption_CustomFlow:
LinuxDeviceOptions::GetInstance().payload.commissioningFlow = static_cast<CommissioningFlow>(strtoul(aValue, nullptr, 0));
break;
case kDeviceOption_Capabilities:
LinuxDeviceOptions::GetInstance().payload.rendezvousInformation.Emplace().SetRaw(
static_cast<uint8_t>(strtoul(aValue, nullptr, 0)));
break;
case kDeviceOption_Discriminator: {
uint16_t value = static_cast<uint16_t>(strtoul(aValue, nullptr, 0));
if (value >= 4096)
{
PrintArgError("%s: invalid value specified for discriminator: %s\n", aProgram, aValue);
retval = false;
}
else
{
LinuxDeviceOptions::GetInstance().discriminator.SetValue(value);
}
break;
}
case kDeviceOption_Passcode:
LinuxDeviceOptions::GetInstance().payload.setUpPINCode = static_cast<uint32_t>(strtoul(aValue, nullptr, 0));
break;
case kDeviceOption_Spake2pSaltBase64: {
constexpr size_t kMaxSize = chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length;
std::vector<uint8_t> saltVector;
bool success = Base64ArgToVector(aValue, kMaxSize, saltVector);
if (!success)
{
PrintArgError("%s: ERROR: Base64 format for argument %s was invalid\n", aProgram, aName);
retval = false;
break;
}
if ((saltVector.size() < chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length) ||
(saltVector.size() > chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length))
{
PrintArgError("%s: ERROR: argument %s not in range [%u, %u]\n", aProgram, aName,
chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length, chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
retval = false;
break;
}
LinuxDeviceOptions::GetInstance().spake2pSalt.SetValue(std::move(saltVector));
break;
}
case kDeviceOption_Spake2pVerifierBase64: {
constexpr size_t kMaxSize = chip::Crypto::kSpake2p_VerifierSerialized_Length;
std::vector<uint8_t> serializedVerifier;
bool success = Base64ArgToVector(aValue, kMaxSize, serializedVerifier);
if (!success)
{
PrintArgError("%s: ERROR: Base64 format for argument %s was invalid\n", aProgram, aName);
retval = false;
break;
}
if (serializedVerifier.size() != chip::Crypto::kSpake2p_VerifierSerialized_Length)
{
PrintArgError("%s: ERROR: argument %s should contain base64 for a %u bytes octet string \n", aProgram, aName,
chip::Crypto::kSpake2p_VerifierSerialized_Length);
retval = false;
break;
}
LinuxDeviceOptions::GetInstance().spake2pVerifier.SetValue(std::move(serializedVerifier));
break;
}
case kDeviceOption_Spake2pIterations: {
errno = 0;
uint32_t iterCount = static_cast<uint32_t>(strtoul(aValue, nullptr, 0));
if (errno == ERANGE)
{
PrintArgError("%s: ERROR: argument %s was not parsable as an integer\n", aProgram, aName);
retval = false;
break;
}
if ((iterCount < chip::Crypto::kSpake2p_Min_PBKDF_Iterations) || (iterCount > chip::Crypto::kSpake2p_Max_PBKDF_Iterations))
{
PrintArgError("%s: ERROR: argument %s not in range [%u, %u]\n", aProgram, aName,
chip::Crypto::kSpake2p_Min_PBKDF_Iterations, chip::Crypto::kSpake2p_Max_PBKDF_Iterations);
retval = false;
break;
}
LinuxDeviceOptions::GetInstance().spake2pIterations = iterCount;
break;
}
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
case kDeviceOption_SecuredDevicePort:
LinuxDeviceOptions::GetInstance().securedDevicePort = static_cast<uint16_t>(atoi(aValue));
break;
case kDeviceOption_UnsecuredCommissionerPort:
LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort = static_cast<uint16_t>(atoi(aValue));
break;
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
case kDeviceOption_SecuredCommissionerPort:
LinuxDeviceOptions::GetInstance().securedCommissionerPort = static_cast<uint16_t>(atoi(aValue));
break;
case kCommissionerOption_FabricID:
LinuxDeviceOptions::GetInstance().commissionerFabricId = static_cast<chip::FabricId>(strtoull(aValue, nullptr, 0));
break;
#endif
case kDeviceOption_Command:
LinuxDeviceOptions::GetInstance().command = aValue;
break;
case kDeviceOption_PICS:
LinuxDeviceOptions::GetInstance().PICS = aValue;
break;
case kDeviceOption_KVS:
LinuxDeviceOptions::GetInstance().KVS = aValue;
break;
case kDeviceOption_InterfaceId:
LinuxDeviceOptions::GetInstance().interfaceId =
Inet::InterfaceId(static_cast<chip::Inet::InterfaceId::PlatformType>(atoi(aValue)));
break;
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
case kDeviceOption_TraceFile:
LinuxDeviceOptions::GetInstance().traceStreamFilename.SetValue(std::string{ aValue });
break;
case kDeviceOption_TraceLog:
if (atoi(aValue) != 0)
{
LinuxDeviceOptions::GetInstance().traceStreamToLogEnabled = true;
}
break;
case kDeviceOption_TraceDecode:
if (atoi(aValue) != 0)
{
LinuxDeviceOptions::GetInstance().traceStreamDecodeEnabled = true;
}
break;
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
// TODO(#35189): change to use a path to JSON files instead
case kDeviceOption_CommissioningArlEntries: {
std::vector<AccessRestrictionProvider::Entry> entries;
retval = ParseAccessRestrictionEntriesFromJson(aValue, entries);
if (retval)
{
LinuxDeviceOptions::GetInstance().commissioningArlEntries.SetValue(std::move(entries));
}
}
break;
case kDeviceOption_ArlEntries: {
std::vector<AccessRestrictionProvider::Entry> entries;
retval = ParseAccessRestrictionEntriesFromJson(aValue, entries);
if (retval)
{
LinuxDeviceOptions::GetInstance().arlEntries.SetValue(std::move(entries));
}
}
break;
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
case kOptionCSRResponseCSRIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrIncorrectType = true;
break;
case kOptionCSRResponseCSRExistingKeyPair:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrExistingKeyPair = true;
break;
case kOptionCSRResponseCSRNonceIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceIncorrectType = true;
break;
case kOptionCSRResponseCSRNonceTooLong:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceTooLong = true;
break;
case kOptionCSRResponseCSRNonceInvalid:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrNonceInvalid = true;
break;
case kOptionCSRResponseNOCSRElementsTooLong:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.nocsrElementsTooLong = true;
break;
case kOptionCSRResponseAttestationSignatureIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureIncorrectType = true;
break;
case kOptionCSRResponseAttestationSignatureInvalid:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.attestationSignatureInvalid = true;
break;
case kDeviceOption_TestEventTriggerEnableKey: {
constexpr size_t kEnableKeyLength = sizeof(LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey);
if (Encoding::HexToBytes(aValue, strlen(aValue), LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey,
kEnableKeyLength) != kEnableKeyLength)
{
PrintArgError("%s: ERROR: invalid value specified for %s\n", aProgram, aName);
retval = false;
}
break;
}
#if ENABLE_TRACING
case kTraceTo:
LinuxDeviceOptions::GetInstance().traceTo.push_back(aValue);
break;
#endif
case kOptionSimulateNoInternalTime:
LinuxDeviceOptions::GetInstance().mSimulateNoInternalTime = true;
break;
#if defined(PW_RPC_ENABLED)
case kOptionRpcServerPort:
LinuxDeviceOptions::GetInstance().rpcServerPort = static_cast<uint16_t>(atoi(aValue));
break;
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
case kDeviceOption_SubscriptionCapacity:
LinuxDeviceOptions::GetInstance().subscriptionCapacity = static_cast<int32_t>(atoi(aValue));
break;
case kDeviceOption_SubscriptionResumptionRetryIntervalSec:
LinuxDeviceOptions::GetInstance().subscriptionResumptionRetryIntervalSec = static_cast<int32_t>(atoi(aValue));
break;
case kDeviceOption_IdleRetransmitTimeout: {
auto mrpConfig = GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig());
auto idleRetransTimeout = System::Clock::Milliseconds32(static_cast<uint32_t>(strtoul(aValue, nullptr, 0)));
auto activeRetransTimeout = mrpConfig.mActiveRetransTimeout;
auto activeThresholdTime = mrpConfig.mActiveThresholdTime;
OverrideLocalMRPConfig(idleRetransTimeout, activeRetransTimeout, activeThresholdTime);
break;
}
case kDeviceOption_ActiveRetransmitTimeout: {
auto mrpConfig = GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig());
auto idleRetransTimeout = mrpConfig.mIdleRetransTimeout;
auto activeRetransTimeout = System::Clock::Milliseconds32(static_cast<uint32_t>(strtoul(aValue, nullptr, 0)));
auto activeThresholdTime = mrpConfig.mActiveThresholdTime;
OverrideLocalMRPConfig(idleRetransTimeout, activeRetransTimeout, activeThresholdTime);
break;
}
case kDeviceOption_ActiveThresholdTime: {
auto mrpConfig = GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig());
auto idleRetransTimeout = mrpConfig.mIdleRetransTimeout;
auto activeRetransTimeout = mrpConfig.mActiveRetransTimeout;
auto activeThresholdTime = System::Clock::Milliseconds16(static_cast<uint16_t>(strtoul(aValue, nullptr, 0)));
OverrideLocalMRPConfig(idleRetransTimeout, activeRetransTimeout, activeThresholdTime);
break;
}
#endif
#if CHIP_WITH_NLFAULTINJECTION
case kDeviceOption_FaultInjection: {
constexpr nl::FaultInjection::GetManagerFn faultManagerFns[] = { FaultInjection::GetManager,
Inet::FaultInjection::GetManager,
System::FaultInjection::GetManager };
Platform::ScopedMemoryString mutableArg(aValue, strlen(aValue)); // ParseFaultInjectionStr may mutate
if (!nl::FaultInjection::ParseFaultInjectionStr(mutableArg.Get(), faultManagerFns, ArraySize(faultManagerFns)))
{
PrintArgError("%s: Invalid fault injection specification\n", aProgram);
retval = false;
}
break;
}
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
case kDeviceOption_WiFi_PAF: {
LinuxDeviceOptions::GetInstance().mWiFiPAF = true;
LinuxDeviceOptions::GetInstance().mWiFiPAFExtCmds = aValue;
break;
}
#endif
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
retval = false;
break;
}
return (retval);
}
OptionSet sDeviceOptions = { HandleOption, sDeviceOptionDefs, "GENERAL OPTIONS", sDeviceOptionHelp };
OptionSet * sLinuxDeviceOptionSets[] = { &sDeviceOptions, nullptr, nullptr, nullptr };
} // namespace
CHIP_ERROR ParseArguments(int argc, char * const argv[], OptionSet * customOptions)
{
// Index 0 is for the general Linux options
uint8_t optionSetIndex = 1;
if (customOptions != nullptr)
{
// If there are custom options, include it during arg parsing
sLinuxDeviceOptionSets[optionSetIndex++] = customOptions;
}
char usage[kAppUsageLength];
snprintf(usage, kAppUsageLength, "Usage: %s [options]", argv[0]);
HelpOptions helpOptions(argv[0], usage, "1.0");
sLinuxDeviceOptionSets[optionSetIndex] = &helpOptions;
if (!ParseArgs(argv[0], argc, argv, sLinuxDeviceOptionSets))
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
return CHIP_NO_ERROR;
}
LinuxDeviceOptions & LinuxDeviceOptions::GetInstance()
{
if (gDeviceOptions.dacProvider == nullptr)
{
gDeviceOptions.dacProvider = chip::Credentials::Examples::GetExampleDACProvider();
}
return gDeviceOptions;
}