3 * Copyright (c) 2020 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file defines the CHIP SPAKE2P Session object that provides
22 * APIs for constructing spake2p messages and establishing encryption
29 #include <crypto/CHIPCryptoPAL.h>
30 #include <protocols/secure_channel/Constants.h>
31 #include <support/Base64.h>
32 #include <system/SystemPacketBuffer.h>
33 #include <transport/PeerConnectionState.h>
34 #include <transport/SecureSession.h>
35 #include <transport/SessionEstablishmentDelegate.h>
36 #include <transport/raw/MessageHeader.h>
37 #include <transport/raw/PeerAddress.h>
41 extern const char * kSpake2pI2RSessionInfo;
42 extern const char * kSpake2pR2ISessionInfo;
44 constexpr uint16_t kPBKDFParamRandomNumberSize = 32;
46 using namespace Crypto;
48 constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;
50 struct PASESessionSerialized;
52 struct PASESessionSerializable
55 uint8_t mKe[kMAX_Hash_Length];
56 uint8_t mPairingComplete;
61 typedef uint8_t PASEVerifier[2][kSpake2p_WS_Length];
63 class DLL_EXPORT PASESession
67 PASESession(PASESession &&) = default;
68 PASESession(const PASESession &) = delete;
69 PASESession & operator=(const PASESession &) = default;
70 PASESession & operator=(PASESession &&) = default;
72 virtual ~PASESession();
76 * Initialize using setup PIN code and wait for pairing requests.
78 * @param mySetUpPINCode Setup PIN code of the local device
79 * @param pbkdf2IterCount Iteration count for PBKDF2 function
80 * @param salt Salt to be used for SPAKE2P opertation
81 * @param saltLen Length of salt
82 * @param myKeyId Key ID to be assigned to the secure session on the peer node
83 * @param delegate Callback object
85 * @return CHIP_ERROR The result of initialization
87 CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
88 uint16_t myKeyId, SessionEstablishmentDelegate * delegate);
92 * Initialize using PASE verifier and wait for pairing requests.
94 * @param verifier PASE verifier to be used for SPAKE2P pairing
95 * @param myKeyId Key ID to be assigned to the secure session on the peer node
96 * @param delegate Callback object
98 * @return CHIP_ERROR The result of initialization
100 CHIP_ERROR WaitForPairing(const PASEVerifier & verifier, uint16_t myKeyId, SessionEstablishmentDelegate * delegate);
104 * Create a pairing request using peer's setup PIN code.
106 * @param peerAddress Address of peer to pair
107 * @param peerSetUpPINCode Setup PIN code of the peer device
108 * @param myKeyId Key ID to be assigned to the secure session on the peer node
109 * @param delegate Callback object
111 * @return CHIP_ERROR The result of initialization
113 CHIP_ERROR Pair(const Transport::PeerAddress peerAddress, uint32_t peerSetUpPINCode, uint16_t myKeyId,
114 SessionEstablishmentDelegate * delegate);
118 * Create a pairing request using given PASE verifier.
120 * @param peerAddress Address of peer to pair
121 * @param verifier PASE verifier to be used for SPAKE2P pairing
122 * @param myKeyId Key ID to be assigned to the secure session on the peer node
123 * @param delegate Callback object
125 * @return CHIP_ERROR The result of initialization
127 CHIP_ERROR Pair(const Transport::PeerAddress peerAddress, const PASEVerifier & verifier, uint16_t myKeyId,
128 SessionEstablishmentDelegate * delegate);
132 * Generate a new PASE verifier.
134 * @param verifier The generated PASE verifier
135 * @param useRandomPIN Generate a random setup PIN, if true. Else, use the provided PIN
136 * @param setupPIN Provided setup PIN (if useRandomPIN is false), or the generated PIN
138 * @return CHIP_ERROR The result of PASE verifier generation
140 static CHIP_ERROR GeneratePASEVerifier(PASEVerifier & verifier, bool useRandomPIN, uint32_t & setupPIN);
144 * Derive a secure session from the paired session. The API will return error
145 * if called before pairing is established.
147 * @param info Information string used for key derivation
148 * @param info_len Length of info string
149 * @param session Referene to the sescure session that will be
150 * initialized once pairing is complete
151 * @return CHIP_ERROR The result of session derivation
153 CHIP_ERROR DeriveSecureSession(const uint8_t * info, size_t info_len, SecureSession & session);
157 * Handler for peer's messages, exchanged during pairing handshake.
159 * @param packetHeader Message header for the received message
160 * @param peerAddress Source of the message
161 * @param msg Message sent by the peer
162 * @return CHIP_ERROR The result of message processing
164 virtual CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
165 System::PacketBufferHandle msg);
169 * Return the associated peer key id
171 * @return uint16_t The associated peer key id
173 uint16_t GetPeerKeyId() { return mConnectionState.GetPeerKeyID(); }
177 * Return the associated local key id
179 * @return uint16_t The assocated local key id
181 uint16_t GetLocalKeyId() { return mConnectionState.GetLocalKeyID(); }
183 Transport::PeerConnectionState & PeerConnection() { return mConnectionState; }
185 /** @brief Serialize the Pairing Session to a string.
187 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
189 CHIP_ERROR Serialize(PASESessionSerialized & output);
191 /** @brief Deserialize the Pairing Session from the string.
193 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
195 CHIP_ERROR Deserialize(PASESessionSerialized & input);
197 /** @brief Serialize the PASESession to the given serializable data structure for secure pairing
199 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
201 CHIP_ERROR ToSerializable(PASESessionSerializable & output);
203 /** @brief Reconstruct secure pairing class from the serializable data structure.
205 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
207 CHIP_ERROR FromSerializable(const PASESessionSerializable & output);
209 /** @brief This function zeroes out and resets the memory used by the object.
214 enum Spake2pErrorType : uint8_t
216 kInvalidKeyConfirmation = 0x00,
220 CHIP_ERROR Init(uint16_t myKeyId, uint32_t setupCode, SessionEstablishmentDelegate * delegate);
222 static CHIP_ERROR ComputePASEVerifier(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
223 PASEVerifier & verifier);
225 CHIP_ERROR SetupSpake2p(uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen);
227 CHIP_ERROR SendPBKDFParamRequest();
228 CHIP_ERROR HandlePBKDFParamRequest(const PacketHeader & header, const System::PacketBufferHandle & msg);
230 CHIP_ERROR SendPBKDFParamResponse();
231 CHIP_ERROR HandlePBKDFParamResponse(const PacketHeader & header, const System::PacketBufferHandle & msg);
233 CHIP_ERROR SendMsg1();
235 CHIP_ERROR HandleMsg1_and_SendMsg2(const PacketHeader & header, const System::PacketBufferHandle & msg);
236 CHIP_ERROR HandleMsg2_and_SendMsg3(const PacketHeader & header, const System::PacketBufferHandle & msg);
237 CHIP_ERROR HandleMsg3(const PacketHeader & header, const System::PacketBufferHandle & msg);
239 void SendErrorMsg(Spake2pErrorType errorCode);
240 void HandleErrorMsg(const PacketHeader & header, const System::PacketBufferHandle & msg);
242 CHIP_ERROR AttachHeaderAndSend(Protocols::SecureChannel::MsgType msgType, System::PacketBufferHandle msgBuf);
244 SessionEstablishmentDelegate * mDelegate = nullptr;
246 Protocols::SecureChannel::MsgType mNextExpectedMsg = Protocols::SecureChannel::MsgType::PASE_Spake2pError;
248 Spake2p_P256_SHA256_HKDF_HMAC mSpake2p;
250 uint8_t mPoint[kMAX_Point_Length];
253 PASEVerifier mPASEVerifier;
255 uint32_t mSetupPINCode;
257 bool mComputeVerifier = true;
259 Hash_SHA256_stream mCommissioningHash;
260 uint32_t mIterationCount = 0;
261 uint16_t mSaltLength = 0;
262 uint8_t * mSalt = nullptr;
264 struct Spake2pErrorMsg
266 Spake2pErrorType error;
270 uint8_t mKe[kMAX_Hash_Length];
272 size_t mKeLen = sizeof(mKe);
274 bool mPairingComplete = false;
276 Transport::PeerConnectionState mConnectionState;
280 * The following constants are node IDs that test devices and test
281 * controllers use while using the SecurePairingUsingTestSecret to
282 * establish secure channel
284 constexpr chip::NodeId kTestControllerNodeId = 112233;
285 constexpr chip::NodeId kTestDeviceNodeId = 12344321;
288 * The following class should only be used for test usecases.
289 * The class is currently also used for devices that do no yet support
290 * rendezvous. Once all the non-test usecases start supporting
291 * rendezvous, this class will be moved to the test code.
293 class SecurePairingUsingTestSecret : public PASESession
296 SecurePairingUsingTestSecret()
298 const char * secret = "Test secret for key derivation";
299 size_t secretLen = strlen(secret);
301 memmove(mKe, secret, mKeLen);
302 mConnectionState.SetPeerKeyID(0);
303 mConnectionState.SetLocalKeyID(0);
304 mPairingComplete = true;
307 SecurePairingUsingTestSecret(uint16_t peerKeyId, uint16_t localKeyId)
309 const char * secret = "Test secret for key derivation";
310 size_t secretLen = strlen(secret);
312 memmove(mKe, secret, mKeLen);
313 mConnectionState.SetPeerKeyID(peerKeyId);
314 mConnectionState.SetLocalKeyID(localKeyId);
315 mPairingComplete = true;
318 ~SecurePairingUsingTestSecret() override {}
320 CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
321 uint16_t myKeyId, SessionEstablishmentDelegate * delegate)
323 return CHIP_NO_ERROR;
326 CHIP_ERROR Pair(uint32_t peerSetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen, uint16_t myKeyId,
327 SessionEstablishmentDelegate * delegate)
329 return CHIP_NO_ERROR;
332 CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
333 System::PacketBufferHandle msg) override
335 return CHIP_NO_ERROR;
339 typedef struct PASESessionSerialized
341 // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads)
342 uint8_t inner[BASE64_ENCODED_LEN(sizeof(PASESessionSerializable) + sizeof(uint64_t))];
343 } PASESessionSerialized;