PairingCommand.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright (c) 2020 Project CHIP Authors
  3. * All rights reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include "PairingCommand.h"
  19. #include "platform/PlatformManager.h"
  20. #include <commands/common/DeviceScanner.h>
  21. #include <controller/ExampleOperationalCredentialsIssuer.h>
  22. #include <crypto/CHIPCryptoPAL.h>
  23. #include <lib/core/CHIPSafeCasts.h>
  24. #include <lib/support/logging/CHIPLogging.h>
  25. #include <protocols/secure_channel/PASESession.h>
  26. #include <setup_payload/ManualSetupPayloadParser.h>
  27. #include <setup_payload/QRCodeSetupPayloadParser.h>
  28. using namespace ::chip;
  29. using namespace ::chip::Controller;
  30. CHIP_ERROR PairingCommand::RunCommand()
  31. {
  32. CurrentCommissioner().RegisterPairingDelegate(this);
  33. // Clear the CATs in OperationalCredentialsIssuer
  34. mCredIssuerCmds->SetCredentialIssuerCATValues(kUndefinedCATs);
  35. if (mCASEAuthTags.HasValue() && mCASEAuthTags.Value().size() <= kMaxSubjectCATAttributeCount)
  36. {
  37. CATValues cats = kUndefinedCATs;
  38. for (size_t index = 0; index < mCASEAuthTags.Value().size(); ++index)
  39. {
  40. cats.values[index] = mCASEAuthTags.Value()[index];
  41. }
  42. if (cats.AreValid())
  43. {
  44. mCredIssuerCmds->SetCredentialIssuerCATValues(cats);
  45. }
  46. }
  47. return RunInternal(mNodeId);
  48. }
  49. CHIP_ERROR PairingCommand::RunInternal(NodeId remoteId)
  50. {
  51. CHIP_ERROR err = CHIP_NO_ERROR;
  52. switch (mPairingMode)
  53. {
  54. case PairingMode::None:
  55. err = Unpair(remoteId);
  56. break;
  57. case PairingMode::Code:
  58. err = PairWithCode(remoteId);
  59. break;
  60. case PairingMode::CodePaseOnly:
  61. err = PaseWithCode(remoteId);
  62. break;
  63. case PairingMode::Ble:
  64. err = Pair(remoteId, PeerAddress::BLE());
  65. break;
  66. case PairingMode::OnNetwork:
  67. err = PairWithMdns(remoteId);
  68. break;
  69. case PairingMode::SoftAP:
  70. err = Pair(remoteId, PeerAddress::UDP(mRemoteAddr.address, mRemotePort, mRemoteAddr.interfaceId));
  71. break;
  72. case PairingMode::AlreadyDiscovered:
  73. err = Pair(remoteId, PeerAddress::UDP(mRemoteAddr.address, mRemotePort, mRemoteAddr.interfaceId));
  74. break;
  75. case PairingMode::AlreadyDiscoveredByIndex:
  76. err = PairWithMdnsOrBleByIndex(remoteId, mIndex);
  77. break;
  78. case PairingMode::AlreadyDiscoveredByIndexWithCode:
  79. err = PairWithMdnsOrBleByIndexWithCode(remoteId, mIndex);
  80. break;
  81. }
  82. return err;
  83. }
  84. CommissioningParameters PairingCommand::GetCommissioningParameters()
  85. {
  86. auto params = CommissioningParameters();
  87. params.SetSkipCommissioningComplete(mSkipCommissioningComplete.ValueOr(false));
  88. if (mBypassAttestationVerifier.ValueOr(false))
  89. {
  90. params.SetDeviceAttestationDelegate(this);
  91. }
  92. switch (mNetworkType)
  93. {
  94. case PairingNetworkType::WiFi:
  95. params.SetWiFiCredentials(Controller::WiFiCredentials(mSSID, mPassword));
  96. break;
  97. case PairingNetworkType::Thread:
  98. params.SetThreadOperationalDataset(mOperationalDataset);
  99. break;
  100. case PairingNetworkType::None:
  101. break;
  102. }
  103. if (mCountryCode.HasValue())
  104. {
  105. params.SetCountryCode(CharSpan::fromCharString(mCountryCode.Value()));
  106. }
  107. // mTimeZoneList is an optional argument managed by TypedComplexArgument mComplex_TimeZones.
  108. // Since optional Complex arguments are not currently supported via the <chip::Optional> class,
  109. // we will use mTimeZoneList.data() value to determine if the argument was provided.
  110. if (mTimeZoneList.data())
  111. {
  112. params.SetTimeZone(mTimeZoneList);
  113. }
  114. // miDSTOffsetList is an optional argument managed by TypedComplexArgument mComplex_DSTOffsets.
  115. // Since optional Complex arguments are not currently supported via the <chip::Optional> class,
  116. // we will use mTimeZoneList.data() value to determine if the argument was provided.
  117. if (mDSTOffsetList.data())
  118. {
  119. params.SetDSTOffsets(mDSTOffsetList);
  120. }
  121. return params;
  122. }
  123. CHIP_ERROR PairingCommand::PaseWithCode(NodeId remoteId)
  124. {
  125. auto discoveryType = DiscoveryType::kAll;
  126. if (mUseOnlyOnNetworkDiscovery.ValueOr(false))
  127. {
  128. discoveryType = DiscoveryType::kDiscoveryNetworkOnly;
  129. }
  130. if (mDiscoverOnce.ValueOr(false))
  131. {
  132. discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry;
  133. }
  134. return CurrentCommissioner().EstablishPASEConnection(remoteId, mOnboardingPayload, discoveryType);
  135. }
  136. CHIP_ERROR PairingCommand::PairWithCode(NodeId remoteId)
  137. {
  138. CommissioningParameters commissioningParams = GetCommissioningParameters();
  139. // If no network discovery behavior and no network credentials are provided, assume that the pairing command is trying to pair
  140. // with an on-network device.
  141. if (!mUseOnlyOnNetworkDiscovery.HasValue())
  142. {
  143. auto threadCredentials = commissioningParams.GetThreadOperationalDataset();
  144. auto wiFiCredentials = commissioningParams.GetWiFiCredentials();
  145. mUseOnlyOnNetworkDiscovery.SetValue(!threadCredentials.HasValue() && !wiFiCredentials.HasValue());
  146. }
  147. auto discoveryType = DiscoveryType::kAll;
  148. if (mUseOnlyOnNetworkDiscovery.ValueOr(false))
  149. {
  150. discoveryType = DiscoveryType::kDiscoveryNetworkOnly;
  151. }
  152. if (mDiscoverOnce.ValueOr(false))
  153. {
  154. discoveryType = DiscoveryType::kDiscoveryNetworkOnlyWithoutPASEAutoRetry;
  155. }
  156. return CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload, commissioningParams, discoveryType);
  157. }
  158. CHIP_ERROR PairingCommand::Pair(NodeId remoteId, PeerAddress address)
  159. {
  160. auto params = RendezvousParameters().SetSetupPINCode(mSetupPINCode).SetDiscriminator(mDiscriminator).SetPeerAddress(address);
  161. CHIP_ERROR err = CHIP_NO_ERROR;
  162. if (mPaseOnly.ValueOr(false))
  163. {
  164. err = CurrentCommissioner().EstablishPASEConnection(remoteId, params);
  165. }
  166. else
  167. {
  168. auto commissioningParams = GetCommissioningParameters();
  169. err = CurrentCommissioner().PairDevice(remoteId, params, commissioningParams);
  170. }
  171. return err;
  172. }
  173. CHIP_ERROR PairingCommand::PairWithMdnsOrBleByIndex(NodeId remoteId, uint16_t index)
  174. {
  175. #if CHIP_DEVICE_LAYER_TARGET_DARWIN
  176. VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);
  177. RendezvousParameters params;
  178. ReturnErrorOnFailure(GetDeviceScanner().Get(index, params));
  179. params.SetSetupPINCode(mSetupPINCode);
  180. CHIP_ERROR err = CHIP_NO_ERROR;
  181. if (mPaseOnly.ValueOr(false))
  182. {
  183. err = CurrentCommissioner().EstablishPASEConnection(remoteId, params);
  184. }
  185. else
  186. {
  187. auto commissioningParams = GetCommissioningParameters();
  188. err = CurrentCommissioner().PairDevice(remoteId, params, commissioningParams);
  189. }
  190. return err;
  191. #else
  192. return CHIP_ERROR_NOT_IMPLEMENTED;
  193. #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN
  194. }
  195. CHIP_ERROR PairingCommand::PairWithMdnsOrBleByIndexWithCode(NodeId remoteId, uint16_t index)
  196. {
  197. #if CHIP_DEVICE_LAYER_TARGET_DARWIN
  198. VerifyOrReturnError(IsInteractive(), CHIP_ERROR_INCORRECT_STATE);
  199. Dnssd::CommonResolutionData resolutionData;
  200. auto err = GetDeviceScanner().Get(index, resolutionData);
  201. if (CHIP_ERROR_NOT_FOUND == err)
  202. {
  203. // There is no device with this index that has some resolution data. This could simply
  204. // be because the device is a ble device. In this case let's fall back to looking for
  205. // a device with this index and some RendezvousParameters.
  206. chip::SetupPayload payload;
  207. bool isQRCode = strncmp(mOnboardingPayload, kQRCodePrefix, strlen(kQRCodePrefix)) == 0;
  208. if (isQRCode)
  209. {
  210. ReturnErrorOnFailure(QRCodeSetupPayloadParser(mOnboardingPayload).populatePayload(payload));
  211. VerifyOrReturnError(payload.isValidQRCodePayload(), CHIP_ERROR_INVALID_ARGUMENT);
  212. }
  213. else
  214. {
  215. ReturnErrorOnFailure(ManualSetupPayloadParser(mOnboardingPayload).populatePayload(payload));
  216. VerifyOrReturnError(payload.isValidManualCode(), CHIP_ERROR_INVALID_ARGUMENT);
  217. }
  218. mSetupPINCode = payload.setUpPINCode;
  219. return PairWithMdnsOrBleByIndex(remoteId, index);
  220. }
  221. err = CHIP_NO_ERROR;
  222. if (mPaseOnly.ValueOr(false))
  223. {
  224. err = CurrentCommissioner().EstablishPASEConnection(remoteId, mOnboardingPayload, DiscoveryType::kDiscoveryNetworkOnly,
  225. MakeOptional(resolutionData));
  226. }
  227. else
  228. {
  229. auto commissioningParams = GetCommissioningParameters();
  230. err = CurrentCommissioner().PairDevice(remoteId, mOnboardingPayload, commissioningParams,
  231. DiscoveryType::kDiscoveryNetworkOnly, MakeOptional(resolutionData));
  232. }
  233. return err;
  234. #else
  235. return CHIP_ERROR_NOT_IMPLEMENTED;
  236. #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN
  237. }
  238. CHIP_ERROR PairingCommand::PairWithMdns(NodeId remoteId)
  239. {
  240. Dnssd::DiscoveryFilter filter(mFilterType);
  241. switch (mFilterType)
  242. {
  243. case chip::Dnssd::DiscoveryFilterType::kNone:
  244. break;
  245. case chip::Dnssd::DiscoveryFilterType::kShortDiscriminator:
  246. case chip::Dnssd::DiscoveryFilterType::kLongDiscriminator:
  247. case chip::Dnssd::DiscoveryFilterType::kCompressedFabricId:
  248. case chip::Dnssd::DiscoveryFilterType::kVendorId:
  249. case chip::Dnssd::DiscoveryFilterType::kDeviceType:
  250. filter.code = mDiscoveryFilterCode;
  251. break;
  252. case chip::Dnssd::DiscoveryFilterType::kCommissioningMode:
  253. break;
  254. case chip::Dnssd::DiscoveryFilterType::kCommissioner:
  255. filter.code = 1;
  256. break;
  257. case chip::Dnssd::DiscoveryFilterType::kInstanceName:
  258. filter.code = 0;
  259. filter.instanceName = mDiscoveryFilterInstanceName;
  260. break;
  261. }
  262. CurrentCommissioner().RegisterDeviceDiscoveryDelegate(this);
  263. return CurrentCommissioner().DiscoverCommissionableNodes(filter);
  264. }
  265. CHIP_ERROR PairingCommand::Unpair(NodeId remoteId)
  266. {
  267. mCurrentFabricRemover = Platform::MakeUnique<Controller::CurrentFabricRemover>(&CurrentCommissioner());
  268. return mCurrentFabricRemover->RemoveCurrentFabric(remoteId, &mCurrentFabricRemoveCallback);
  269. }
  270. void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status)
  271. {
  272. switch (status)
  273. {
  274. case DevicePairingDelegate::Status::SecurePairingSuccess:
  275. ChipLogProgress(chipTool, "Secure Pairing Success");
  276. ChipLogProgress(chipTool, "CASE establishment successful");
  277. break;
  278. case DevicePairingDelegate::Status::SecurePairingFailed:
  279. ChipLogError(chipTool, "Secure Pairing Failed");
  280. SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE);
  281. break;
  282. }
  283. }
  284. void PairingCommand::OnPairingComplete(CHIP_ERROR err)
  285. {
  286. if (err == CHIP_NO_ERROR)
  287. {
  288. ChipLogProgress(chipTool, "Pairing Success");
  289. ChipLogProgress(chipTool, "PASE establishment successful");
  290. if (mPairingMode == PairingMode::CodePaseOnly || mPaseOnly.ValueOr(false))
  291. {
  292. SetCommandExitStatus(err);
  293. }
  294. }
  295. else
  296. {
  297. ChipLogProgress(chipTool, "Pairing Failure: %s", ErrorStr(err));
  298. }
  299. if (err != CHIP_NO_ERROR)
  300. {
  301. SetCommandExitStatus(err);
  302. }
  303. }
  304. void PairingCommand::OnPairingDeleted(CHIP_ERROR err)
  305. {
  306. if (err == CHIP_NO_ERROR)
  307. {
  308. ChipLogProgress(chipTool, "Pairing Deleted Success");
  309. }
  310. else
  311. {
  312. ChipLogProgress(chipTool, "Pairing Deleted Failure: %s", ErrorStr(err));
  313. }
  314. SetCommandExitStatus(err);
  315. }
  316. void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
  317. {
  318. if (err == CHIP_NO_ERROR)
  319. {
  320. ChipLogProgress(chipTool, "Device commissioning completed with success");
  321. }
  322. else
  323. {
  324. ChipLogProgress(chipTool, "Device commissioning Failure: %s", ErrorStr(err));
  325. }
  326. SetCommandExitStatus(err);
  327. }
  328. void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData & nodeData)
  329. {
  330. // Ignore nodes with closed commissioning window
  331. VerifyOrReturn(nodeData.commissionData.commissioningMode != 0);
  332. auto & resolutionData = nodeData.resolutionData;
  333. const uint16_t port = resolutionData.port;
  334. char buf[chip::Inet::IPAddress::kMaxStringLength];
  335. resolutionData.ipAddress[0].ToString(buf);
  336. ChipLogProgress(chipTool, "Discovered Device: %s:%u", buf, port);
  337. // Stop Mdns discovery.
  338. auto err = CurrentCommissioner().StopCommissionableDiscovery();
  339. // Some platforms does not implement a mechanism to stop mdns browse, so
  340. // we just ignore CHIP_ERROR_NOT_IMPLEMENTED instead of bailing out.
  341. if (CHIP_NO_ERROR != err && CHIP_ERROR_NOT_IMPLEMENTED != err)
  342. {
  343. SetCommandExitStatus(err);
  344. return;
  345. }
  346. CurrentCommissioner().RegisterDeviceDiscoveryDelegate(nullptr);
  347. auto interfaceId = resolutionData.ipAddress[0].IsIPv6LinkLocal() ? resolutionData.interfaceId : Inet::InterfaceId::Null();
  348. auto peerAddress = PeerAddress::UDP(resolutionData.ipAddress[0], port, interfaceId);
  349. err = Pair(mNodeId, peerAddress);
  350. if (CHIP_NO_ERROR != err)
  351. {
  352. SetCommandExitStatus(err);
  353. }
  354. }
  355. void PairingCommand::OnCurrentFabricRemove(void * context, NodeId nodeId, CHIP_ERROR err)
  356. {
  357. PairingCommand * command = reinterpret_cast<PairingCommand *>(context);
  358. VerifyOrReturn(command != nullptr, ChipLogError(chipTool, "OnCurrentFabricRemove: context is null"));
  359. if (err == CHIP_NO_ERROR)
  360. {
  361. ChipLogProgress(chipTool, "Device unpair completed with success: " ChipLogFormatX64, ChipLogValueX64(nodeId));
  362. }
  363. else
  364. {
  365. ChipLogProgress(chipTool, "Device unpair Failure: " ChipLogFormatX64 " %s", ChipLogValueX64(nodeId), ErrorStr(err));
  366. }
  367. command->SetCommandExitStatus(err);
  368. }
  369. chip::Optional<uint16_t> PairingCommand::FailSafeExpiryTimeoutSecs() const
  370. {
  371. // We don't need to set additional failsafe timeout as we don't ask the final user if he wants to continue
  372. return chip::Optional<uint16_t>();
  373. }
  374. void PairingCommand::OnDeviceAttestationCompleted(chip::Controller::DeviceCommissioner * deviceCommissioner,
  375. chip::DeviceProxy * device,
  376. const chip::Credentials::DeviceAttestationVerifier::AttestationDeviceInfo & info,
  377. chip::Credentials::AttestationVerificationResult attestationResult)
  378. {
  379. // Bypass attestation verification, continue with success
  380. auto err = deviceCommissioner->ContinueCommissioningAfterDeviceAttestation(
  381. device, chip::Credentials::AttestationVerificationResult::kSuccess);
  382. if (CHIP_NO_ERROR != err)
  383. {
  384. SetCommandExitStatus(err);
  385. }
  386. }