/src/connectedhomeip/src/app/server/CommissioningWindowManager.h
Line | Count | Source (jump to first uncovered line) |
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/RendezvousParameters.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 | 2 | CommissioningWindowManager() : mPASESession(*this) {} |
50 | | |
51 | | CHIP_ERROR Init(Server * server) |
52 | 1 | { |
53 | 1 | if (server == nullptr) |
54 | 0 | { |
55 | 0 | return CHIP_ERROR_INVALID_ARGUMENT; |
56 | 0 | } |
57 | 1 | mServer = server; |
58 | 1 | return CHIP_NO_ERROR; |
59 | 1 | } |
60 | | |
61 | | System::Clock::Seconds32 MaxCommissioningTimeout() const; |
62 | | |
63 | | System::Clock::Seconds32 MinCommissioningTimeout() const |
64 | 1 | { |
65 | | // Specification section 5.4.2.3. Announcement Duration says 3 minutes. |
66 | 1 | return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds32(3 * 60)); |
67 | 1 | } |
68 | | |
69 | 1 | 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 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC |
96 | | |
97 | | void CloseCommissioningWindow(); |
98 | | |
99 | | app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum CommissioningWindowStatusForCluster() const; |
100 | | |
101 | | bool IsCommissioningWindowOpen() const; |
102 | | |
103 | 0 | const app::DataModel::Nullable<VendorId> & GetOpenerVendorId() const { return mOpenerVendorId; } |
104 | | |
105 | 0 | const app::DataModel::Nullable<FabricIndex> & GetOpenerFabricIndex() const { return mOpenerFabricIndex; } |
106 | | |
107 | | void OnFabricRemoved(FabricIndex removedIndex); |
108 | | |
109 | | // CommissioningModeProvider implementation. |
110 | | Dnssd::CommissioningMode GetCommissioningMode() const override; |
111 | | |
112 | | //// UnsolicitedMessageHandler Implementation //// |
113 | | CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, |
114 | | Messaging::ExchangeDelegate *& newDelegate) override; |
115 | | void OnExchangeCreationFailed(Messaging::ExchangeDelegate * delegate) override; |
116 | | |
117 | | //////////// SessionEstablishmentDelegate Implementation /////////////// |
118 | | void OnSessionEstablishmentError(CHIP_ERROR error) override; |
119 | | void OnSessionEstablishmentStarted() override; |
120 | | void OnSessionEstablished(const SessionHandle & session) override; |
121 | | |
122 | | void Shutdown(); |
123 | | |
124 | | void OnPlatformEvent(const DeviceLayer::ChipDeviceEvent * event); |
125 | | |
126 | | // For tests only, allow overriding the spec-defined minimum value of the |
127 | | // commissioning window timeout. |
128 | 0 | void OverrideMinCommissioningTimeout(System::Clock::Seconds32 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); } |
129 | | |
130 | | private: |
131 | | //////////// SessionDelegate Implementation /////////////// |
132 | | void OnSessionReleased() override; |
133 | | |
134 | 1 | void SetBLE(bool ble) { mIsBLE = ble; } |
135 | | |
136 | | CHIP_ERROR SetTemporaryDiscriminator(uint16_t discriminator); |
137 | | |
138 | | CHIP_ERROR RestoreDiscriminator(); |
139 | | |
140 | | CHIP_ERROR StartAdvertisement(); |
141 | | |
142 | | CHIP_ERROR StopAdvertisement(bool aShuttingDown); |
143 | | |
144 | | // Start a timer that will call HandleCommissioningWindowTimeout, and then |
145 | | // start advertising and listen for PASE. |
146 | | CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds32 commissioningTimeout); |
147 | | |
148 | | // Start advertising and listening for PASE connections. Should only be |
149 | | // called when a commissioning window timeout timer is running. |
150 | | CHIP_ERROR AdvertiseAndListenForPASE(); |
151 | | |
152 | | // Call AdvertiseAndListenForPASE, only if max attempts have not been reached. |
153 | | // Cleans up and calls app server delegate on failure. |
154 | | // err gives the current error we're attemping to recover from |
155 | | void HandleFailedAttempt(CHIP_ERROR err); |
156 | | |
157 | | // Helper for Shutdown and Cleanup. Does not do anything with |
158 | | // advertisements, because Shutdown and Cleanup want to handle those |
159 | | // differently. |
160 | | void ResetState(); |
161 | | |
162 | | void Cleanup(); |
163 | | |
164 | | /** |
165 | | * Function that gets called when our commissioning window timeout timer |
166 | | * fires. |
167 | | * |
168 | | * This timer is started when a commissioning window is initially opened via |
169 | | * OpenEnhancedCommissioningWindow or OpenBasicCommissioningWindow. |
170 | | * |
171 | | * The timer is canceled when a PASE connection is established, because it |
172 | | * should not affect the actual commissioning process, and after a PASE |
173 | | * connection is established we will not re-enter commissioning mode without |
174 | | * a new call to OpenEnhancedCommissioningWindow or |
175 | | * OpenBasicCommissioningWindow. |
176 | | */ |
177 | | static void HandleCommissioningWindowTimeout(chip::System::Layer * aSystemLayer, void * aAppState); |
178 | | |
179 | | /** |
180 | | * Helper to immediately expire the fail-safe if it's currently armed. |
181 | | */ |
182 | | void ExpireFailSafeIfArmed(); |
183 | | |
184 | | /** |
185 | | * Helpers to ensure the right attribute reporting happens when our state is |
186 | | * updated. |
187 | | */ |
188 | | void UpdateWindowStatus(app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum aNewStatus); |
189 | | void UpdateOpenerVendorId(app::DataModel::Nullable<VendorId> aNewOpenerVendorId); |
190 | | void UpdateOpenerFabricIndex(app::DataModel::Nullable<FabricIndex> aNewOpenerFabricIndex); |
191 | | |
192 | | AppDelegate * mAppDelegate = nullptr; |
193 | | Server * mServer = nullptr; |
194 | | |
195 | | app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum mWindowStatus = |
196 | | app::Clusters::AdministratorCommissioning::CommissioningWindowStatusEnum::kWindowNotOpen; |
197 | | |
198 | | bool mIsBLE = true; |
199 | | |
200 | | #if CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC |
201 | | // Boolean that tracks whether we are currently in a Joint Commissioning Mode. |
202 | | bool mJCM = false; |
203 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_JOINT_FABRIC |
204 | | |
205 | | PASESession mPairingSession; |
206 | | |
207 | | uint8_t mFailedCommissioningAttempts = 0; |
208 | | |
209 | | bool mUseECM = false; |
210 | | Crypto::Spake2pVerifier mECMPASEVerifier; |
211 | | uint16_t mECMDiscriminator = 0; |
212 | | // mListeningForPASE is true only when we are listening for |
213 | | // PBKDFParamRequest messages or when we're in the middle of a PASE |
214 | | // handshake. |
215 | | bool mListeningForPASE = false; |
216 | | // Boolean that tracks whether we have a live commissioning timeout timer. |
217 | | bool mCommissioningTimeoutTimerArmed = false; |
218 | | uint32_t mECMIterations = 0; |
219 | | uint32_t mECMSaltLength = 0; |
220 | | uint8_t mECMSalt[Crypto::kSpake2p_Max_PBKDF_Salt_Length]; |
221 | | |
222 | | // For tests only, so that we can test the commissioning window timeout |
223 | | // without having to wait 3 minutes. |
224 | | Optional<System::Clock::Seconds32> mMinCommissioningTimeoutOverride; |
225 | | |
226 | | // The PASE session we are using, so we can handle CloseSession properly. |
227 | | SessionHolderWithDelegate mPASESession; |
228 | | |
229 | | // Information about who opened the commissioning window. These will only |
230 | | // be non-null if the window was opened via the operational credentials |
231 | | // cluster and the fabric index may be null even then if the fabric has been |
232 | | // removed. |
233 | | app::DataModel::Nullable<VendorId> mOpenerVendorId; |
234 | | app::DataModel::Nullable<FabricIndex> mOpenerFabricIndex; |
235 | | }; |
236 | | |
237 | | } // namespace chip |