Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2022 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines the CHIP SPAKE2P Session object that provides
22 : * APIs for constructing spake2p messages and establishing encryption
23 : * keys.
24 : *
25 : */
26 :
27 : #pragma once
28 :
29 : #include <crypto/CHIPCryptoPAL.h>
30 : #if CHIP_CRYPTO_PSA_SPAKE2P
31 : #include <crypto/PSASpake2p.h>
32 : #endif
33 : #include <lib/support/Base64.h>
34 : #include <messaging/ExchangeContext.h>
35 : #include <messaging/ExchangeDelegate.h>
36 : #include <messaging/ExchangeMessageDispatch.h>
37 : #include <protocols/secure_channel/Constants.h>
38 : #include <protocols/secure_channel/PairingSession.h>
39 : #include <protocols/secure_channel/SessionEstablishmentExchangeDispatch.h>
40 : #include <system/SystemPacketBuffer.h>
41 : #include <system/TLVPacketBufferBackingStore.h>
42 : #include <transport/CryptoContext.h>
43 : #include <transport/raw/MessageHeader.h>
44 : #include <transport/raw/PeerAddress.h>
45 :
46 : namespace chip {
47 : namespace Testing {
48 : class TestPASESession;
49 : }
50 : extern const char kSpake2pI2RSessionInfo[];
51 : extern const char kSpake2pR2ISessionInfo[];
52 :
53 : inline constexpr uint16_t kPBKDFParamRandomNumberSize = 32;
54 :
55 : class DLL_EXPORT PASESession : public Messaging::UnsolicitedMessageHandler,
56 : public Messaging::ExchangeDelegate,
57 : public PairingSession
58 : {
59 : public:
60 : ~PASESession() override;
61 :
62 6 : Transport::SecureSession::Type GetSecureSessionType() const override { return Transport::SecureSession::Type::kPASE; }
63 40 : ScopedNodeId GetPeer() const override
64 : {
65 40 : return ScopedNodeId(NodeIdFromPAKEKeyId(kDefaultCommissioningPasscodeId), kUndefinedFabricIndex);
66 : }
67 :
68 10 : ScopedNodeId GetLocalScopedNodeId() const override
69 : {
70 : // For PASE, source is always the undefined node ID
71 10 : return ScopedNodeId();
72 : }
73 :
74 30 : CATValues GetPeerCATs() const override { return CATValues(); };
75 :
76 : CHIP_ERROR OnUnsolicitedMessageReceived(const PayloadHeader & payloadHeader, ExchangeDelegate *& newDelegate) override;
77 :
78 : /**
79 : * @brief
80 : * Initialize using PASE verifier and wait for pairing requests.
81 : *
82 : * @param sessionManager session manager from which to allocate a secure session object
83 : * @param verifier PASE verifier to be used for SPAKE2P pairing
84 : * @param pbkdf2IterCount Iteration count for PBKDF2 function
85 : * @param salt Salt to be used for SPAKE2P operation
86 : * @param delegate Callback object
87 : *
88 : * @return CHIP_ERROR The result of initialization
89 : */
90 : CHIP_ERROR WaitForPairing(SessionManager & sessionManager, const Crypto::Spake2pVerifier & verifier, uint32_t pbkdf2IterCount,
91 : const ByteSpan & salt, Optional<ReliableMessageProtocolConfig> mrpLocalConfig,
92 : SessionEstablishmentDelegate * delegate);
93 :
94 : /**
95 : * @brief
96 : * Create a pairing request using peer's setup PIN code.
97 : *
98 : * @param sessionManager session manager from which to allocate a secure session object
99 : * @param peerSetUpPINCode Setup PIN code of the peer device
100 : * @param exchangeCtxt The exchange context to send and receive messages with the peer
101 : * Note: It's expected that the caller of this API hands over the
102 : * ownership of the exchangeCtxt to PASESession object. PASESession
103 : * will close the exchange on (successful/failed) handshake completion.
104 : * @param delegate Callback object
105 : * The delegate will be notified if and only if Pair() returns success. Errors occurring after Pair()
106 : * returns success will be reported via the delegate.
107 : *
108 : * @return CHIP_ERROR The result of initialization
109 : */
110 : CHIP_ERROR Pair(SessionManager & sessionManager, uint32_t peerSetUpPINCode,
111 : Optional<ReliableMessageProtocolConfig> mrpLocalConfig, Messaging::ExchangeContext * exchangeCtxt,
112 : SessionEstablishmentDelegate * delegate);
113 :
114 : /**
115 : * @brief
116 : * Generate a new PASE verifier.
117 : *
118 : * @param verifier The generated PASE verifier
119 : * @param pbkdf2IterCount Iteration count for PBKDF2 function
120 : * @param salt Salt to be used for SPAKE2P operation
121 : * @param useRandomPIN Generate a random setup PIN, if true. Else, use the provided PIN
122 : * @param setupPIN Provided setup PIN (if useRandomPIN is false), or the generated PIN
123 : *
124 : * @return CHIP_ERROR The result of PASE verifier generation
125 : */
126 : static CHIP_ERROR GeneratePASEVerifier(Crypto::Spake2pVerifier & verifier, uint32_t pbkdf2IterCount, const ByteSpan & salt,
127 : bool useRandomPIN, uint32_t & setupPIN);
128 :
129 : /**
130 : * @brief
131 : * Derive a secure session from the paired session. The API will return error if called before pairing is established.
132 : *
133 : * @param session Reference to the secure session that will be initialized once pairing is complete
134 : * @return CHIP_ERROR The result of session derivation
135 : */
136 : CHIP_ERROR DeriveSecureSession(CryptoContext & session) override;
137 :
138 : // TODO: remove Clear, we should create a new instance instead reset the old instance.
139 : /** @brief This function zeroes out and resets the memory used by the object.
140 : **/
141 : void Clear();
142 :
143 : //// ExchangeDelegate Implementation ////
144 : /**
145 : * @brief
146 : * This function is the called by exchange context or exchange manager when it receives
147 : * a CHIP message corresponding to the context, or registered unsolicited message handler.
148 : *
149 : * Note: If the function is called by unsolicited message handler, the ownership of the
150 : * provide exchange context is handed over to PASE Session object. The PASE Session
151 : * object ensures that the exchange will be closed on completion of the handshake.
152 : *
153 : * @param[in] ec A pointer to the ExchangeContext object.
154 : * @param[in] payloadHeader A reference to the PayloadHeader object.
155 : * @param[in] payload A handle to the PacketBuffer object holding the message payload.
156 : */
157 : CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * ec, const PayloadHeader & payloadHeader,
158 : System::PacketBufferHandle && payload) override;
159 :
160 : /**
161 : * @brief
162 : * This function is the protocol callback to invoke when the timeout for the receipt
163 : * of a response message has expired.
164 : *
165 : * @param[in] ec A pointer to the ExchangeContext object.
166 : */
167 : void OnResponseTimeout(Messaging::ExchangeContext * ec) override;
168 :
169 14 : Messaging::ExchangeMessageDispatch & GetMessageDispatch() override { return SessionEstablishmentExchangeDispatch::Instance(); }
170 :
171 : //// SessionDelegate ////
172 : void OnSessionReleased() override;
173 :
174 : private:
175 : enum Spake2pErrorType : uint8_t
176 : {
177 : kInvalidKeyConfirmation = 0x00,
178 : kUnexpected = 0xff,
179 : };
180 : friend class Testing::TestPASESession;
181 :
182 : CHIP_ERROR Init(SessionManager & sessionManager, uint32_t setupCode, SessionEstablishmentDelegate * delegate);
183 :
184 : CHIP_ERROR ValidateReceivedMessage(Messaging::ExchangeContext * exchange, const PayloadHeader & payloadHeader,
185 : const System::PacketBufferHandle & msg);
186 :
187 : CHIP_ERROR SetupSpake2p();
188 :
189 : CHIP_ERROR SendPBKDFParamRequest();
190 : CHIP_ERROR HandlePBKDFParamRequest(System::PacketBufferHandle && msg);
191 :
192 : CHIP_ERROR SendPBKDFParamResponse(ByteSpan initiatorRandom, bool initiatorHasPBKDFParams);
193 : CHIP_ERROR HandlePBKDFParamResponse(System::PacketBufferHandle && msg);
194 :
195 : CHIP_ERROR SendMsg1();
196 :
197 : CHIP_ERROR HandleMsg1_and_SendMsg2(System::PacketBufferHandle && msg);
198 : CHIP_ERROR HandleMsg2_and_SendMsg3(System::PacketBufferHandle && msg);
199 : CHIP_ERROR HandleMsg3(System::PacketBufferHandle && msg);
200 :
201 : void OnSuccessStatusReport() override;
202 : CHIP_ERROR OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
203 : Optional<uintptr_t> protocolData) override;
204 :
205 : /** This function returns the CHIP_ERROR from a call to TLVReader::Next() method.
206 : *
207 : * @retval #CHIP_END_OF_TLV If the end of the TLV encoding is reached.
208 : * @retval #CHIP_NO_ERROR If there are additional non-parsed TLV Elements.
209 : * @retval other See return values of TLVReader::Next()
210 : **/
211 : CHIP_ERROR ReadSessionParamsIfPresent(const TLV::Tag & SessionParamsTag, System::PacketBufferTLVReader & tlvReader);
212 :
213 : void Finish();
214 :
215 : // mNextExpectedMsg is set when we are expecting a message.
216 : Optional<Protocols::SecureChannel::MsgType> mNextExpectedMsg;
217 :
218 : #if CHIP_CRYPTO_PSA_SPAKE2P
219 : Crypto::PSASpake2p_P256_SHA256_HKDF_HMAC mSpake2p;
220 : #else
221 : Crypto::Spake2p_P256_SHA256_HKDF_HMAC mSpake2p;
222 : #endif
223 :
224 : Crypto::Spake2pVerifier mPASEVerifier;
225 :
226 : uint32_t mSetupPINCode;
227 :
228 : bool mHavePBKDFParameters = false;
229 :
230 : uint8_t mPBKDFLocalRandomData[kPBKDFParamRandomNumberSize];
231 :
232 : Crypto::Hash_SHA256_stream mCommissioningHash;
233 : uint32_t mIterationCount = 0;
234 : uint16_t mSaltLength = 0;
235 : uint8_t * mSalt = nullptr;
236 :
237 : struct Spake2pErrorMsg
238 : {
239 : Spake2pErrorType error;
240 : };
241 :
242 : protected:
243 : uint8_t mKe[Crypto::kMAX_Hash_Length];
244 :
245 : size_t mKeLen = sizeof(mKe);
246 :
247 : bool mPairingComplete = false;
248 : };
249 :
250 : // The following constants are node IDs that test devices and test controllers use.
251 : inline constexpr chip::NodeId kTestControllerNodeId = 112233;
252 : inline constexpr chip::NodeId kTestDeviceNodeId = 12344321;
253 :
254 : } // namespace chip
|