Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 Project CHIP Authors
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 : #pragma once
19 :
20 : #include <app/data-model/Nullable.h>
21 : #include <app/server/AppDelegate.h>
22 : #include <app/server/CommissioningModeProvider.h>
23 : #include <crypto/CHIPCryptoPAL.h>
24 : #include <lib/core/CHIPVendorIdentifiers.hpp>
25 : #include <lib/core/ClusterEnums.h>
26 : #include <lib/core/DataModelTypes.h>
27 : #include <lib/dnssd/Advertiser.h>
28 : #include <messaging/ExchangeDelegate.h>
29 : #include <platform/CHIPDeviceConfig.h>
30 : #include <protocols/secure_channel/PASESession.h>
31 : #include <system/SystemClock.h>
32 :
33 : namespace chip {
34 :
35 : enum class CommissioningWindowAdvertisement
36 : {
37 : kAllSupported,
38 : kDnssdOnly,
39 : };
40 :
41 : class Server;
42 :
43 : class CommissioningWindowManager : public Messaging::UnsolicitedMessageHandler,
44 : public SessionEstablishmentDelegate,
45 : public app::CommissioningModeProvider,
46 : public SessionDelegate
47 : {
48 : public:
49 133 : CommissioningWindowManager() : mPASESession(*this) {}
50 :
51 1 : CHIP_ERROR Init(Server * server)
52 : {
53 1 : if (server == nullptr)
54 : {
55 0 : return CHIP_ERROR_INVALID_ARGUMENT;
56 : }
57 1 : mServer = server;
58 1 : return CHIP_NO_ERROR;
59 : }
60 :
61 : System::Clock::Seconds32 MaxCommissioningTimeout() const;
62 :
63 10 : System::Clock::Seconds32 MinCommissioningTimeout() const
64 : {
65 : // Specification section 5.4.2.3. Announcement Duration says 3 minutes.
66 10 : return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds32(3 * 60));
67 : }
68 :
69 5 : void SetAppDelegate(AppDelegate * delegate) { mAppDelegate = delegate; }
70 :
71 : /**
72 : * Open the pairing window using default configured parameters.
73 : */
74 : CHIP_ERROR
75 : OpenBasicCommissioningWindow(
76 : System::Clock::Seconds32 commissioningTimeout = System::Clock::Seconds32(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS),
77 : CommissioningWindowAdvertisement advertisementMode = chip::CommissioningWindowAdvertisement::kAllSupported);
78 :
79 : /**
80 : * Open the pairing window using default configured parameters, triggered by
81 : * the Administrator Commmissioning cluster implementation.
82 : */
83 : CHIP_ERROR
84 : OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds32 commissioningTimeout,
85 : FabricIndex fabricIndex, VendorId vendorId);
86 :
87 : CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds32 commissioningTimeout, uint16_t discriminator,
88 : Crypto::Spake2pVerifier & verifier, uint32_t iterations, chip::ByteSpan salt,
89 : FabricIndex fabricIndex, VendorId vendorId);
90 :
91 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
92 : CHIP_ERROR OpenJointCommissioningWindow(System::Clock::Seconds32 commissioningTimeout, uint16_t discriminator,
93 : Crypto::Spake2pVerifier & verifier, uint32_t iterations, ByteSpan salt,
94 : FabricIndex fabricIndex, VendorId vendorId);
95 :
96 : // Tracks whether joint commissioning mode is ongoing
97 : bool IsJCM() const;
98 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
99 :
100 : void CloseCommissioningWindow();
101 :
102 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum CommissioningWindowStatusForCluster() const;
103 :
104 : bool IsCommissioningWindowOpen() const;
105 :
106 7 : const app::DataModel::Nullable<VendorId> & GetOpenerVendorId() const { return mOpenerVendorId; }
107 :
108 7 : const app::DataModel::Nullable<FabricIndex> & GetOpenerFabricIndex() const { return mOpenerFabricIndex; }
109 :
110 : void OnFabricRemoved(FabricIndex removedIndex);
111 :
112 : // CommissioningModeProvider implementation.
113 : Dnssd::CommissioningMode GetCommissioningMode() const override;
114 :
115 : //// UnsolicitedMessageHandler Implementation ////
116 : CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader,
117 : Messaging::ExchangeDelegate *& newDelegate) override;
118 : void OnExchangeCreationFailed(Messaging::ExchangeDelegate * delegate) override;
119 :
120 : //////////// SessionEstablishmentDelegate Implementation ///////////////
121 : void OnSessionEstablishmentError(CHIP_ERROR error) override;
122 : void OnSessionEstablishmentStarted() override;
123 : void OnSessionEstablished(const SessionHandle & session) override;
124 :
125 : void Shutdown();
126 :
127 : void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event);
128 :
129 : // For tests only, allow overriding the spec-defined minimum value of the
130 : // commissioning window timeout.
131 2 : void OverrideMinCommissioningTimeout(System::Clock::Seconds32 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); }
132 :
133 9 : Optional<SessionHandle> GetPASESession() const { return mPASESession.Get(); }
134 :
135 : /**
136 : * Expire the fail-safe if there is an active PASE session, since this indicates that the fail-safe is for the commissioning
137 : * happening over the PASE session, and not for some unrelated non-commissioning activity.
138 : */
139 : void ExpireFailSafeIfHeldByOpenPASESession();
140 :
141 : private:
142 : //////////// SessionDelegate Implementation ///////////////
143 : void OnSessionReleased() override;
144 :
145 8 : void SetBLE(bool ble) { mIsBLE = ble; }
146 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
147 5 : void SetWiFiPAF(bool paf) { mIsWiFiPAF = paf; }
148 : #endif
149 :
150 : CHIP_ERROR SetTemporaryDiscriminator(uint16_t discriminator);
151 :
152 : CHIP_ERROR RestoreDiscriminator();
153 :
154 : CHIP_ERROR StartAdvertisement();
155 :
156 : CHIP_ERROR StopAdvertisement(bool aShuttingDown);
157 :
158 : // Start a timer that will call HandleCommissioningWindowTimeout, and then
159 : // start advertising and listen for PASE.
160 : CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds32 commissioningTimeout);
161 :
162 : // Start advertising and listening for PASE connections. Should only be
163 : // called when a commissioning window timeout timer is running.
164 : CHIP_ERROR AdvertiseAndListenForPASE();
165 :
166 : // Call AdvertiseAndListenForPASE, only if max attempts have not been reached.
167 : // Cleans up and calls app server delegate on failure.
168 : // err gives the current error we're attemping to recover from
169 : void HandleFailedAttempt(CHIP_ERROR err);
170 :
171 : // Helper for Shutdown and Cleanup. Does not do anything with
172 : // advertisements, because Shutdown and Cleanup want to handle those
173 : // differently.
174 : void ResetState();
175 :
176 : void Cleanup();
177 :
178 : /**
179 : * Function that gets called when our commissioning window timeout timer
180 : * fires.
181 : *
182 : * This timer is started when a commissioning window is initially opened via
183 : * OpenEnhancedCommissioningWindow or OpenBasicCommissioningWindow.
184 : *
185 : * The timer is canceled when a PASE connection is established, because it
186 : * should not affect the actual commissioning process, and after a PASE
187 : * connection is established we will not re-enter commissioning mode without
188 : * a new call to OpenEnhancedCommissioningWindow or
189 : * OpenBasicCommissioningWindow.
190 : */
191 : static void HandleCommissioningWindowTimeout(chip::System::Layer * aSystemLayer, void * aAppState);
192 :
193 : /**
194 : * Helper to immediately expire the fail-safe if it's currently armed.
195 : */
196 : void ExpireFailSafeIfArmed();
197 :
198 : /**
199 : * Helpers to ensure the right attribute reporting happens when our state is
200 : * updated.
201 : */
202 : void UpdateWindowStatus(app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum aNewStatus);
203 : void UpdateOpenerVendorId(app::DataModel::Nullable<VendorId> aNewOpenerVendorId);
204 : void UpdateOpenerFabricIndex(app::DataModel::Nullable<FabricIndex> aNewOpenerFabricIndex);
205 :
206 : AppDelegate * mAppDelegate = nullptr;
207 : Server * mServer = nullptr;
208 :
209 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum mWindowStatus =
210 : app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen;
211 :
212 : bool mIsBLE = true;
213 :
214 : #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
215 : bool mIsWiFiPAF = false;
216 : // Both 0 and kUndefinedWiFiPafSessionId are invalid publish-id.
217 : // Use 0 as the default value so that the PAF definition does not need to be included.
218 : uint32_t mPublishId = 0;
219 : #endif
220 :
221 : #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
222 : // Boolean that tracks whether we are currently in a Joint Commissioning Mode.
223 : bool mJCM = false;
224 : #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC
225 :
226 : PASESession mPairingSession;
227 :
228 : uint8_t mFailedCommissioningAttempts = 0;
229 :
230 : bool mUseECM = false;
231 : Crypto::Spake2pVerifier mECMPASEVerifier;
232 : uint16_t mECMDiscriminator = 0;
233 : // mListeningForPASE is true only when we are listening for
234 : // PBKDFParamRequest messages or when we're in the middle of a PASE
235 : // handshake.
236 : bool mListeningForPASE = false;
237 : // Boolean that tracks whether we have a live commissioning timeout timer.
238 : bool mCommissioningTimeoutTimerArmed = false;
239 : uint32_t mECMIterations = 0;
240 : uint32_t mECMSaltLength = 0;
241 : uint8_t mECMSalt[Crypto::kSpake2p_Max_PBKDF_Salt_Length];
242 :
243 : // For tests only, so that we can test the commissioning window timeout
244 : // without having to wait 3 minutes.
245 : Optional<System::Clock::Seconds32> mMinCommissioningTimeoutOverride;
246 :
247 : // The PASE session we are using, so we can handle CloseSession properly.
248 : SessionHolderWithDelegate mPASESession;
249 :
250 : // Information about who opened the commissioning window. These will only
251 : // be non-null if the window was opened via the operational credentials
252 : // cluster and the fabric index may be null even then if the fabric has been
253 : // removed.
254 : app::DataModel::Nullable<VendorId> mOpenerVendorId;
255 : app::DataModel::Nullable<FabricIndex> mOpenerFabricIndex;
256 : };
257 :
258 : } // namespace chip
|