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 <support/Base64.h>
31 #include <system/SystemPacketBuffer.h>
32 #include <transport/SecureSession.h>
33 #include <transport/raw/MessageHeader.h>
34 #include <transport/raw/PeerAddress.h>
38 extern const char * kSpake2pI2RSessionInfo;
39 extern const char * kSpake2pR2ISessionInfo;
41 using namespace Crypto;
43 class DLL_EXPORT SecurePairingSessionDelegate
48 * Called when pairing session generates a new message that should be sent to peer.
50 * @param header the message header for the sent message
51 * @param peerAddress the destination of the message
52 * @param msgBuf the raw data for the message being sent
53 * @return CHIP_ERROR Error thrown when sending the message
55 virtual CHIP_ERROR SendPairingMessage(const PacketHeader & header, const Transport::PeerAddress & peerAddress,
56 System::PacketBuffer * msgBuf)
58 return CHIP_ERROR_NOT_IMPLEMENTED;
63 * Called when pairing fails with an error
65 * @param error error code
67 virtual void OnPairingError(CHIP_ERROR error) {}
71 * Called when the pairing is complete and the new secure session has been established
73 virtual void OnPairingComplete() {}
75 virtual ~SecurePairingSessionDelegate() {}
78 struct SecurePairingSessionSerialized;
80 struct SecurePairingSessionSerializable
83 uint8_t mKe[kMAX_Hash_Length];
84 uint8_t mPairingComplete;
85 uint64_t mLocalNodeId;
91 class DLL_EXPORT SecurePairingSession
94 SecurePairingSession();
95 SecurePairingSession(SecurePairingSession &&) = default;
96 SecurePairingSession(const SecurePairingSession &) = delete;
97 SecurePairingSession & operator=(const SecurePairingSession &) = default;
98 SecurePairingSession & operator=(SecurePairingSession &&) = default;
100 virtual ~SecurePairingSession();
104 * Initialize using setup PIN code and wait for pairing requests.
106 * @param mySetUpPINCode Setup PIN code of the local device
107 * @param pbkdf2IterCount Iteration count for PBKDF2 function
108 * @param salt Salt to be used for SPAKE2P opertation
109 * @param saltLen Length of salt
110 * @param myNodeId Optional node id of local node
111 * @param myKeyId Key ID to be assigned to the secure session on the peer node
112 * @param delegate Callback object
114 * @return CHIP_ERROR The result of initialization
116 CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
117 Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
121 * Create a pairing request using peer's setup PIN code.
123 * @param peerAddress Address of peer to pair
124 * @param peerSetUpPINCode Setup PIN code of the peer device
125 * @param pbkdf2IterCount Iteration count for PBKDF2 function
126 * @param salt Salt to be used for SPAKE2P opertation
127 * @param saltLen Length of salt
128 * @param myNodeId Optional node id of local node
129 * @param myKeyId Key ID to be assigned to the secure session on the peer node
130 * @param delegate Callback object
132 * @return CHIP_ERROR The result of initialization
134 CHIP_ERROR Pair(const Transport::PeerAddress peerAddress, uint32_t peerSetUpPINCode, uint32_t pbkdf2IterCount,
135 const uint8_t * salt, size_t saltLen, Optional<NodeId> myNodeId, uint16_t myKeyId,
136 SecurePairingSessionDelegate * delegate);
140 * Derive a secure session from the paired session. The API will return error
141 * if called before pairing is established.
143 * @param info Information string used for key derivation
144 * @param info_len Length of info string
145 * @param session Referene to the sescure session that will be
146 * initialized once pairing is complete
147 * @return CHIP_ERROR The result of session derivation
149 virtual CHIP_ERROR DeriveSecureSession(const uint8_t * info, size_t info_len, SecureSession & session);
153 * Handler for peer's messages, exchanged during pairing handshake.
155 * @param packetHeader Message header for the received message
156 * @param peerAddress Source of the message
157 * @param msg Message sent by the peer
158 * @return CHIP_ERROR The result of message processing
160 virtual CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
161 System::PacketBufferHandle msg);
165 * Return the associated secure session peer NodeId
167 * @return Optional<NodeId> The associated peer NodeId
169 NodeId GetPeerNodeId() const { return mPeerNodeId.Value(); }
173 * Return the associated peer key id
175 * @return uint16_t The associated peer key id
177 uint16_t GetPeerKeyId() { return mPeerKeyId; }
181 * Return the associated local key id
183 * @return uint16_t The assocated local key id
185 uint16_t GetLocalKeyId() { return mLocalKeyId; }
187 /** @brief Serialize the Pairing Session to a string.
189 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
191 CHIP_ERROR Serialize(SecurePairingSessionSerialized & output);
193 /** @brief Deserialize the Pairing Session from the string.
195 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
197 CHIP_ERROR Deserialize(SecurePairingSessionSerialized & input);
199 /** @brief Serialize the SecurePairingSession to the given serializable data structure for secure pairing
201 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
203 CHIP_ERROR ToSerializable(SecurePairingSessionSerializable & output);
205 /** @brief Reconstruct secure pairing class from the serializable data structure.
207 * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise
209 CHIP_ERROR FromSerializable(const SecurePairingSessionSerializable & output);
212 CHIP_ERROR Init(uint32_t setupCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen, Optional<NodeId> myNodeId,
213 uint16_t myKeyId, SecurePairingSessionDelegate * delegate);
215 CHIP_ERROR HandleCompute_pA(const PacketHeader & header, const System::PacketBufferHandle & msg);
216 CHIP_ERROR HandleCompute_pB_cB(const PacketHeader & header, const System::PacketBufferHandle & msg);
217 CHIP_ERROR HandleCompute_cA(const PacketHeader & header, const System::PacketBufferHandle & msg);
219 CHIP_ERROR AttachHeaderAndSend(uint8_t msgType, System::PacketBuffer * msgBuf);
221 static constexpr size_t kSpake2p_WS_Length = kP256_FE_Length + 8;
223 enum Spake2pMsgType : uint8_t
225 kSpake2pCompute_pA = 0,
226 kSpake2pCompute_pB_cB = 1,
227 kSpake2pCompute_cA = 2,
228 kSpake2pMsgTypeMax = 3,
231 SecurePairingSessionDelegate * mDelegate = nullptr;
233 Spake2pMsgType mNextExpectedMsg = Spake2pMsgType::kSpake2pMsgTypeMax;
235 Spake2p_P256_SHA256_HKDF_HMAC mSpake2p;
237 uint8_t mPoint[kMAX_Point_Length];
240 uint8_t mWS[2][kSpake2p_WS_Length];
243 Optional<NodeId> mLocalNodeId = Optional<NodeId>::Value(kUndefinedNodeId);
245 Optional<NodeId> mPeerNodeId = Optional<NodeId>::Value(kUndefinedNodeId);
247 uint16_t mLocalKeyId;
251 Transport::PeerAddress mPeerAddress;
253 uint8_t mKe[kMAX_Hash_Length];
255 size_t mKeLen = sizeof(mKe);
257 bool mPairingComplete = false;
261 * The following constants are node IDs that test devices and test
262 * controllers use while using the SecurePairingUsingTestSecret to
263 * establish secure channel
265 constexpr chip::NodeId kTestControllerNodeId = 112233;
266 constexpr chip::NodeId kTestDeviceNodeId = 12344321;
269 * The following class should only be used for test usecases.
270 * The class is currently also used for devices that do no yet support
271 * rendezvous. Once all the non-test usecases start supporting
272 * rendezvous, this class will be moved to the test code.
274 class SecurePairingUsingTestSecret : public SecurePairingSession
277 SecurePairingUsingTestSecret()
279 const char * secret = "Test secret for key derivation";
280 size_t secretLen = strlen(secret);
282 memmove(mKe, secret, mKeLen);
283 mPairingComplete = true;
286 SecurePairingUsingTestSecret(Optional<NodeId> peerNodeId, uint16_t peerKeyId, uint16_t localKeyId)
288 const char * secret = "Test secret for key derivation";
289 size_t secretLen = strlen(secret);
290 mPeerNodeId = peerNodeId;
291 mPeerKeyId = peerKeyId;
292 mLocalKeyId = localKeyId;
294 memmove(mKe, secret, mKeLen);
295 mPairingComplete = true;
298 ~SecurePairingUsingTestSecret() override {}
300 CHIP_ERROR WaitForPairing(uint32_t mySetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
301 Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate)
303 return CHIP_NO_ERROR;
306 CHIP_ERROR Pair(uint32_t peerSetUpPINCode, uint32_t pbkdf2IterCount, const uint8_t * salt, size_t saltLen,
307 Optional<NodeId> myNodeId, uint16_t myKeyId, SecurePairingSessionDelegate * delegate)
309 return CHIP_NO_ERROR;
312 CHIP_ERROR HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
313 System::PacketBufferHandle msg) override
315 return CHIP_NO_ERROR;
319 typedef struct SecurePairingSessionSerialized
321 // Extra uint64_t to account for padding bytes (NULL termination, and some decoding overheads)
322 uint8_t inner[BASE64_ENCODED_LEN(sizeof(SecurePairingSessionSerializable) + sizeof(uint64_t))];
323 } SecurePairingSessionSerialized;