| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /*
- * 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 "PairingCommand.h"
- #include "platform/PlatformManager.h"
- #include <commands/common/DeviceScanner.h>
- #include <controller/ExampleOperationalCredentialsIssuer.h>
- #include <crypto/CHIPCryptoPAL.h>
- #include <lib/core/CHIPSafeCasts.h>
- #include <lib/support/logging/CHIPLogging.h>
- #include <protocols/secure_channel/PASESession.h>
- #include <setup_payload/ManualSetupPayloadParser.h>
- #include <setup_payload/QRCodeSetupPayloadParser.h>
- using namespace ::chip;
- using namespace ::chip::Controller;
- CHIP_ERROR PairingCommand::RunCommand()
- {
- CurrentCommissioner().RegisterPairingDelegate(this);
- // Clear the CATs in OperationalCredentialsIssuer
- mCredIssuerCmds->SetCredentialIssuerCATValues(kUndefinedCATs);
- if (mCASEAuthTags.HasValue() && mCASEAuthTags.Value().size() <= kMaxSubjectCATAttributeCount)
- {
- CATValues cats = kUndefinedCATs;
- for (size_t index = 0; index < mCASEAuthTags.Value().size(); ++index)
- {
- cats.values[index] = mCASEAuthTags.Value()[index];
- }
- if (cats.AreValid())
- {
- mCredIssuerCmds->SetCredentialIssuerCATValues(cats);
- }
- }
- return RunInternal(mNodeId);
- }
- CHIP_ERROR PairingCommand::RunInternal(NodeId remoteId)
- {
- CHIP_ERROR err = CHIP_NO_ERROR;
- switch (mPairingMode)
- {
- case PairingMode::None:
- err = Unpair(remoteId);
- break;
- case PairingMode::Code:
- err = PairWithCode(remoteId);
- break;
- case PairingMode::CodePaseOnly:
- err = PaseWithCode(remoteId);
- break;
- case PairingMode::Ble:
- err = Pair(remoteId, PeerAddress::BLE());
- break;
- case PairingMode::OnNetwork:
- err = PairWithMdns(remoteId);
- break;
- case PairingMode::SoftAP:
- err = Pair(remoteId, PeerAddress::UDP(mRemoteAddr.address, mRemotePort, mRemoteAddr.interfaceId));
- break;
- case PairingMode::AlreadyDiscovered:
- err = Pair(remoteId, PeerAddress::UDP(mRemoteAddr.address, mRemotePort, mRemoteAddr.interfaceId));
- break;
- case PairingMode::AlreadyDiscoveredByIndex:
- err = PairWithMdnsOrBleByIndex(remoteId, mIndex);
- break;
- case PairingMode::AlreadyDiscoveredByIndexWithCode:
- err = PairWithMdnsOrBleByIndexWithCode(remoteId, mIndex);
- break;
- }
- return err;
- }
- CommissioningParameters PairingCommand::GetCommissioningParameters()
- {
- auto params = CommissioningParameters();
- params.SetSkipCommissioningComplete(mSkipCommissioningComplete.ValueOr(false));
- if (mBypassAttestationVerifier.ValueOr(false))
- {
- params.SetDeviceAttestationDelegate(this);
- }
- switch (mNetworkType)
- {
- case PairingNetworkType::WiFi:
- params.SetWiFiCredentials(Controller::WiFiCredentials(mSSID, mPassword));
- break;
- case PairingNetworkType::Thread:
- params.SetThreadOperationalDataset(mOperationalDataset);
- break;
- case PairingNetworkType::None:
- break;
- }
- if (mCountryCode.HasValue())
- {
- params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value()));
- }
- // mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones.
- // Since optional Complex arguments are not currently supported via the <chip::Optional> class,
- // we will use mTimeZoneList.data() value to determine if the argument was provided.
- if (mTimeZoneList.data())
- {
- params.SetTimeZone(mTimeZoneList);
- }
- // miDSTOffsetList is an optional argument managed by TypedComplexArgument mComplex_DSTOffsets.
- // Since optional Complex arguments are not currently supported via the <chip::Optional> class,
- // we will use mTimeZoneList.data() value to determine if the argument was provided.
- if (mDSTOffsetList.data())
- {
- params.SetDSTOffsets(mDSTOffsetList);
- }
- return params;
- }
- CHIP_ERROR PairingCommand::PaseWithCode(NodeId remoteId)
- {
- auto discoveryType = DiscoveryType::kAll;
- if (mUseOnlyOnNetworkDiscovery.ValueOr(false))
- {
- discoveryType = DiscoveryType::kDiscoveryNetworkOnly;
- }
- if (mDiscoverOnce.ValueOr(false))
- {
- discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry;
- }
- return CurrentCommissioner().EstablishPASEConnection(remoteId, mOnboardingPayload, discoveryType);
- }
- CHIP_ERROR PairingCommand::PairWithCode(NodeId remoteId)
- {
- CommissioningParameters commissioningParams = GetCommissioningParameters();
- // If no network discovery behavior and no network credentials are provided, assume that the pairing command is trying to pair
- // with an on-network device.
- if (!mUseOnlyOnNetworkDiscovery.HasValue())
- {
- auto threadCredentials = commissioningParams.GetThreadOperationalDataset();
- auto wiFiCredentials = commissioningParams.GetWiFiCredentials();
- mUseOnlyOnNetworkDiscovery.SetValue(!threadCredentials.HasValue() && !wiFiCredentials.HasValue());
- }
- auto discoveryType = DiscoveryType::kAll;
- if (mUseOnlyOnNetworkDiscovery.ValueOr(false))
- {
- discoveryType = DiscoveryType::kDiscoveryNetworkOnly;
- }
- if (mDiscoverOnce.ValueOr(false))
- {
- discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry;
- }
- return CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload, commissioningParams, discoveryType);
- }
- CHIP_ERROR PairingCommand::Pair(NodeId remoteId, PeerAddress address)
- {
- auto params = RendezvousParameters().SetSetupPINCode(mSetupPINCode).SetDiscriminator(mDiscriminator).SetPeerAddress(address);
- CHIP_ERROR err = CHIP_NO_ERROR;
- if (mPaseOnly.ValueOr(false))
- {
- err = CurrentCommissioner().EstablishPASEConnection(remoteId, params);
- }
- else
- {
- auto commissioningParams = GetCommissioningParameters();
- err = CurrentCommissioner().PairDevice(remoteId, params, commissioningParams);
- }
- return err;
- }
- CHIP_ERROR PairingCommand::PairWithMdnsOrBleByIndex(NodeId remoteId, uint16_t index)
- {
- #if CHIP_DEVICE_LAYER_TARGET_DARWIN
- VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);
- RendezvousParameters params;
- ReturnErrorOnFailure(GetDeviceScanner().Get(index, params));
- params.SetSetupPINCode(mSetupPINCode);
- CHIP_ERROR err = CHIP_NO_ERROR;
- if (mPaseOnly.ValueOr(false))
- {
- err = CurrentCommissioner().EstablishPASEConnection(remoteId, params);
- }
- else
- {
- auto commissioningParams = GetCommissioningParameters();
- err = CurrentCommissioner().PairDevice(remoteId, params, commissioningParams);
- }
- return err;
- #else
- return CHIP_ERROR_NOT_IMPLEMENTED;
- #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN
- }
- CHIP_ERROR PairingCommand::PairWithMdnsOrBleByIndexWithCode(NodeId remoteId, uint16_t index)
- {
- #if CHIP_DEVICE_LAYER_TARGET_DARWIN
- VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);
- Dnssd::CommonResolutionData resolutionData;
- auto err = GetDeviceScanner().Get(index, resolutionData);
- if (CHIP_ERROR_NOT_FOUND == err)
- {
- // There is no device with this index that has some resolution data. This could simply
- // be because the device is a ble device. In this case let's fall back to looking for
- // a device with this index and some RendezvousParameters.
- chip::SetupPayload payload;
- bool isQRCode = strncmp(mOnboardingPayload, kQRCodePrefix, strlen(kQRCodePrefix)) == 0;
- if (isQRCode)
- {
- ReturnErrorOnFailure(QRCodeSetupPayloadParser(mOnboardingPayload).populatePayload(payload));
- VerifyOrReturnError(payload.isValidQRCodePayload(), CHIP_ERROR_INVALID_ARGUMENT);
- }
- else
- {
- ReturnErrorOnFailure(ManualSetupPayloadParser(mOnboardingPayload).populatePayload(payload));
- VerifyOrReturnError(payload.isValidManualCode(), CHIP_ERROR_INVALID_ARGUMENT);
- }
- mSetupPINCode = payload.setUpPINCode;
- return PairWithMdnsOrBleByIndex(remoteId, index);
- }
- err = CHIP_NO_ERROR;
- if (mPaseOnly.ValueOr(false))
- {
- err = CurrentCommissioner().EstablishPASEConnection(remoteId, mOnboardingPayload, DiscoveryType::kDiscoveryNetworkOnly,
- MakeOptional(resolutionData));
- }
- else
- {
- auto commissioningParams = GetCommissioningParameters();
- err = CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload, commissioningParams,
- DiscoveryType::kDiscoveryNetworkOnly, MakeOptional(resolutionData));
- }
- return err;
- #else
- return CHIP_ERROR_NOT_IMPLEMENTED;
- #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN
- }
- CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId)
- {
- Dnssd::DiscoveryFilter filter(mFilterType);
- switch (mFilterType)
- {
- case chip::Dnssd::DiscoveryFilterType::kNone:
- break;
- case chip::Dnssd::DiscoveryFilterType::kShortDiscriminator:
- case chip::Dnssd::DiscoveryFilterType::kLongDiscriminator:
- case chip::Dnssd::DiscoveryFilterType::kCompressedFabricId:
- case chip::Dnssd::DiscoveryFilterType::kVendorId:
- case chip::Dnssd::DiscoveryFilterType::kDeviceType:
- filter.code = mDiscoveryFilterCode;
- break;
- case chip::Dnssd::DiscoveryFilterType::kCommissioningMode:
- break;
- case chip::Dnssd::DiscoveryFilterType::kCommissioner:
- filter.code = 1;
- break;
- case chip::Dnssd::DiscoveryFilterType::kInstanceName:
- filter.code = 0;
- filter.instanceName = mDiscoveryFilterInstanceName;
- break;
- }
- CurrentCommissioner().RegisterDeviceDiscoveryDelegate(this);
- return CurrentCommissioner().DiscoverCommissionableNodes(filter);
- }
- CHIP_ERROR PairingCommand::Unpair(NodeId remoteId)
- {
- mCurrentFabricRemover = Platform::MakeUnique<Controller::CurrentFabricRemover>(&CurrentCommissioner());
- return mCurrentFabricRemover->RemoveCurrentFabric(remoteId, &mCurrentFabricRemoveCallback);
- }
- void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status)
- {
- switch (status)
- {
- case DevicePairingDelegate::Status::SecurePairingSuccess:
- ChipLogProgress(chipTool, "Secure Pairing Success");
- ChipLogProgress(chipTool, "CASE establishment successful");
- break;
- case DevicePairingDelegate::Status::SecurePairingFailed:
- ChipLogError(chipTool, "Secure Pairing Failed");
- SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE);
- break;
- }
- }
- void PairingCommand::OnPairingComplete(CHIP_ERROR err)
- {
- if (err == CHIP_NO_ERROR)
- {
- ChipLogProgress(chipTool, "Pairing Success");
- ChipLogProgress(chipTool, "PASE establishment successful");
- if (mPairingMode == PairingMode::CodePaseOnly || mPaseOnly.ValueOr(false))
- {
- SetCommandExitStatus(err);
- }
- }
- else
- {
- ChipLogProgress(chipTool, "Pairing Failure: %s", ErrorStr(err));
- }
- if (err != CHIP_NO_ERROR)
- {
- SetCommandExitStatus(err);
- }
- }
- void PairingCommand::OnPairingDeleted(CHIP_ERROR err)
- {
- if (err == CHIP_NO_ERROR)
- {
- ChipLogProgress(chipTool, "Pairing Deleted Success");
- }
- else
- {
- ChipLogProgress(chipTool, "Pairing Deleted Failure: %s", ErrorStr(err));
- }
- SetCommandExitStatus(err);
- }
- void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
- {
- if (err == CHIP_NO_ERROR)
- {
- ChipLogProgress(chipTool, "Device commissioning completed with success");
- }
- else
- {
- ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
- }
- SetCommandExitStatus(err);
- }
- void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData)
- {
- // Ignore nodes with closed commissioning window
- VerifyOrReturn(nodeData.commissionData.commissioningMode != 0);
- auto & resolutionData = nodeData.resolutionData;
- const uint16_t port = resolutionData.port;
- char buf[chip::Inet::IPAddress::kMaxStringLength];
- resolutionData.ipAddress[0].ToString(buf);
- ChipLogProgress(chipTool, "Discovered Device: %s:%u", buf, port);
- // Stop Mdns discovery.
- auto err = CurrentCommissioner().StopCommissionableDiscovery();
- // Some platforms does not implement a mechanism to stop mdns browse, so
- // we just ignore CHIP_ERROR_NOT_IMPLEMENTED instead of bailing out.
- if (CHIP_NO_ERROR != err && CHIP_ERROR_NOT_IMPLEMENTED != err)
- {
- SetCommandExitStatus(err);
- return;
- }
- CurrentCommissioner().RegisterDeviceDiscoveryDelegate(nullptr);
- auto interfaceId = resolutionData.ipAddress[0].IsIPv6LinkLocal() ? resolutionData.interfaceId : Inet::InterfaceId::Null();
- auto peerAddress = PeerAddress::UDP(resolutionData.ipAddress[0], port, interfaceId);
- err = Pair(mNodeId, peerAddress);
- if (CHIP_NO_ERROR != err)
- {
- SetCommandExitStatus(err);
- }
- }
- void PairingCommand::OnCurrentFabricRemove(void * context, NodeId nodeId, CHIP_ERROR err)
- {
- PairingCommand * command = reinterpret_cast<PairingCommand *>(context);
- VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "OnCurrentFabricRemove: context is null"));
- if (err == CHIP_NO_ERROR)
- {
- ChipLogProgress(chipTool, "Device unpair completed with success: " ChipLogFormatX64, ChipLogValueX64(nodeId));
- }
- else
- {
- ChipLogProgress(chipTool, "Device unpair Failure: " ChipLogFormatX64 " %s", ChipLogValueX64(nodeId), ErrorStr(err));
- }
- command->SetCommandExitStatus(err);
- }
- chip::Optional<uint16_t> PairingCommand::FailSafeExpiryTimeoutSecs() const
- {
- // We don't need to set additional failsafe timeout as we don't ask the final user if he wants to continue
- return chip::Optional<uint16_t>();
- }
- void PairingCommand::OnDeviceAttestationCompleted(chip::Controller::DeviceCommissioner * deviceCommissioner,
- chip::DeviceProxy * device,
- const chip::Credentials::DeviceAttestationVerifier::AttestationDeviceInfo & info,
- chip::Credentials::AttestationVerificationResult attestationResult)
- {
- // Bypass attestation verification, continue with success
- auto err = deviceCommissioner->ContinueCommissioningAfterDeviceAttestation(
- device, chip::Credentials::AttestationVerificationResult::kSuccess);
- if (CHIP_NO_ERROR != err)
- {
- SetCommandExitStatus(err);
- }
- }
|