Line data Source code
1 : /*
2 : * Copyright (c) 2022 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 : #pragma once
19 :
20 : #include <app/OperationalSessionSetup.h>
21 : #include <app/data-model/NullObject.h>
22 : #include <controller/CHIPDeviceController.h>
23 : #include <controller/CommissioningWindowParams.h>
24 : #include <crypto/CHIPCryptoPAL.h>
25 : #include <lib/core/CHIPCallback.h>
26 : #include <lib/core/CHIPError.h>
27 : #include <lib/core/NodeId.h>
28 : #include <lib/core/Optional.h>
29 : #include <setup_payload/SetupPayload.h>
30 :
31 : namespace chip {
32 : namespace Controller {
33 :
34 : /**
35 : * A helper class to open a commissioning window given some parameters.
36 : */
37 : class CommissioningWindowOpener
38 : {
39 : public:
40 0 : CommissioningWindowOpener(DeviceController * controller) :
41 0 : mController(controller), mDeviceConnected(&OnDeviceConnectedCallback, this),
42 0 : mDeviceConnectionFailure(&OnDeviceConnectionFailureCallback, this)
43 0 : {}
44 :
45 : enum class CommissioningWindowOption : uint8_t
46 : {
47 : kOriginalSetupCode = 0,
48 : kTokenWithRandomPIN,
49 : kTokenWithProvidedPIN,
50 : };
51 :
52 : /*
53 : * @brief
54 : * Try to look up the device attached to our controller with the given
55 : * node id and ask it to re-enter commissioning mode with its original
56 : * PASE verifier, discriminator, etc. The device will exit commissioning
57 : * mode after a successful commissioning, or after the given `timeout`
58 : * time.
59 : *
60 : * @param[in] deviceId The device Id.
61 : * @param[in] timeout The commissioning mode should terminate after this much time.
62 : * @param[in] callback The callback to call once the commissioning window is
63 : * open or if an error occurs.
64 : */
65 : CHIP_ERROR OpenBasicCommissioningWindow(NodeId deviceId, System::Clock::Seconds16 timeout,
66 : Callback::Callback<OnOpenBasicCommissioningWindow> * callback);
67 :
68 : /**
69 : * @brief
70 : * Try to look up the device attached to our controller with the given
71 : * node id and ask it to re-enter commissioning mode with a PASE verifier
72 : * derived from the given information and the given discriminator. The
73 : * device will exit commissioning mode after a successful commissioning,
74 : * or after the given `timeout` time.
75 : *
76 : * @param[in] deviceId The device Id.
77 : * @param[in] timeout The commissioning mode should terminate after this much time.
78 : * @param[in] iteration The PAKE iteration count associated with the PAKE Passcode ID and ephemeral
79 : * PAKE passcode verifier to be used for this commissioning.
80 : * @param[in] discriminator The long discriminator for the DNS-SD advertisement.
81 : * @param[in] setupPIN The setup PIN to use, or NullOptional to use a randomly-generated one.
82 : * @param[in] salt The salt to use, or NullOptional to use a
83 : * randomly-generated one. If provided, must be at
84 : * least kSpake2p_Min_PBKDF_Salt_Length bytes and
85 : * at most kSpake2p_Max_PBKDF_Salt_Length bytes in
86 : * length.
87 : * @param[in] callback The function to be called on success or failure of opening of commissioning window.
88 : * @param[out] payload The setup payload, not including the VID/PID bits,
89 : * even if those were asked for, that is generated
90 : * based on the passed-in information. The payload
91 : * provided to the callback function, unlike this
92 : * out parameter, will include the VID/PID bits if
93 : * readVIDPIDAttributes is true.
94 : *
95 : * @param[in] readVIDPIDAttributes Should the API internally read VID and PID from the device while opening the
96 : * commissioning window. If this argument is `true`, the API will read VID and
97 : * PID from the device and include them in the setup payload passed to the
98 : * callback.
99 : */
100 : CHIP_ERROR OpenCommissioningWindow(NodeId deviceId, System::Clock::Seconds16 timeout, uint32_t iteration,
101 : uint16_t discriminator, Optional<uint32_t> setupPIN, Optional<ByteSpan> salt,
102 : Callback::Callback<OnOpenCommissioningWindow> * callback, SetupPayload & payload,
103 : bool readVIDPIDAttributes = false);
104 :
105 : /**
106 : * @brief
107 : * Try to look up the device attached to our controller with the given
108 : * node id and ask it to re-enter commissioning mode with a PASE verifier
109 : * derived from the given information and the given discriminator. The
110 : * device will exit commissioning mode after a successful commissioning,
111 : * or after the given `timeout` time.
112 : *
113 : * @param[in] params The parameters required to open an enhanced commissioning window
114 : * with the provided or generated passcode.
115 : * @param[out] payload The setup payload, not including the VID/PID bits,
116 : * even if those were asked for, that is generated
117 : * based on the passed-in information. The payload
118 : * provided to the callback function, unlike this
119 : * out parameter, will include the VID/PID bits if
120 : * readVIDPIDAttributes is true.
121 : */
122 : CHIP_ERROR OpenCommissioningWindow(const CommissioningWindowPasscodeParams & params, SetupPayload & payload);
123 :
124 : /**
125 : * @brief
126 : * Try to look up the device attached to our controller with the given
127 : * node id and ask it to re-enter commissioning mode with a PASE verifier
128 : * derived from the given information and the given discriminator. The
129 : * device will exit commissioning mode after a successful commissioning,
130 : * or after the given `timeout` time.
131 : *
132 : * @param[in] params The parameters required to open an enhanced commissioning window
133 : * with the provided PAKE passcode verifier.
134 : */
135 : CHIP_ERROR OpenCommissioningWindow(const CommissioningWindowVerifierParams & params);
136 :
137 : private:
138 : enum class Step : uint8_t
139 : {
140 : // Ready to start opening a commissioning window.
141 : kAcceptCommissioningStart,
142 : // Need to read VID.
143 : kReadVID,
144 : // Need to read PID.
145 : kReadPID,
146 : // Need to open commissioning window.
147 : kOpenCommissioningWindow,
148 : };
149 :
150 : CHIP_ERROR OpenCommissioningWindowInternal(Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle);
151 : static void OnPIDReadResponse(void * context, uint16_t value);
152 : static void OnVIDReadResponse(void * context, VendorId value);
153 : static void OnVIDPIDReadFailureResponse(void * context, CHIP_ERROR error);
154 : static void OnOpenCommissioningWindowSuccess(void * context, const app::DataModel::NullObjectType &);
155 : static void OnOpenCommissioningWindowFailure(void * context, CHIP_ERROR error);
156 : static void OnDeviceConnectedCallback(void * context, Messaging::ExchangeManager & exchangeMgr,
157 : const SessionHandle & sessionHandle);
158 : static void OnDeviceConnectionFailureCallback(void * context, const ScopedNodeId & peerId, CHIP_ERROR error);
159 :
160 : DeviceController * const mController = nullptr;
161 : Step mNextStep = Step::kAcceptCommissioningStart;
162 :
163 : Callback::Callback<OnOpenCommissioningWindow> * mCommissioningWindowCallback = nullptr;
164 : Callback::Callback<OnOpenCommissioningWindowWithVerifier> * mCommissioningWindowVerifierCallback = nullptr;
165 : Callback::Callback<OnOpenBasicCommissioningWindow> * mBasicCommissioningWindowCallback = nullptr;
166 : SetupPayload mSetupPayload;
167 : SetupDiscriminator mDiscriminator{};
168 : NodeId mNodeId = kUndefinedNodeId;
169 : EndpointId mTargetEndpointId = kRootEndpointId; // Default endpoint for Administrator Commissioning Cluster
170 : System::Clock::Seconds16 mCommissioningWindowTimeout = System::Clock::kZero;
171 : CommissioningWindowOption mCommissioningWindowOption = CommissioningWindowOption::kOriginalSetupCode;
172 : Crypto::Spake2pVerifier mVerifier; // Used for non-basic commissioning.
173 : // Parameters needed for non-basic commissioning.
174 : uint32_t mPBKDFIterations = 0;
175 : uint8_t mPBKDFSaltBuffer[Crypto::kSpake2p_Max_PBKDF_Salt_Length];
176 : ByteSpan mPBKDFSalt;
177 :
178 : Callback::Callback<OnDeviceConnected> mDeviceConnected;
179 : Callback::Callback<OnDeviceConnectionFailure> mDeviceConnectionFailure;
180 : };
181 :
182 : /**
183 : * A helper class that can be used by consumers that don't care about the callback from the
184 : * open-commissioning-window process and just want automatic cleanup of the CommissioningWindowOpener when done
185 : * with it.
186 : */
187 : class AutoCommissioningWindowOpener : private CommissioningWindowOpener
188 : {
189 : public:
190 : // Takes the same arguments as CommissioningWindowOpener::OpenBasicCommissioningWindow except without the
191 : // callback.
192 : static CHIP_ERROR OpenBasicCommissioningWindow(DeviceController * controller, NodeId deviceId,
193 : System::Clock::Seconds16 timeout);
194 : // Takes the same arguments as CommissioningWindowOpener::OpenCommissioningWindow except without the
195 : // callback.
196 : static CHIP_ERROR OpenCommissioningWindow(DeviceController * controller, NodeId deviceId, System::Clock::Seconds16 timeout,
197 : uint32_t iteration, uint16_t discriminator, Optional<uint32_t> setupPIN,
198 : Optional<ByteSpan> salt, SetupPayload & payload, bool readVIDPIDAttributes = false);
199 :
200 : private:
201 : AutoCommissioningWindowOpener(DeviceController * controller);
202 :
203 : static void OnOpenCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status, chip::SetupPayload payload);
204 : static void OnOpenBasicCommissioningWindowResponse(void * context, NodeId deviceId, CHIP_ERROR status);
205 :
206 : chip::Callback::Callback<chip::Controller::OnOpenCommissioningWindow> mOnOpenCommissioningWindowCallback;
207 : chip::Callback::Callback<chip::Controller::OnOpenBasicCommissioningWindow> mOnOpenBasicCommissioningWindowCallback;
208 : };
209 :
210 : } // Namespace Controller
211 : } // namespace chip
|