3 * Copyright (c) 2021 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 implements the the CHIP CASE Session object that provides
22 * APIs for constructing a secure session using a certificate from the device's
23 * operational credentials.
26 #include <transport/CASESession.h>
31 #include <core/CHIPEncoding.h>
32 #include <core/CHIPSafeCasts.h>
33 #include <protocols/Protocols.h>
34 #include <support/CHIPMem.h>
35 #include <support/CodeUtils.h>
36 #include <support/SafeInt.h>
37 #include <transport/SecureSessionMgr.h>
41 using namespace Crypto;
43 CASESession::CASESession() {}
45 CASESession::~CASESession()
47 // Let's clear out any security state stored in the object, before destroying it.
51 void CASESession::Clear()
53 // This function zeroes out and resets the memory used by the object.
54 // It's done so that no security related information will be leaked.
55 mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr;
56 mLocalNodeId = kUndefinedNodeId;
57 mPairingComplete = false;
58 mConnectionState.Reset();
62 CASESession::WaitForSessionEstablishment(NodeId myNodeId, uint16_t myKeyId, SessionEstablishmentDelegate * delegate)
67 CHIP_ERROR CASESession::AttachHeaderAndSend(Protocols::SecureChannel::MsgType msgType, System::PacketBufferHandle msgBuf)
69 PayloadHeader payloadHeader;
71 payloadHeader.SetMessageType(msgType);
73 CHIP_ERROR err = payloadHeader.EncodeBeforeData(msgBuf);
76 err = mDelegate->SendSessionEstablishmentMessage(PacketHeader()
77 .SetSourceNodeId(mLocalNodeId)
78 .SetDestinationNodeId(mConnectionState.GetPeerNodeId())
79 .SetEncryptionKeyID(mConnectionState.GetLocalKeyID()),
80 mConnectionState.GetPeerAddress(), std::move(msgBuf));
87 CHIP_ERROR CASESession::EstablishSession(const Transport::PeerAddress peerAddress, NodeId myNodeId, NodeId peerNodeId,
88 uint16_t myKeyId, SessionEstablishmentDelegate * delegate)
90 CHIP_ERROR err = CHIP_NO_ERROR;
93 mConnectionState.SetPeerAddress(peerAddress);
94 mConnectionState.SetPeerNodeId(peerNodeId);
100 if (err != CHIP_NO_ERROR)
107 CHIP_ERROR CASESession::DeriveSecureSession(SecureSession & session)
109 CHIP_ERROR err = CHIP_NO_ERROR;
111 VerifyOrExit(mPairingComplete, err = CHIP_ERROR_INCORRECT_STATE);
113 // TODO: Use asymmetric keypair to create the secure session
114 // err = session.Init();
115 err = CHIP_ERROR_NOT_IMPLEMENTED;
122 CHIP_ERROR CASESession::SendSigmaR1()
124 uint16_t data_len = 0;
126 System::PacketBufferHandle msg_R1;
128 msg_R1 = System::PacketBufferHandle::New(data_len);
129 VerifyOrReturnError(!msg_R1.IsNull(), CHIP_SYSTEM_ERROR_NO_MEMORY);
131 // TODO: Construct SigmaR1 message in form of the following structure
132 // https://github.com/project-chip/connectedhomeip/issues/4469
137 uint8_t sessionid[2];
138 TrustedRootIdentifier trusted_roots[];
139 CipherSuite cipher_suites[];
140 KeyShare key_shares[];
141 Extensions extensions[];
145 msg_R1->SetDataLength(data_len);
146 mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaR2;
148 // Call delegate to send the msg to peer
149 ReturnErrorOnFailure(AttachHeaderAndSend(Protocols::SecureChannel::MsgType::CASE_SigmaR1, std::move(msg_R1)));
151 ChipLogDetail(Inet, "Sent SigmaR1 msg");
153 return CHIP_NO_ERROR;
156 CHIP_ERROR CASESession::HandleSigmaR1_and_SendSigmaR2(const PacketHeader & header, const System::PacketBufferHandle & msg)
158 CHIP_ERROR err = CHIP_NO_ERROR;
160 uint16_t data_len = 0;
162 const uint8_t * buf = msg->Start();
164 System::PacketBufferHandle msg_R2;
166 ChipLogDetail(Inet, "Received SigmaR1 msg");
168 VerifyOrExit(buf != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
170 // TODO: Verify received SigmaR1 message.
171 // https://github.com/project-chip/connectedhomeip/issues/4469
173 mConnectionState.SetPeerKeyID(header.GetEncryptionKeyID());
175 msg_R2 = System::PacketBufferHandle::New(data_len);
176 VerifyOrExit(!msg_R2.IsNull(), err = CHIP_SYSTEM_ERROR_NO_MEMORY);
178 // TODO: Construct SigmaR2 message in form of the following structure
179 // https://github.com/project-chip/connectedhomeip/issues/4469
181 struct SigmaR2Encrypted
183 opaque responder_identity;
190 uint8_t sessionid[2];
191 TrustedRootIdentifier trusted_root;
192 CipherSuite cipher_suite;
194 SigmaR2Encrypted encrypted_r2;
198 msg_R2->SetDataLength(data_len);
199 mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaR3;
201 // Call delegate to send the msg to peer
202 err = AttachHeaderAndSend(Protocols::SecureChannel::MsgType::CASE_SigmaR2, std::move(msg_R2));
205 ChipLogDetail(Inet, "Sent SigmaR2 msg");
209 if (err != CHIP_NO_ERROR)
211 SendErrorMsg(SigmaErrorType::kUnexpected);
216 CHIP_ERROR CASESession::HandleSigmaR2_and_SendSigmaR3(const PacketHeader & header, const System::PacketBufferHandle & msg)
218 CHIP_ERROR err = CHIP_NO_ERROR;
220 uint16_t data_len = 0;
222 const uint8_t * buf = msg->Start();
224 System::PacketBufferHandle msg_R3;
226 ChipLogDetail(Inet, "Received SigmaR2 msg");
228 // TODO: Verify received SigmaR2 message.
229 // https://github.com/project-chip/connectedhomeip/issues/4469
231 mConnectionState.SetPeerKeyID(header.GetEncryptionKeyID());
233 VerifyOrExit(buf != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
235 msg_R3 = System::PacketBufferHandle::New(data_len);
236 VerifyOrExit(!msg_R3.IsNull(), err = CHIP_SYSTEM_ERROR_NO_MEMORY);
238 // TODO: Construct SigmaR3 message in form of the following structure
239 // https://github.com/project-chip/connectedhomeip/issues/4469
241 struct SigmaR3Encrypted
243 opaque initiator_identity;
249 SigmaR3Encrypted encrypted_r3;
253 msg_R3->SetDataLength(data_len);
255 // Call delegate to send the Msg3 to peer
256 err = AttachHeaderAndSend(Protocols::SecureChannel::MsgType::CASE_SigmaR3, std::move(msg_R3));
259 ChipLogDetail(Inet, "Sent SigmaR3 msg");
261 mPairingComplete = true;
263 // Call delegate to indicate pairing completion
264 mDelegate->OnSessionEstablished();
268 if (err != CHIP_NO_ERROR)
270 SendErrorMsg(SigmaErrorType::kUnexpected);
275 CHIP_ERROR CASESession::HandleSigmaR3(const PacketHeader & header, const System::PacketBufferHandle & msg)
277 CHIP_ERROR err = CHIP_NO_ERROR;
279 ChipLogDetail(Inet, "Received SigmaR3 msg");
281 // TODO: Verify received SigmaR3 message.
282 // https://github.com/project-chip/connectedhomeip/issues/4469
284 mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr;
286 VerifyOrExit(header.GetSourceNodeId().ValueOr(kUndefinedNodeId) == mConnectionState.GetPeerNodeId(),
287 err = CHIP_ERROR_WRONG_NODE_ID);
288 VerifyOrExit(header.GetEncryptionKeyID() == mConnectionState.GetPeerKeyID(), err = CHIP_ERROR_INVALID_KEY_ID);
290 mPairingComplete = true;
292 // Call delegate to indicate pairing completion
293 mDelegate->OnSessionEstablished();
297 if (err != CHIP_NO_ERROR)
299 SendErrorMsg(SigmaErrorType::kUnexpected);
304 void CASESession::SendErrorMsg(SigmaErrorType errorCode)
306 CHIP_ERROR err = CHIP_NO_ERROR;
308 System::PacketBufferHandle msg;
309 uint16_t msglen = sizeof(SigmaErrorMsg);
310 SigmaErrorMsg * pMsg = nullptr;
312 msg = System::PacketBufferHandle::New(msglen);
313 VerifyOrExit(!msg.IsNull(), err = CHIP_SYSTEM_ERROR_NO_MEMORY);
315 pMsg = reinterpret_cast<SigmaErrorMsg *>(msg->Start());
316 pMsg->error = errorCode;
318 msg->SetDataLength(msglen);
320 err = AttachHeaderAndSend(Protocols::SecureChannel::MsgType::CASE_SigmaErr, std::move(msg));
327 void CASESession::HandleErrorMsg(const PacketHeader & header, const System::PacketBufferHandle & msg)
329 // Error message processing
330 const uint8_t * buf = msg->Start();
331 size_t buflen = msg->DataLength();
332 SigmaErrorMsg * pMsg = nullptr;
334 VerifyOrExit(buf != nullptr, ChipLogError(Inet, "Null error msg received during pairing"));
335 static_assert(sizeof(SigmaErrorMsg) == sizeof(uint8_t),
336 "Assuming size of SigmaErrorMsg message is 1 octet, so that endian-ness conversion is not needed");
337 VerifyOrExit(buflen == sizeof(SigmaErrorMsg), ChipLogError(Inet, "Error msg with incorrect length received during pairing"));
339 pMsg = reinterpret_cast<SigmaErrorMsg *>(msg->Start());
340 ChipLogError(Inet, "Received error (%d) during CASE pairing process", pMsg->error);
346 CHIP_ERROR CASESession::HandlePeerMessage(const PacketHeader & packetHeader, const Transport::PeerAddress & peerAddress,
347 System::PacketBufferHandle msg)
349 CHIP_ERROR err = CHIP_NO_ERROR;
350 PayloadHeader payloadHeader;
352 Protocols::SecureChannel::MsgType msgType;
354 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
356 err = payloadHeader.DecodeAndConsume(msg);
359 VerifyOrExit(payloadHeader.HasProtocol(Protocols::SecureChannel::Id), err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
361 msgType = static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType());
362 VerifyOrExit(msgType == mNextExpectedMsg, err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
364 mConnectionState.SetPeerAddress(peerAddress);
365 VerifyOrExit(mLocalNodeId == packetHeader.GetDestinationNodeId().Value(), err = CHIP_ERROR_WRONG_NODE_ID);
369 case Protocols::SecureChannel::MsgType::CASE_SigmaR1:
370 err = HandleSigmaR1_and_SendSigmaR2(packetHeader, msg);
373 case Protocols::SecureChannel::MsgType::CASE_SigmaR2:
374 err = HandleSigmaR2_and_SendSigmaR3(packetHeader, msg);
377 case Protocols::SecureChannel::MsgType::CASE_SigmaR3:
378 err = HandleSigmaR3(packetHeader, msg);
381 case Protocols::SecureChannel::MsgType::CASE_SigmaErr:
382 HandleErrorMsg(packetHeader, msg);
386 SendErrorMsg(SigmaErrorType::kUnexpected);
387 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
393 // Call delegate to indicate session establishment failure.
394 if (err != CHIP_NO_ERROR)
396 mDelegate->OnSessionEstablishmentError(err);