Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-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 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.
24 : *
25 : */
26 : #include <protocols/secure_channel/CASESession.h>
27 :
28 : #include <atomic>
29 : #include <inttypes.h>
30 : #include <memory>
31 : #include <string.h>
32 :
33 : #include <lib/core/CHIPEncoding.h>
34 : #include <lib/core/CHIPSafeCasts.h>
35 : #include <lib/support/CHIPMem.h>
36 : #include <lib/support/CodeUtils.h>
37 : #include <lib/support/SafeInt.h>
38 : #include <lib/support/ScopedBuffer.h>
39 : #include <lib/support/TypeTraits.h>
40 : #include <messaging/SessionParameters.h>
41 : #include <platform/PlatformManager.h>
42 : #include <protocols/Protocols.h>
43 : #include <protocols/secure_channel/CASEDestinationId.h>
44 : #include <protocols/secure_channel/PairingSession.h>
45 : #include <protocols/secure_channel/SessionResumptionStorage.h>
46 : #include <protocols/secure_channel/StatusReport.h>
47 : #include <system/SystemClock.h>
48 : #include <system/TLVPacketBufferBackingStore.h>
49 : #include <tracing/macros.h>
50 : #include <tracing/metric_event.h>
51 : #include <transport/SessionManager.h>
52 :
53 : namespace {
54 :
55 : enum
56 : {
57 : kTag_TBEData_SenderNOC = 1,
58 : kTag_TBEData_SenderICAC = 2,
59 : kTag_TBEData_Signature = 3,
60 : kTag_TBEData_ResumptionID = 4,
61 : };
62 :
63 : enum
64 : {
65 : kTag_TBSData_SenderNOC = 1,
66 : kTag_TBSData_SenderICAC = 2,
67 : kTag_TBSData_SenderPubKey = 3,
68 : kTag_TBSData_ReceiverPubKey = 4,
69 : };
70 :
71 : enum
72 : {
73 : kTag_Sigma1_InitiatorRandom = 1,
74 : kTag_Sigma1_InitiatorSessionId = 2,
75 : kTag_Sigma1_DestinationId = 3,
76 : kTag_Sigma1_InitiatorEphPubKey = 4,
77 : kTag_Sigma1_InitiatorMRPParams = 5,
78 : kTag_Sigma1_ResumptionID = 6,
79 : kTag_Sigma1_InitiatorResumeMIC = 7,
80 : };
81 :
82 : enum
83 : {
84 : kTag_Sigma2_ResponderRandom = 1,
85 : kTag_Sigma2_ResponderSessionId = 2,
86 : kTag_Sigma2_ResponderEphPubKey = 3,
87 : kTag_Sigma2_Encrypted2 = 4,
88 : kTag_Sigma2_ResponderMRPParams = 5,
89 : };
90 :
91 : enum
92 : {
93 : kTag_Sigma3_Encrypted3 = 1,
94 : };
95 :
96 : } // namespace
97 :
98 : namespace chip {
99 :
100 : using namespace Crypto;
101 : using namespace Credentials;
102 : using namespace Messaging;
103 : using namespace Encoding;
104 : using namespace Protocols::SecureChannel;
105 : using namespace Tracing;
106 :
107 : constexpr uint8_t kKDFSR2Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32 };
108 : constexpr uint8_t kKDFSR3Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33 };
109 :
110 : constexpr uint8_t kKDFS1RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x31, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 };
111 : constexpr uint8_t kKDFS2RKeyInfo[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32, 0x5f, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65 };
112 :
113 : constexpr uint8_t kResume1MIC_Nonce[] =
114 : /* "NCASE_SigmaS1" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x53, 0x31 };
115 : constexpr uint8_t kResume2MIC_Nonce[] =
116 : /* "NCASE_SigmaS2" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x53, 0x32 };
117 : constexpr uint8_t kTBEData2_Nonce[] =
118 : /* "NCASE_Sigma2N" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32, 0x4e };
119 : constexpr uint8_t kTBEData3_Nonce[] =
120 : /* "NCASE_Sigma3N" */ { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33, 0x4e };
121 : constexpr size_t kTBEDataNonceLength = sizeof(kTBEData2_Nonce);
122 : static_assert(sizeof(kTBEData2_Nonce) == sizeof(kTBEData3_Nonce), "TBEData2_Nonce and TBEData3_Nonce must be same size");
123 :
124 : // Amounts of time to allow for server-side processing of messages.
125 : //
126 : // These timeout values only allow for the server-side processing and assume that any transport-specific
127 : // latency will be added to them.
128 : //
129 : // The session establishment fails if the response is not received within the resulting timeout window,
130 : // which accounts for both transport latency and the server-side latency.
131 : static constexpr ExchangeContext::Timeout kExpectedLowProcessingTime = System::Clock::Seconds16(2);
132 : static constexpr ExchangeContext::Timeout kExpectedSigma1ProcessingTime = kExpectedLowProcessingTime;
133 : static constexpr ExchangeContext::Timeout kExpectedHighProcessingTime = System::Clock::Seconds16(30);
134 :
135 : // Helper for managing a session's outstanding work.
136 : // Holds work data which is provided to a scheduled work callback (standalone),
137 : // then (if not canceled) to a scheduled after work callback (on the session).
138 : template <class DATA>
139 : class CASESession::WorkHelper
140 : {
141 : public:
142 : // Work callback, processed in the background via `PlatformManager::ScheduleBackgroundWork`.
143 : // This is a non-member function which does not use the associated session.
144 : // The return value is passed to the after work callback (called afterward).
145 : // Set `cancel` to true if calling the after work callback is not necessary.
146 : typedef CHIP_ERROR (*WorkCallback)(DATA & data, bool & cancel);
147 :
148 : // After work callback, processed in the main Matter task via `PlatformManager::ScheduleWork`.
149 : // This is a member function to be called on the associated session after the work callback.
150 : // The `status` value is the result of the work callback (called beforehand), or the status of
151 : // queueing the after work callback back to the Matter thread, if the work callback succeeds
152 : // but queueing fails.
153 : //
154 : // When this callback is called asynchronously (i.e. via ScheduleWork), the helper guarantees
155 : // that it will keep itself (and hence `data`) alive until the callback completes.
156 : typedef CHIP_ERROR (CASESession::*AfterWorkCallback)(DATA & data, CHIP_ERROR status);
157 :
158 : public:
159 : // Create a work helper using the specified session, work callback, after work callback, and data (template arg).
160 : // Lifetime is managed by sharing between the caller (typically the session) and the helper itself (while work is scheduled).
161 14 : static Platform::SharedPtr<WorkHelper> Create(CASESession & session, WorkCallback workCallback,
162 : AfterWorkCallback afterWorkCallback)
163 : {
164 : struct EnableShared : public WorkHelper
165 : {
166 14 : EnableShared(CASESession & session, WorkCallback workCallback, AfterWorkCallback afterWorkCallback) :
167 14 : WorkHelper(session, workCallback, afterWorkCallback)
168 14 : {}
169 : };
170 14 : auto ptr = Platform::MakeShared<EnableShared>(session, workCallback, afterWorkCallback);
171 14 : if (ptr)
172 : {
173 14 : ptr->mWeakPtr = ptr; // used by `ScheduleWork`
174 : }
175 14 : return ptr;
176 14 : }
177 :
178 : // Do the work immediately.
179 : // No scheduling, no outstanding work, no shared lifetime management.
180 : //
181 : // The caller must guarantee that it keeps the helper alive across this call, most likely by
182 : // holding a reference to it on the stack.
183 7 : CHIP_ERROR DoWork()
184 : {
185 : // Ensure that this function is being called from main Matter thread
186 7 : assertChipStackLockedByCurrentThread();
187 :
188 7 : VerifyOrReturnError(mSession && mWorkCallback && mAfterWorkCallback, CHIP_ERROR_INCORRECT_STATE);
189 7 : auto * helper = this;
190 7 : bool cancel = false;
191 7 : helper->mStatus = helper->mWorkCallback(helper->mData, cancel);
192 7 : if (!cancel)
193 : {
194 7 : helper->mStatus = (helper->mSession->*(helper->mAfterWorkCallback))(helper->mData, helper->mStatus);
195 : }
196 7 : return helper->mStatus;
197 : }
198 :
199 : // Schedule the work for later execution.
200 : // If lifetime is managed, the helper shares management while work is outstanding.
201 7 : CHIP_ERROR ScheduleWork()
202 : {
203 7 : VerifyOrReturnError(mSession && mWorkCallback && mAfterWorkCallback, CHIP_ERROR_INCORRECT_STATE);
204 : // Hold strong ptr while work is outstanding
205 7 : mStrongPtr = mWeakPtr.lock(); // set in `Create`
206 7 : auto status = DeviceLayer::PlatformMgr().ScheduleBackgroundWork(WorkHandler, reinterpret_cast<intptr_t>(this));
207 7 : if (status != CHIP_NO_ERROR)
208 : {
209 : // Release strong ptr since scheduling failed.
210 0 : mStrongPtr.reset();
211 : }
212 7 : return status;
213 : }
214 :
215 : // Cancel the work, by clearing the associated session.
216 6 : void CancelWork() { mSession.store(nullptr); }
217 :
218 14 : bool IsCancelled() const { return mSession.load() == nullptr; }
219 :
220 : // This API returns true when background thread fails to schedule the AfterWorkCallback
221 0 : bool UnableToScheduleAfterWorkCallback() { return mScheduleAfterWorkFailed.load(); }
222 :
223 : // Do after work immediately.
224 : // No scheduling, no outstanding work, no shared lifetime management.
225 0 : void DoAfterWork()
226 : {
227 0 : VerifyOrDie(UnableToScheduleAfterWorkCallback());
228 0 : AfterWorkHandler(reinterpret_cast<intptr_t>(this));
229 0 : }
230 :
231 : private:
232 : // Create a work helper using the specified session, work callback, after work callback, and data (template arg).
233 : // Lifetime is not managed, see `Create` for that option.
234 14 : WorkHelper(CASESession & session, WorkCallback workCallback, AfterWorkCallback afterWorkCallback) :
235 14 : mSession(&session), mWorkCallback(workCallback), mAfterWorkCallback(afterWorkCallback)
236 14 : {}
237 :
238 : // Handler for the work callback.
239 7 : static void WorkHandler(intptr_t arg)
240 : {
241 7 : auto * helper = reinterpret_cast<WorkHelper *>(arg);
242 : // Hold strong ptr while work is handled
243 7 : auto strongPtr(std::move(helper->mStrongPtr));
244 7 : VerifyOrReturn(!helper->IsCancelled());
245 7 : bool cancel = false;
246 : // Execute callback in background thread; data must be OK with this
247 7 : helper->mStatus = helper->mWorkCallback(helper->mData, cancel);
248 7 : VerifyOrReturn(!cancel && !helper->IsCancelled());
249 : // Hold strong ptr to ourselves while work is outstanding
250 7 : helper->mStrongPtr.swap(strongPtr);
251 7 : auto status = DeviceLayer::PlatformMgr().ScheduleWork(AfterWorkHandler, reinterpret_cast<intptr_t>(helper));
252 7 : if (status != CHIP_NO_ERROR)
253 : {
254 0 : ChipLogError(SecureChannel, "Failed to Schedule the AfterWorkCallback on foreground thread: %" CHIP_ERROR_FORMAT,
255 : status.Format());
256 :
257 : // We failed to schedule after work callback, so setting mScheduleAfterWorkFailed flag to true
258 : // This can be checked from foreground thread and after work callback can be retried
259 0 : helper->mStatus = status;
260 :
261 : // Release strong ptr to self since scheduling failed, because nothing guarantees
262 : // that AfterWorkHandler will get called at this point to release the reference,
263 : // and we don't want to leak. That said, we want to ensure that "helper" stays
264 : // alive through the end of this function (so we can set mScheduleAfterWorkFailed
265 : // on it), but also want to avoid racing on the single SharedPtr instance in
266 : // helper->mStrongPtr. That means we need to not touch helper->mStrongPtr after
267 : // writing to mScheduleAfterWorkFailed.
268 : //
269 : // The simplest way to do this is to move the reference in helper->mStrongPtr to
270 : // our stack, where it outlives all our accesses to "helper".
271 0 : strongPtr.swap(helper->mStrongPtr);
272 :
273 : // helper and any of its state should not be touched after storing mScheduleAfterWorkFailed.
274 0 : helper->mScheduleAfterWorkFailed.store(true);
275 : }
276 7 : }
277 :
278 : // Handler for the after work callback.
279 7 : static void AfterWorkHandler(intptr_t arg)
280 : {
281 : // Ensure that this function is being called from main Matter thread
282 7 : assertChipStackLockedByCurrentThread();
283 :
284 7 : auto * helper = reinterpret_cast<WorkHelper *>(arg);
285 : // Hold strong ptr while work is handled, and ensure that helper->mStrongPtr does not keep
286 : // holding a reference.
287 7 : auto strongPtr(std::move(helper->mStrongPtr));
288 7 : if (!strongPtr)
289 : {
290 : // This can happen if scheduling AfterWorkHandler failed. Just grab a strong ref
291 : // to handler directly, to fulfill our API contract of holding a strong reference
292 : // across the after-work callback. At this point, we are guaranteed that the
293 : // background thread is not touching the helper anymore.
294 0 : strongPtr = helper->mWeakPtr.lock();
295 : }
296 7 : if (auto * session = helper->mSession.load())
297 : {
298 : // Execute callback in Matter thread; session should be OK with this
299 7 : (session->*(helper->mAfterWorkCallback))(helper->mData, helper->mStatus);
300 : }
301 7 : }
302 :
303 : private:
304 : // Lifetime management: `ScheduleWork` sets `mStrongPtr` from `mWeakPtr`.
305 : Platform::WeakPtr<WorkHelper> mWeakPtr;
306 :
307 : // Lifetime management: `ScheduleWork` sets `mStrongPtr` from `mWeakPtr`.
308 : Platform::SharedPtr<WorkHelper> mStrongPtr;
309 :
310 : // Associated session, cleared by `CancelWork`.
311 : std::atomic<CASESession *> mSession;
312 :
313 : // Work callback, called by `WorkHandler`.
314 : WorkCallback mWorkCallback;
315 :
316 : // After work callback, called by `AfterWorkHandler`.
317 : AfterWorkCallback mAfterWorkCallback;
318 :
319 : // Return value of `mWorkCallback`, passed to `mAfterWorkCallback`.
320 : CHIP_ERROR mStatus;
321 :
322 : // If background thread fails to schedule AfterWorkCallback then this flag is set to true
323 : // and CASEServer then can check this one and run the AfterWorkCallback for us.
324 : //
325 : // When this happens, the write to this boolean _must_ be the last code that touches this
326 : // object on the background thread. After that, the Matter thread owns the object.
327 : std::atomic<bool> mScheduleAfterWorkFailed{ false };
328 :
329 : public:
330 : // Data passed to `mWorkCallback` and `mAfterWorkCallback`.
331 : DATA mData;
332 : };
333 :
334 : struct CASESession::SendSigma3Data
335 : {
336 : FabricIndex fabricIndex;
337 :
338 : // Use one or the other
339 : const FabricTable * fabricTable;
340 : const Crypto::OperationalKeystore * keystore;
341 :
342 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Signed;
343 : size_t msg_r3_signed_len;
344 :
345 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Encrypted;
346 : size_t msg_r3_encrypted_len;
347 :
348 : chip::Platform::ScopedMemoryBuffer<uint8_t> icacBuf;
349 : MutableByteSpan icaCert;
350 :
351 : chip::Platform::ScopedMemoryBuffer<uint8_t> nocBuf;
352 : MutableByteSpan nocCert;
353 :
354 : P256ECDSASignature tbsData3Signature;
355 : };
356 :
357 : struct CASESession::HandleSigma3Data
358 : {
359 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Signed;
360 : size_t msg_r3_signed_len;
361 :
362 : ByteSpan initiatorNOC;
363 : ByteSpan initiatorICAC;
364 :
365 : uint8_t rootCertBuf[kMaxCHIPCertLength];
366 : ByteSpan fabricRCAC;
367 :
368 : P256ECDSASignature tbsData3Signature;
369 :
370 : FabricId fabricId;
371 : NodeId initiatorNodeId;
372 :
373 : ValidationContext validContext;
374 : };
375 :
376 34 : CASESession::~CASESession()
377 : {
378 : // Let's clear out any security state stored in the object, before destroying it.
379 34 : Clear();
380 34 : }
381 :
382 0 : void CASESession::OnSessionReleased()
383 : {
384 : // Call into our super-class before we clear our state.
385 0 : PairingSession::OnSessionReleased();
386 0 : Clear();
387 0 : }
388 :
389 95 : void CASESession::Clear()
390 : {
391 : MATTER_TRACE_SCOPE("Clear", "CASESession");
392 : // Cancel any outstanding work.
393 95 : if (mSendSigma3Helper)
394 : {
395 0 : mSendSigma3Helper->CancelWork();
396 0 : mSendSigma3Helper.reset();
397 : }
398 95 : if (mHandleSigma3Helper)
399 : {
400 6 : mHandleSigma3Helper->CancelWork();
401 6 : mHandleSigma3Helper.reset();
402 : }
403 :
404 : // This function zeroes out and resets the memory used by the object.
405 : // It's done so that no security related information will be leaked.
406 95 : mCommissioningHash.Clear();
407 95 : PairingSession::Clear();
408 :
409 95 : mState = State::kInitialized;
410 95 : Crypto::ClearSecretData(mIPK);
411 :
412 95 : if (mFabricsTable != nullptr)
413 : {
414 30 : mFabricsTable->RemoveFabricDelegate(this);
415 :
416 30 : mFabricsTable->ReleaseEphemeralKeypair(mEphemeralKey);
417 30 : mEphemeralKey = nullptr;
418 : }
419 :
420 95 : mLocalNodeId = kUndefinedNodeId;
421 95 : mPeerNodeId = kUndefinedNodeId;
422 95 : mFabricsTable = nullptr;
423 95 : mFabricIndex = kUndefinedFabricIndex;
424 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
425 : // Clear the context object.
426 95 : mTCPConnCbCtxt.appContext = nullptr;
427 95 : mTCPConnCbCtxt.connCompleteCb = nullptr;
428 95 : mTCPConnCbCtxt.connClosedCb = nullptr;
429 95 : mTCPConnCbCtxt.connReceivedCb = nullptr;
430 :
431 95 : if (mPeerConnState && mPeerConnState->mConnectionState != Transport::TCPState::kConnected)
432 : {
433 : // Abort the connection if the CASESession is being destroyed and the
434 : // connection is in the middle of being set up.
435 0 : mSessionManager->TCPDisconnect(mPeerConnState, /* shouldAbort = */ true);
436 0 : mPeerConnState = nullptr;
437 : }
438 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
439 95 : }
440 :
441 5 : void CASESession::InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex)
442 : {
443 5 : if (mFabricIndex != fabricIndex)
444 : {
445 1 : return;
446 : }
447 4 : if (!IsSessionEstablishmentInProgress())
448 : {
449 2 : return;
450 : }
451 2 : AbortPendingEstablish(CHIP_ERROR_CANCELLED);
452 : }
453 :
454 30 : CHIP_ERROR CASESession::Init(SessionManager & sessionManager, Credentials::CertificateValidityPolicy * policy,
455 : SessionEstablishmentDelegate * delegate, const ScopedNodeId & sessionEvictionHint)
456 : {
457 : MATTER_TRACE_SCOPE("Init", "CASESession");
458 30 : VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
459 30 : VerifyOrReturnError(mGroupDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
460 30 : VerifyOrReturnError(sessionManager.GetSessionKeystore() != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
461 :
462 30 : Clear();
463 :
464 30 : ReturnErrorOnFailure(mCommissioningHash.Begin());
465 :
466 30 : mDelegate = delegate;
467 30 : mSessionManager = &sessionManager;
468 :
469 30 : ReturnErrorOnFailure(AllocateSecureSession(sessionManager, sessionEvictionHint));
470 :
471 30 : mValidContext.Reset();
472 30 : mValidContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature);
473 30 : mValidContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth);
474 30 : mValidContext.mValidityPolicy = policy;
475 :
476 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
477 30 : mTCPConnCbCtxt.appContext = this;
478 30 : mTCPConnCbCtxt.connCompleteCb = HandleConnectionAttemptComplete;
479 30 : mTCPConnCbCtxt.connClosedCb = HandleConnectionClosed;
480 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
481 30 : return CHIP_NO_ERROR;
482 : }
483 :
484 : CHIP_ERROR
485 20 : CASESession::PrepareForSessionEstablishment(SessionManager & sessionManager, FabricTable * fabricTable,
486 : SessionResumptionStorage * sessionResumptionStorage,
487 : Credentials::CertificateValidityPolicy * policy,
488 : SessionEstablishmentDelegate * delegate, const ScopedNodeId & previouslyEstablishedPeer,
489 : Optional<ReliableMessageProtocolConfig> mrpLocalConfig)
490 : {
491 : MATTER_TRACE_SCOPE("PrepareForSessionEstablishment", "CASESession");
492 : // Below VerifyOrReturnError is not SuccessOrExit since we only want to goto `exit:` after
493 : // Init has been successfully called.
494 20 : VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
495 18 : ReturnErrorOnFailure(Init(sessionManager, policy, delegate, previouslyEstablishedPeer));
496 :
497 18 : CHIP_ERROR err = CHIP_NO_ERROR;
498 :
499 18 : SuccessOrExit(err = fabricTable->AddFabricDelegate(this));
500 :
501 18 : mFabricsTable = fabricTable;
502 18 : mRole = CryptoContext::SessionRole::kResponder;
503 18 : mSessionResumptionStorage = sessionResumptionStorage;
504 18 : mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
505 :
506 18 : ChipLogDetail(SecureChannel, "Allocated SecureSession (%p) - waiting for Sigma1 msg",
507 : mSecureSessionHolder.Get().Value()->AsSecureSession());
508 :
509 0 : exit:
510 18 : if (err != CHIP_NO_ERROR)
511 : {
512 0 : Clear();
513 : }
514 18 : return err;
515 : }
516 :
517 14 : CHIP_ERROR CASESession::EstablishSession(SessionManager & sessionManager, FabricTable * fabricTable, ScopedNodeId peerScopedNodeId,
518 : ExchangeContext * exchangeCtxt, SessionResumptionStorage * sessionResumptionStorage,
519 : Credentials::CertificateValidityPolicy * policy, SessionEstablishmentDelegate * delegate,
520 : Optional<ReliableMessageProtocolConfig> mrpLocalConfig)
521 : {
522 : MATTER_TRACE_SCOPE("EstablishSession", "CASESession");
523 14 : CHIP_ERROR err = CHIP_NO_ERROR;
524 :
525 : // Return early on error here, as we have not initialized any state yet
526 14 : VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, exchangeCtxt != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
527 12 : VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
528 :
529 : // Use FabricTable directly to avoid situation of dangling index from stale FabricInfo
530 : // until we factor-out any FabricInfo direct usage.
531 12 : VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, peerScopedNodeId.GetFabricIndex() != kUndefinedFabricIndex,
532 : CHIP_ERROR_INVALID_ARGUMENT);
533 12 : const auto * fabricInfo = fabricTable->FindFabricWithIndex(peerScopedNodeId.GetFabricIndex());
534 12 : VerifyOrReturnErrorWithMetric(kMetricDeviceCASESession, fabricInfo != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
535 :
536 12 : err = Init(sessionManager, policy, delegate, peerScopedNodeId);
537 :
538 12 : mRole = CryptoContext::SessionRole::kInitiator;
539 :
540 : // We are setting the exchange context specifically before checking for error.
541 : // This is to make sure the exchange will get closed if Init() returned an error.
542 12 : mExchangeCtxt.Emplace(*exchangeCtxt);
543 :
544 12 : Transport::PeerAddress peerAddress = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress();
545 :
546 : // From here onwards, let's go to exit on error, as some state might have already
547 : // been initialized
548 12 : SuccessOrExitWithMetric(kMetricDeviceCASESession, err);
549 :
550 12 : SuccessOrExitWithMetric(kMetricDeviceCASESession, err = fabricTable->AddFabricDelegate(this));
551 :
552 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESession);
553 :
554 : // Set the PeerAddress in the secure session up front to indicate the
555 : // Transport Type of the session that is being set up.
556 12 : mSecureSessionHolder->AsSecureSession()->SetPeerAddress(peerAddress);
557 :
558 12 : mFabricsTable = fabricTable;
559 12 : mFabricIndex = fabricInfo->GetFabricIndex();
560 12 : mSessionResumptionStorage = sessionResumptionStorage;
561 12 : mLocalMRPConfig = MakeOptional(mrpLocalConfig.ValueOr(GetDefaultMRPConfig()));
562 :
563 12 : mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedSigma1ProcessingTime);
564 12 : mPeerNodeId = peerScopedNodeId.GetNodeId();
565 12 : mLocalNodeId = fabricInfo->GetNodeId();
566 :
567 12 : ChipLogProgress(SecureChannel, "Initiating session on local FabricIndex %u from 0x" ChipLogFormatX64 " -> 0x" ChipLogFormatX64,
568 : static_cast<unsigned>(mFabricIndex), ChipLogValueX64(mLocalNodeId), ChipLogValueX64(mPeerNodeId));
569 :
570 12 : if (peerAddress.GetTransportType() == Transport::Type::kTcp)
571 : {
572 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
573 0 : err = sessionManager.TCPConnect(peerAddress, &mTCPConnCbCtxt, &mPeerConnState);
574 0 : SuccessOrExit(err);
575 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
576 : }
577 : else
578 : {
579 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma1);
580 12 : err = SendSigma1();
581 12 : SuccessOrExit(err);
582 : }
583 :
584 12 : exit:
585 12 : if (err != CHIP_NO_ERROR)
586 : {
587 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
588 : MATTER_LOG_METRIC_END(kMetricDeviceCASESession, err);
589 1 : Clear();
590 : }
591 12 : return err;
592 : }
593 :
594 0 : void CASESession::OnResponseTimeout(ExchangeContext * ec)
595 : {
596 : MATTER_TRACE_SCOPE("OnResponseTimeout", "CASESession");
597 0 : VerifyOrReturn(ec != nullptr, ChipLogError(SecureChannel, "CASESession::OnResponseTimeout was called by null exchange"));
598 0 : VerifyOrReturn(mExchangeCtxt.HasValue() && (&mExchangeCtxt.Value().Get() == ec),
599 : ChipLogError(SecureChannel, "CASESession::OnResponseTimeout exchange doesn't match"));
600 0 : ChipLogError(SecureChannel,
601 : "CASESession timed out while waiting for a response from peer " ChipLogFormatScopedNodeId ". Current state was %u",
602 : ChipLogValueScopedNodeId(GetPeer()), to_underlying(mState));
603 : MATTER_TRACE_COUNTER("CASETimeout");
604 : // Discard the exchange so that Clear() doesn't try aborting it. The
605 : // exchange will handle that.
606 0 : DiscardExchange();
607 0 : AbortPendingEstablish(CHIP_ERROR_TIMEOUT);
608 : }
609 :
610 4 : void CASESession::AbortPendingEstablish(CHIP_ERROR err)
611 : {
612 : MATTER_LOG_METRIC_END(kMetricDeviceCASESession, err);
613 : MATTER_TRACE_SCOPE("AbortPendingEstablish", "CASESession");
614 : // This needs to come before Clear() which will reset mState.
615 4 : SessionEstablishmentStage state = MapCASEStateToSessionEstablishmentStage(mState);
616 4 : Clear();
617 : // Do this last in case the delegate frees us.
618 4 : NotifySessionEstablishmentError(err, state);
619 4 : }
620 :
621 16 : CHIP_ERROR CASESession::DeriveSecureSession(CryptoContext & session)
622 : {
623 16 : switch (mState)
624 : {
625 14 : case State::kFinished: {
626 : std::array<uint8_t, sizeof(mIPK) + kSHA256_Hash_Length> msg_salt;
627 :
628 : {
629 14 : Encoding::LittleEndian::BufferWriter bbuf(msg_salt);
630 14 : bbuf.Put(mIPK, sizeof(mIPK));
631 14 : bbuf.Put(mMessageDigest, sizeof(mMessageDigest));
632 :
633 14 : VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
634 : }
635 :
636 14 : ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(),
637 : ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionEstablishment,
638 : mRole));
639 :
640 14 : return CHIP_NO_ERROR;
641 : }
642 2 : case State::kFinishedViaResume: {
643 : std::array<uint8_t, sizeof(mInitiatorRandom) + decltype(mResumeResumptionId)().size()> msg_salt;
644 :
645 : {
646 2 : Encoding::LittleEndian::BufferWriter bbuf(msg_salt);
647 2 : bbuf.Put(mInitiatorRandom, sizeof(mInitiatorRandom));
648 2 : bbuf.Put(mResumeResumptionId.data(), mResumeResumptionId.size());
649 :
650 2 : VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
651 : }
652 :
653 2 : ReturnErrorOnFailure(session.InitFromSecret(*mSessionManager->GetSessionKeystore(), mSharedSecret.Span(),
654 : ByteSpan(msg_salt), CryptoContext::SessionInfoType::kSessionResumption, mRole));
655 :
656 2 : return CHIP_NO_ERROR;
657 : }
658 0 : default:
659 0 : return CHIP_ERROR_INCORRECT_STATE;
660 : }
661 : }
662 :
663 12 : CHIP_ERROR CASESession::RecoverInitiatorIpk()
664 : {
665 12 : Credentials::GroupDataProvider::KeySet ipkKeySet;
666 :
667 12 : CHIP_ERROR err = mGroupDataProvider->GetIpkKeySet(mFabricIndex, ipkKeySet);
668 :
669 12 : if (err != CHIP_NO_ERROR)
670 : {
671 0 : ChipLogError(SecureChannel, "Failed to obtain IPK for initiating: %" CHIP_ERROR_FORMAT, err.Format());
672 0 : return err;
673 : }
674 12 : if ((ipkKeySet.num_keys_used == 0) || (ipkKeySet.num_keys_used > Credentials::GroupDataProvider::KeySet::kEpochKeysMax))
675 : {
676 0 : ChipLogError(SecureChannel, "Found invalid IPK keyset for initiator.");
677 0 : return CHIP_ERROR_INTERNAL;
678 : }
679 :
680 : // For the generation of the Destination Identifier,
681 : // the originator SHALL use the operational group key with the second oldest
682 : // EpochStartTime, if one exists, otherwise it SHALL use the single operational
683 : // group key available. The EpochStartTime are already ordered
684 12 : size_t ipkIndex = (ipkKeySet.num_keys_used > 1) ? ((ipkKeySet.num_keys_used - 1) - 1) : 0;
685 12 : memcpy(&mIPK[0], ipkKeySet.epoch_keys[ipkIndex].key, sizeof(mIPK));
686 :
687 : // Leaving this logging code for debug, but this cannot be enabled at runtime
688 : // since it leaks private security material.
689 : #if 0
690 : ChipLogProgress(SecureChannel, "RecoverInitiatorIpk: GroupDataProvider %p, Got IPK for FabricIndex %u", mGroupDataProvider,
691 : static_cast<unsigned>(mFabricIndex));
692 : ChipLogByteSpan(SecureChannel, ByteSpan(mIPK));
693 : #endif
694 :
695 12 : return CHIP_NO_ERROR;
696 : }
697 :
698 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
699 0 : void CASESession::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR err)
700 : {
701 0 : VerifyOrReturn(conn != nullptr);
702 : // conn->mAppState should not be NULL. SessionManager has already checked
703 : // before calling this callback.
704 0 : VerifyOrDie(conn->mAppState != nullptr);
705 :
706 : char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
707 0 : conn->mPeerAddr.ToString(peerAddrBuf);
708 :
709 0 : CASESession * caseSession = reinterpret_cast<CASESession *>(conn->mAppState->appContext);
710 0 : VerifyOrReturn(caseSession != nullptr);
711 :
712 : // Exit and disconnect if connection setup encountered an error.
713 0 : SuccessOrExit(err);
714 :
715 0 : ChipLogDetail(SecureChannel, "TCP Connection established with %s before session establishment", peerAddrBuf);
716 :
717 : // Associate the connection with the current unauthenticated session for the
718 : // CASE exchange.
719 0 : caseSession->mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetTCPConnection(conn);
720 :
721 : // Associate the connection with the current secure session that is being
722 : // set up.
723 0 : caseSession->mSecureSessionHolder.Get().Value()->AsSecureSession()->SetTCPConnection(conn);
724 :
725 : // Send Sigma1 after connection is established for sessions over TCP
726 0 : err = caseSession->SendSigma1();
727 0 : SuccessOrExit(err);
728 :
729 0 : exit:
730 0 : if (err != CHIP_NO_ERROR)
731 : {
732 0 : ChipLogError(SecureChannel, "Connection establishment failed with peer at %s: %" CHIP_ERROR_FORMAT, peerAddrBuf,
733 : err.Format());
734 :
735 : // Close the underlying connection and ensure that the CASESession is
736 : // not holding on to a stale ActiveTCPConnectionState. We call
737 : // TCPDisconnect() here explicitly in order to abort the connection
738 : // even after it establishes successfully, but SendSigma1() fails for
739 : // some reason.
740 0 : caseSession->mSessionManager->TCPDisconnect(conn, /* shouldAbort = */ true);
741 0 : caseSession->mPeerConnState = nullptr;
742 :
743 0 : caseSession->Clear();
744 : }
745 : }
746 :
747 0 : void CASESession::HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr)
748 : {
749 0 : VerifyOrReturn(conn != nullptr);
750 : // conn->mAppState should not be NULL. SessionManager has already checked
751 : // before calling this callback.
752 0 : VerifyOrDie(conn->mAppState != nullptr);
753 :
754 0 : CASESession * caseSession = reinterpret_cast<CASESession *>(conn->mAppState->appContext);
755 0 : VerifyOrReturn(caseSession != nullptr);
756 :
757 : // Drop our pointer to the now-invalid connection state.
758 : //
759 : // Since the connection is closed, message sends over the ExchangeContext
760 : // will just fail and be handled like normal send errors.
761 : //
762 : // Additionally, SessionManager notifies (via ExchangeMgr) all ExchangeContexts on the
763 : // connection closures for the attached sessions and the ExchangeContexts
764 : // can close proactively if that's appropriate.
765 0 : caseSession->mPeerConnState = nullptr;
766 0 : ChipLogDetail(SecureChannel, "TCP Connection for this session has closed");
767 : }
768 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
769 :
770 12 : CHIP_ERROR CASESession::SendSigma1()
771 : {
772 : MATTER_TRACE_SCOPE("SendSigma1", "CASESession");
773 12 : size_t data_len = TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, // initiatorRandom
774 : sizeof(uint16_t), // initiatorSessionId,
775 : kSHA256_Hash_Length, // destinationId
776 : kP256_PublicKey_Length, // InitiatorEphPubKey,
777 : SessionParameters::kEstimatedTLVSize, // initiatorSessionParams
778 : SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
779 :
780 12 : System::PacketBufferTLVWriter tlvWriter;
781 12 : System::PacketBufferHandle msg_R1;
782 12 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
783 12 : uint8_t destinationIdentifier[kSHA256_Hash_Length] = { 0 };
784 :
785 : // Lookup fabric info.
786 12 : const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
787 12 : VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
788 :
789 : // Validate that we have a session ID allocated.
790 12 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
791 :
792 : // Generate an ephemeral keypair
793 12 : mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE();
794 12 : VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY);
795 12 : ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH));
796 :
797 : // Fill in the random value
798 12 : ReturnErrorOnFailure(DRBG_get_bytes(mInitiatorRandom, sizeof(mInitiatorRandom)));
799 :
800 : // Construct Sigma1 Msg
801 12 : msg_R1 = System::PacketBufferHandle::New(data_len);
802 12 : VerifyOrReturnError(!msg_R1.IsNull(), CHIP_ERROR_NO_MEMORY);
803 :
804 12 : tlvWriter.Init(std::move(msg_R1));
805 12 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
806 12 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), ByteSpan(mInitiatorRandom)));
807 : // Retrieve Session Identifier
808 12 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), GetLocalSessionId().Value()));
809 :
810 : // Generate a Destination Identifier based on the node we are attempting to reach
811 : {
812 : // Obtain originator IPK matching the fabric where we are trying to open a session. mIPK
813 : // will be properly set thereafter.
814 12 : ReturnErrorOnFailure(RecoverInitiatorIpk());
815 :
816 12 : FabricId fabricId = fabricInfo->GetFabricId();
817 12 : Crypto::P256PublicKey rootPubKey;
818 12 : ReturnErrorOnFailure(mFabricsTable->FetchRootPubkey(mFabricIndex, rootPubKey));
819 12 : Credentials::P256PublicKeySpan rootPubKeySpan{ rootPubKey.ConstBytes() };
820 :
821 12 : MutableByteSpan destinationIdSpan(destinationIdentifier);
822 12 : ReturnErrorOnFailure(GenerateCaseDestinationId(ByteSpan(mIPK), ByteSpan(mInitiatorRandom), rootPubKeySpan, fabricId,
823 : mPeerNodeId, destinationIdSpan));
824 12 : }
825 12 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(3), destinationIdentifier, sizeof(destinationIdentifier)));
826 :
827 12 : ReturnErrorOnFailure(
828 : tlvWriter.PutBytes(TLV::ContextTag(4), mEphemeralKey->Pubkey(), static_cast<uint32_t>(mEphemeralKey->Pubkey().Length())));
829 :
830 12 : VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
831 12 : ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter));
832 :
833 : // Try to find persistent session, and resume it.
834 12 : bool resuming = false;
835 12 : if (mSessionResumptionStorage != nullptr)
836 : {
837 4 : CHIP_ERROR err = mSessionResumptionStorage->FindByScopedNodeId(fabricInfo->GetScopedNodeIdForNode(mPeerNodeId),
838 4 : mResumeResumptionId, mSharedSecret, mPeerCATs);
839 4 : if (err == CHIP_NO_ERROR)
840 : {
841 : // Found valid resumption state, try to resume the session.
842 3 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(6), mResumeResumptionId));
843 :
844 : uint8_t initiatorResume1MIC[CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES];
845 3 : MutableByteSpan resumeMICSpan(initiatorResume1MIC);
846 3 : ReturnErrorOnFailure(GenerateSigmaResumeMIC(ByteSpan(mInitiatorRandom), ByteSpan(mResumeResumptionId),
847 : ByteSpan(kKDFS1RKeyInfo), ByteSpan(kResume1MIC_Nonce), resumeMICSpan));
848 :
849 3 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(7), resumeMICSpan));
850 3 : resuming = true;
851 : }
852 : }
853 :
854 12 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
855 12 : ReturnErrorOnFailure(tlvWriter.Finalize(&msg_R1));
856 :
857 12 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msg_R1->Start(), msg_R1->DataLength() }));
858 :
859 : // Call delegate to send the msg to peer
860 12 : ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma1, std::move(msg_R1),
861 : SendFlags(SendMessageFlags::kExpectResponse)));
862 :
863 11 : if (resuming)
864 : {
865 3 : mState = State::kSentSigma1Resume;
866 :
867 : // Flags that Resume is being attempted
868 : MATTER_LOG_METRIC(kMetricDeviceCASESessionSigma1Resume);
869 : }
870 : else
871 : {
872 8 : mState = State::kSentSigma1;
873 : }
874 :
875 : #if CHIP_PROGRESS_LOGGING
876 11 : const auto localMRPConfig = mLocalMRPConfig.Value();
877 : #endif // CHIP_PROGRESS_LOGGING
878 11 : ChipLogProgress(SecureChannel, "Sent Sigma1 msg to " ChipLogFormatScopedNodeId " [II:%" PRIu32 "ms AI:%" PRIu32 "ms AT:%ums]",
879 : ChipLogValueScopedNodeId(GetPeer()), localMRPConfig.mIdleRetransTimeout.count(),
880 : localMRPConfig.mActiveRetransTimeout.count(), localMRPConfig.mActiveThresholdTime.count());
881 :
882 11 : mDelegate->OnSessionEstablishmentStarted();
883 :
884 11 : return CHIP_NO_ERROR;
885 12 : }
886 :
887 10 : CHIP_ERROR CASESession::HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg)
888 : {
889 : MATTER_TRACE_SCOPE("HandleSigma1_and_SendSigma2", "CASESession");
890 10 : ReturnErrorOnFailure(HandleSigma1(std::move(msg)));
891 :
892 9 : return CHIP_NO_ERROR;
893 : }
894 :
895 9 : CHIP_ERROR CASESession::FindLocalNodeFromDestinationId(const ByteSpan & destinationId, const ByteSpan & initiatorRandom)
896 : {
897 : MATTER_TRACE_SCOPE("FindLocalNodeFromDestinationId", "CASESession");
898 9 : VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
899 :
900 9 : bool found = false;
901 10 : for (const FabricInfo & fabricInfo : *mFabricsTable)
902 : {
903 : // Basic data for candidate fabric, used to compute candidate destination identifiers
904 9 : FabricId fabricId = fabricInfo.GetFabricId();
905 9 : NodeId nodeId = fabricInfo.GetNodeId();
906 9 : Crypto::P256PublicKey rootPubKey;
907 9 : ReturnErrorOnFailure(mFabricsTable->FetchRootPubkey(fabricInfo.GetFabricIndex(), rootPubKey));
908 9 : Credentials::P256PublicKeySpan rootPubKeySpan{ rootPubKey.ConstBytes() };
909 :
910 : // Get IPK operational group key set for current candidate fabric
911 9 : GroupDataProvider::KeySet ipkKeySet;
912 9 : CHIP_ERROR err = mGroupDataProvider->GetIpkKeySet(fabricInfo.GetFabricIndex(), ipkKeySet);
913 18 : if ((err != CHIP_NO_ERROR) ||
914 9 : ((ipkKeySet.num_keys_used == 0) || (ipkKeySet.num_keys_used > Credentials::GroupDataProvider::KeySet::kEpochKeysMax)))
915 : {
916 0 : continue;
917 : }
918 :
919 : // Try every IPK candidate we have for a match
920 10 : for (size_t keyIdx = 0; keyIdx < ipkKeySet.num_keys_used; ++keyIdx)
921 : {
922 : uint8_t candidateDestinationId[kSHA256_Hash_Length];
923 9 : MutableByteSpan candidateDestinationIdSpan(candidateDestinationId);
924 9 : ByteSpan candidateIpkSpan(ipkKeySet.epoch_keys[keyIdx].key);
925 :
926 9 : err = GenerateCaseDestinationId(ByteSpan(candidateIpkSpan), ByteSpan(initiatorRandom), rootPubKeySpan, fabricId, nodeId,
927 : candidateDestinationIdSpan);
928 9 : if ((err == CHIP_NO_ERROR) && (candidateDestinationIdSpan.data_equal(destinationId)))
929 : {
930 : // Found a match, stop working, cache IPK, update local fabric context
931 8 : found = true;
932 8 : MutableByteSpan ipkSpan(mIPK);
933 8 : CopySpanToMutableSpan(candidateIpkSpan, ipkSpan);
934 8 : mFabricIndex = fabricInfo.GetFabricIndex();
935 8 : mLocalNodeId = nodeId;
936 8 : break;
937 : }
938 : }
939 :
940 9 : if (found)
941 : {
942 8 : break;
943 : }
944 9 : }
945 :
946 9 : return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
947 : }
948 :
949 3 : CHIP_ERROR CASESession::TryResumeSession(SessionResumptionStorage::ConstResumptionIdView resumptionId, ByteSpan resume1MIC,
950 : ByteSpan initiatorRandom)
951 : {
952 : MATTER_TRACE_SCOPE("TryResumeSession", "CASESession");
953 3 : VerifyOrReturnError(mSessionResumptionStorage != nullptr, CHIP_ERROR_INCORRECT_STATE);
954 3 : VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
955 :
956 3 : SessionResumptionStorage::ConstResumptionIdView resumptionIdSpan(resumptionId);
957 3 : ScopedNodeId node;
958 3 : ReturnErrorOnFailure(mSessionResumptionStorage->FindByResumptionId(resumptionIdSpan, node, mSharedSecret, mPeerCATs));
959 :
960 : // Cross check resume1MIC with the shared secret
961 2 : ReturnErrorOnFailure(
962 : ValidateSigmaResumeMIC(resume1MIC, initiatorRandom, resumptionId, ByteSpan(kKDFS1RKeyInfo), ByteSpan(kResume1MIC_Nonce)));
963 :
964 1 : const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(node.GetFabricIndex());
965 1 : VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE);
966 :
967 1 : mFabricIndex = node.GetFabricIndex();
968 1 : mPeerNodeId = node.GetNodeId();
969 1 : mLocalNodeId = fabricInfo->GetNodeId();
970 :
971 1 : return CHIP_NO_ERROR;
972 : }
973 :
974 10 : CHIP_ERROR CASESession::HandleSigma1(System::PacketBufferHandle && msg)
975 : {
976 : MATTER_TRACE_SCOPE("HandleSigma1", "CASESession");
977 10 : CHIP_ERROR err = CHIP_NO_ERROR;
978 10 : System::PacketBufferTLVReader tlvReader;
979 :
980 : uint16_t initiatorSessionId;
981 10 : ByteSpan destinationIdentifier;
982 10 : ByteSpan initiatorRandom;
983 :
984 10 : ChipLogProgress(SecureChannel, "Received Sigma1 msg");
985 : MATTER_TRACE_COUNTER("Sigma1");
986 :
987 10 : bool sessionResumptionRequested = false;
988 10 : ByteSpan resumptionId;
989 10 : ByteSpan resume1MIC;
990 10 : ByteSpan initiatorPubKey;
991 :
992 10 : SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() }));
993 :
994 10 : tlvReader.Init(std::move(msg));
995 10 : SuccessOrExit(err = ParseSigma1(tlvReader, initiatorRandom, initiatorSessionId, destinationIdentifier, initiatorPubKey,
996 : sessionResumptionRequested, resumptionId, resume1MIC));
997 :
998 10 : ChipLogDetail(SecureChannel, "Peer assigned session key ID %d", initiatorSessionId);
999 10 : SetPeerSessionId(initiatorSessionId);
1000 :
1001 10 : VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1002 :
1003 13 : if (sessionResumptionRequested && resumptionId.size() == SessionResumptionStorage::kResumptionIdSize &&
1004 3 : CHIP_NO_ERROR ==
1005 13 : TryResumeSession(SessionResumptionStorage::ConstResumptionIdView(resumptionId.data()), resume1MIC, initiatorRandom))
1006 : {
1007 1 : std::copy(initiatorRandom.begin(), initiatorRandom.end(), mInitiatorRandom);
1008 1 : std::copy(resumptionId.begin(), resumptionId.end(), mResumeResumptionId.begin());
1009 :
1010 : // Send Sigma2Resume message to the initiator
1011 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2Resume);
1012 1 : err = SendSigma2Resume();
1013 1 : if (CHIP_NO_ERROR != err)
1014 : {
1015 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2Resume, err);
1016 : }
1017 1 : SuccessOrExit(err);
1018 :
1019 1 : mDelegate->OnSessionEstablishmentStarted();
1020 :
1021 : // Early returning here, since we have sent Sigma2Resume, and no further processing is needed for the Sigma1 message
1022 1 : return CHIP_NO_ERROR;
1023 : }
1024 :
1025 : // Attempt to match the initiator's desired destination based on local fabric table.
1026 9 : err = FindLocalNodeFromDestinationId(destinationIdentifier, initiatorRandom);
1027 9 : if (err == CHIP_NO_ERROR)
1028 : {
1029 8 : ChipLogProgress(SecureChannel, "CASE matched destination ID: fabricIndex %u, NodeID 0x" ChipLogFormatX64,
1030 : static_cast<unsigned>(mFabricIndex), ChipLogValueX64(mLocalNodeId));
1031 :
1032 : // Side-effect of FindLocalNodeFromDestinationId success was that mFabricIndex/mLocalNodeId are now
1033 : // set to the local fabric and associated NodeId that was targeted by the initiator.
1034 : }
1035 : else
1036 : {
1037 1 : ChipLogError(SecureChannel, "CASE failed to match destination ID with local fabrics");
1038 1 : ChipLogByteSpan(SecureChannel, destinationIdentifier);
1039 : }
1040 9 : SuccessOrExit(err);
1041 :
1042 : // ParseSigma1 ensures that:
1043 : // mRemotePubKey.Length() == initiatorPubKey.size() == kP256_PublicKey_Length.
1044 8 : memcpy(mRemotePubKey.Bytes(), initiatorPubKey.data(), mRemotePubKey.Length());
1045 :
1046 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2);
1047 8 : err = SendSigma2();
1048 8 : if (CHIP_NO_ERROR != err)
1049 : {
1050 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err);
1051 : }
1052 8 : SuccessOrExit(err);
1053 :
1054 8 : mDelegate->OnSessionEstablishmentStarted();
1055 :
1056 9 : exit:
1057 :
1058 9 : if (err == CHIP_ERROR_KEY_NOT_FOUND)
1059 : {
1060 1 : SendStatusReport(mExchangeCtxt, kProtocolCodeNoSharedRoot);
1061 1 : mState = State::kInitialized;
1062 : }
1063 8 : else if (err != CHIP_NO_ERROR)
1064 : {
1065 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1066 0 : mState = State::kInitialized;
1067 : }
1068 9 : return err;
1069 10 : }
1070 :
1071 1 : CHIP_ERROR CASESession::SendSigma2Resume()
1072 : {
1073 : MATTER_TRACE_SCOPE("SendSigma2Resume", "CASESession");
1074 1 : size_t max_sigma2_resume_data_len =
1075 : TLV::EstimateStructOverhead(SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,
1076 : sizeof(uint16_t), SessionParameters::kEstimatedTLVSize);
1077 :
1078 1 : System::PacketBufferTLVWriter tlvWriter;
1079 1 : System::PacketBufferHandle msg_R2_resume;
1080 1 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
1081 :
1082 : // Validate that we have a session ID allocated.
1083 1 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
1084 :
1085 1 : msg_R2_resume = System::PacketBufferHandle::New(max_sigma2_resume_data_len);
1086 1 : VerifyOrReturnError(!msg_R2_resume.IsNull(), CHIP_ERROR_NO_MEMORY);
1087 :
1088 1 : tlvWriter.Init(std::move(msg_R2_resume));
1089 :
1090 : // Generate a new resumption ID
1091 1 : ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size()));
1092 :
1093 1 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
1094 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), mNewResumptionId));
1095 :
1096 : uint8_t sigma2ResumeMIC[CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES];
1097 1 : MutableByteSpan resumeMICSpan(sigma2ResumeMIC);
1098 1 : ReturnErrorOnFailure(GenerateSigmaResumeMIC(ByteSpan(mInitiatorRandom), mNewResumptionId, ByteSpan(kKDFS2RKeyInfo),
1099 : ByteSpan(kResume2MIC_Nonce), resumeMICSpan));
1100 :
1101 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), resumeMICSpan));
1102 :
1103 1 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), GetLocalSessionId().Value()));
1104 :
1105 1 : VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
1106 1 : ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(4), mLocalMRPConfig.Value(), tlvWriter));
1107 :
1108 1 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
1109 1 : ReturnErrorOnFailure(tlvWriter.Finalize(&msg_R2_resume));
1110 :
1111 : // Call delegate to send the msg to peer
1112 1 : ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2Resume,
1113 : std::move(msg_R2_resume),
1114 : SendFlags(SendMessageFlags::kExpectResponse)));
1115 :
1116 1 : mState = State::kSentSigma2Resume;
1117 :
1118 1 : ChipLogDetail(SecureChannel, "Sent Sigma2Resume msg");
1119 :
1120 1 : return CHIP_NO_ERROR;
1121 1 : }
1122 :
1123 8 : CHIP_ERROR CASESession::SendSigma2()
1124 : {
1125 : MATTER_TRACE_SCOPE("SendSigma2", "CASESession");
1126 :
1127 8 : VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE);
1128 8 : VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
1129 :
1130 8 : chip::Platform::ScopedMemoryBuffer<uint8_t> icacBuf;
1131 8 : VerifyOrReturnError(icacBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
1132 :
1133 8 : chip::Platform::ScopedMemoryBuffer<uint8_t> nocBuf;
1134 8 : VerifyOrReturnError(nocBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY);
1135 :
1136 8 : MutableByteSpan icaCert{ icacBuf.Get(), kMaxCHIPCertLength };
1137 8 : ReturnErrorOnFailure(mFabricsTable->FetchICACert(mFabricIndex, icaCert));
1138 :
1139 8 : MutableByteSpan nocCert{ nocBuf.Get(), kMaxCHIPCertLength };
1140 8 : ReturnErrorOnFailure(mFabricsTable->FetchNOCCert(mFabricIndex, nocCert));
1141 :
1142 : // Fill in the random value
1143 : uint8_t msg_rand[kSigmaParamRandomNumberSize];
1144 8 : ReturnErrorOnFailure(DRBG_get_bytes(&msg_rand[0], sizeof(msg_rand)));
1145 :
1146 : // Generate an ephemeral keypair
1147 8 : mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE();
1148 8 : VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY);
1149 8 : ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH));
1150 :
1151 : // Generate a Shared Secret
1152 8 : ReturnErrorOnFailure(mEphemeralKey->ECDH_derive_secret(mRemotePubKey, mSharedSecret));
1153 :
1154 : uint8_t msg_salt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length];
1155 :
1156 8 : MutableByteSpan saltSpan(msg_salt);
1157 8 : ReturnErrorOnFailure(ConstructSaltSigma2(ByteSpan(msg_rand), mEphemeralKey->Pubkey(), ByteSpan(mIPK), saltSpan));
1158 :
1159 8 : AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore());
1160 8 : ReturnErrorOnFailure(DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k));
1161 :
1162 : // Construct Sigma2 TBS Data
1163 8 : size_t msg_r2_signed_len =
1164 : TLV::EstimateStructOverhead(kMaxCHIPCertLength, kMaxCHIPCertLength, kP256_PublicKey_Length, kP256_PublicKey_Length);
1165 :
1166 8 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Signed;
1167 8 : VerifyOrReturnError(msg_R2_Signed.Alloc(msg_r2_signed_len), CHIP_ERROR_NO_MEMORY);
1168 :
1169 8 : ReturnErrorOnFailure(ConstructTBSData(nocCert, icaCert, ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
1170 : ByteSpan(mRemotePubKey, mRemotePubKey.Length()), msg_R2_Signed.Get(), msg_r2_signed_len));
1171 :
1172 : // Generate a Signature
1173 8 : P256ECDSASignature tbsData2Signature;
1174 8 : ReturnErrorOnFailure(
1175 : mFabricsTable->SignWithOpKeypair(mFabricIndex, ByteSpan{ msg_R2_Signed.Get(), msg_r2_signed_len }, tbsData2Signature));
1176 8 : msg_R2_Signed.Free();
1177 :
1178 : // Construct Sigma2 TBE Data
1179 8 : size_t msg_r2_signed_enc_len = TLV::EstimateStructOverhead(nocCert.size(), icaCert.size(), tbsData2Signature.Length(),
1180 : SessionResumptionStorage::kResumptionIdSize);
1181 :
1182 8 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Encrypted;
1183 8 : VerifyOrReturnError(msg_R2_Encrypted.Alloc(msg_r2_signed_enc_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES), CHIP_ERROR_NO_MEMORY);
1184 :
1185 8 : TLV::TLVWriter tlvWriter;
1186 8 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
1187 :
1188 8 : tlvWriter.Init(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len);
1189 8 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
1190 8 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderNOC), nocCert));
1191 8 : if (!icaCert.empty())
1192 : {
1193 8 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderICAC), icaCert));
1194 : }
1195 :
1196 : // We are now done with ICAC and NOC certs so we can release the memory.
1197 : {
1198 8 : icacBuf.Free();
1199 8 : icaCert = MutableByteSpan{};
1200 :
1201 8 : nocBuf.Free();
1202 8 : nocCert = MutableByteSpan{};
1203 : }
1204 :
1205 8 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kTag_TBEData_Signature), tbsData2Signature.ConstBytes(),
1206 : static_cast<uint32_t>(tbsData2Signature.Length())));
1207 :
1208 : // Generate a new resumption ID
1209 8 : ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size()));
1210 8 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_ResumptionID), mNewResumptionId));
1211 :
1212 8 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
1213 8 : ReturnErrorOnFailure(tlvWriter.Finalize());
1214 8 : msg_r2_signed_enc_len = static_cast<size_t>(tlvWriter.GetLengthWritten());
1215 :
1216 : // Generate the encrypted data blob
1217 8 : ReturnErrorOnFailure(AES_CCM_encrypt(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len, nullptr, 0, sr2k.KeyHandle(),
1218 : kTBEData2_Nonce, kTBEDataNonceLength, msg_R2_Encrypted.Get(),
1219 : msg_R2_Encrypted.Get() + msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
1220 :
1221 : // Construct Sigma2 Msg
1222 8 : size_t size_of_local_session_id = sizeof(uint16_t);
1223 : size_t data_len =
1224 8 : TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, size_of_local_session_id, kP256_PublicKey_Length,
1225 : msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, SessionParameters::kEstimatedTLVSize);
1226 :
1227 8 : System::PacketBufferHandle msg_R2 = System::PacketBufferHandle::New(data_len);
1228 8 : VerifyOrReturnError(!msg_R2.IsNull(), CHIP_ERROR_NO_MEMORY);
1229 :
1230 8 : System::PacketBufferTLVWriter tlvWriterMsg2;
1231 8 : outerContainerType = TLV::kTLVType_NotSpecified;
1232 :
1233 8 : tlvWriterMsg2.Init(std::move(msg_R2));
1234 8 : ReturnErrorOnFailure(tlvWriterMsg2.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
1235 8 : ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(1), &msg_rand[0], sizeof(msg_rand)));
1236 8 : ReturnErrorOnFailure(tlvWriterMsg2.Put(TLV::ContextTag(2), GetLocalSessionId().Value()));
1237 8 : ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(3), mEphemeralKey->Pubkey(),
1238 : static_cast<uint32_t>(mEphemeralKey->Pubkey().Length())));
1239 8 : ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(4), msg_R2_Encrypted.Get(),
1240 : static_cast<uint32_t>(msg_r2_signed_enc_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)));
1241 :
1242 8 : VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE);
1243 8 : ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriterMsg2));
1244 :
1245 8 : ReturnErrorOnFailure(tlvWriterMsg2.EndContainer(outerContainerType));
1246 8 : ReturnErrorOnFailure(tlvWriterMsg2.Finalize(&msg_R2));
1247 :
1248 8 : ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msg_R2->Start(), msg_R2->DataLength() }));
1249 :
1250 : // Call delegate to send the msg to peer
1251 8 : ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2, std::move(msg_R2),
1252 : SendFlags(SendMessageFlags::kExpectResponse)));
1253 :
1254 8 : mState = State::kSentSigma2;
1255 :
1256 8 : ChipLogProgress(SecureChannel, "Sent Sigma2 msg");
1257 : MATTER_TRACE_COUNTER("Sigma2");
1258 :
1259 8 : return CHIP_NO_ERROR;
1260 8 : }
1261 :
1262 1 : CHIP_ERROR CASESession::HandleSigma2Resume(System::PacketBufferHandle && msg)
1263 : {
1264 : MATTER_TRACE_SCOPE("HandleSigma2Resume", "CASESession");
1265 1 : CHIP_ERROR err = CHIP_NO_ERROR;
1266 1 : System::PacketBufferTLVReader tlvReader;
1267 1 : TLV::TLVType containerType = TLV::kTLVType_Structure;
1268 :
1269 : uint16_t responderSessionId;
1270 :
1271 1 : uint32_t decodeTagIdSeq = 0;
1272 :
1273 1 : ChipLogDetail(SecureChannel, "Received Sigma2Resume msg");
1274 : MATTER_TRACE_COUNTER("Sigma2Resume");
1275 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
1276 :
1277 : uint8_t sigma2ResumeMIC[CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES];
1278 :
1279 1 : tlvReader.Init(std::move(msg));
1280 1 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
1281 1 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
1282 :
1283 1 : SuccessOrExit(err = tlvReader.Next());
1284 1 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
1285 : SessionResumptionStorage::ResumptionIdStorage resumptionId;
1286 1 : VerifyOrExit(tlvReader.GetLength() == resumptionId.size(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1287 1 : SuccessOrExit(err = tlvReader.GetBytes(resumptionId.data(), resumptionId.size()));
1288 :
1289 1 : SuccessOrExit(err = tlvReader.Next());
1290 1 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
1291 1 : VerifyOrExit(tlvReader.GetLength() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1292 1 : SuccessOrExit(err = tlvReader.GetBytes(sigma2ResumeMIC, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
1293 :
1294 1 : SuccessOrExit(err = ValidateSigmaResumeMIC(ByteSpan(sigma2ResumeMIC), ByteSpan(mInitiatorRandom), resumptionId,
1295 : ByteSpan(kKDFS2RKeyInfo), ByteSpan(kResume2MIC_Nonce)));
1296 :
1297 1 : SuccessOrExit(err = tlvReader.Next());
1298 1 : VerifyOrExit(TLV::TagNumFromTag(tlvReader.GetTag()) == ++decodeTagIdSeq, err = CHIP_ERROR_INVALID_TLV_TAG);
1299 1 : SuccessOrExit(err = tlvReader.Get(responderSessionId));
1300 :
1301 1 : if (tlvReader.Next() != CHIP_END_OF_TLV)
1302 : {
1303 1 : SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(4), tlvReader));
1304 1 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
1305 : GetRemoteSessionParameters());
1306 : }
1307 :
1308 1 : ChipLogDetail(SecureChannel, "Peer assigned session session ID %d", responderSessionId);
1309 1 : SetPeerSessionId(responderSessionId);
1310 :
1311 1 : if (mSessionResumptionStorage != nullptr)
1312 : {
1313 1 : CHIP_ERROR err2 = mSessionResumptionStorage->Save(GetPeer(), resumptionId, mSharedSecret, mPeerCATs);
1314 1 : if (err2 != CHIP_NO_ERROR)
1315 0 : ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
1316 : }
1317 :
1318 : MATTER_LOG_METRIC(kMetricDeviceCASESessionSigmaFinished);
1319 1 : SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
1320 :
1321 1 : mState = State::kFinishedViaResume;
1322 1 : Finish();
1323 :
1324 1 : exit:
1325 1 : if (err != CHIP_NO_ERROR)
1326 : {
1327 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1328 : }
1329 1 : return err;
1330 1 : }
1331 :
1332 7 : CHIP_ERROR CASESession::HandleSigma2_and_SendSigma3(System::PacketBufferHandle && msg)
1333 : {
1334 : MATTER_TRACE_SCOPE("HandleSigma2_and_SendSigma3", "CASESession");
1335 7 : CHIP_ERROR err = HandleSigma2(std::move(msg));
1336 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
1337 7 : ReturnErrorOnFailure(err);
1338 :
1339 : MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma3);
1340 7 : err = SendSigma3a();
1341 7 : if (CHIP_NO_ERROR != err)
1342 : {
1343 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma3, err);
1344 : }
1345 7 : return err;
1346 : }
1347 :
1348 7 : CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg)
1349 : {
1350 : MATTER_TRACE_SCOPE("HandleSigma2", "CASESession");
1351 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1352 7 : System::PacketBufferTLVReader tlvReader;
1353 7 : TLV::TLVReader decryptedDataTlvReader;
1354 7 : TLV::TLVType containerType = TLV::kTLVType_Structure;
1355 :
1356 7 : const uint8_t * buf = msg->Start();
1357 7 : size_t buflen = msg->DataLength();
1358 :
1359 : uint8_t msg_salt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length];
1360 :
1361 7 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Encrypted;
1362 7 : size_t msg_r2_encrypted_len = 0;
1363 7 : size_t msg_r2_encrypted_len_with_tag = 0;
1364 :
1365 7 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Signed;
1366 : size_t msg_r2_signed_len;
1367 : size_t max_msg_r2_signed_enc_len;
1368 7 : constexpr size_t kCaseOverheadForFutureTbeData = 128;
1369 :
1370 7 : AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore());
1371 :
1372 7 : P256ECDSASignature tbsData2Signature;
1373 :
1374 : NodeId responderNodeId;
1375 7 : P256PublicKey responderPublicKey;
1376 :
1377 : uint8_t responderRandom[kSigmaParamRandomNumberSize];
1378 7 : ByteSpan responderNOC;
1379 7 : ByteSpan responderICAC;
1380 :
1381 : uint16_t responderSessionId;
1382 :
1383 7 : ChipLogProgress(SecureChannel, "Received Sigma2 msg");
1384 :
1385 7 : FabricId fabricId = kUndefinedFabricId;
1386 : {
1387 7 : VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1388 7 : const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
1389 7 : VerifyOrExit(fabricInfo != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1390 7 : fabricId = fabricInfo->GetFabricId();
1391 : }
1392 :
1393 7 : VerifyOrExit(mEphemeralKey != nullptr, err = CHIP_ERROR_INTERNAL);
1394 7 : VerifyOrExit(buf != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
1395 :
1396 7 : tlvReader.Init(std::move(msg));
1397 7 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
1398 7 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
1399 :
1400 : // Retrieve Responder's Random value
1401 7 : SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_ResponderRandom)));
1402 7 : SuccessOrExit(err = tlvReader.GetBytes(responderRandom, sizeof(responderRandom)));
1403 :
1404 : // Assign Session ID
1405 7 : SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_UnsignedInteger, TLV::ContextTag(kTag_Sigma2_ResponderSessionId)));
1406 7 : SuccessOrExit(err = tlvReader.Get(responderSessionId));
1407 :
1408 7 : ChipLogDetail(SecureChannel, "Peer assigned session session ID %d", responderSessionId);
1409 7 : SetPeerSessionId(responderSessionId);
1410 :
1411 : // Retrieve Responder's Ephemeral Pubkey
1412 7 : SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_ResponderEphPubKey)));
1413 7 : SuccessOrExit(err = tlvReader.GetBytes(mRemotePubKey, static_cast<uint32_t>(mRemotePubKey.Length())));
1414 :
1415 : // Generate a Shared Secret
1416 7 : SuccessOrExit(err = mEphemeralKey->ECDH_derive_secret(mRemotePubKey, mSharedSecret));
1417 :
1418 : // Generate the S2K key
1419 : {
1420 7 : MutableByteSpan saltSpan(msg_salt);
1421 7 : SuccessOrExit(err = ConstructSaltSigma2(ByteSpan(responderRandom), mRemotePubKey, ByteSpan(mIPK), saltSpan));
1422 7 : SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k));
1423 : }
1424 :
1425 7 : SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, buflen }));
1426 :
1427 : // Generate decrypted data
1428 7 : SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_Encrypted2)));
1429 :
1430 : max_msg_r2_signed_enc_len =
1431 7 : TLV::EstimateStructOverhead(Credentials::kMaxCHIPCertLength, Credentials::kMaxCHIPCertLength, tbsData2Signature.Length(),
1432 : SessionResumptionStorage::kResumptionIdSize, kCaseOverheadForFutureTbeData);
1433 7 : msg_r2_encrypted_len_with_tag = tlvReader.GetLength();
1434 :
1435 : // Validate we did not receive a buffer larger than legal
1436 7 : VerifyOrExit(msg_r2_encrypted_len_with_tag <= max_msg_r2_signed_enc_len, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1437 7 : VerifyOrExit(msg_r2_encrypted_len_with_tag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1438 7 : VerifyOrExit(msg_R2_Encrypted.Alloc(msg_r2_encrypted_len_with_tag), err = CHIP_ERROR_NO_MEMORY);
1439 :
1440 7 : SuccessOrExit(err = tlvReader.GetBytes(msg_R2_Encrypted.Get(), static_cast<uint32_t>(msg_r2_encrypted_len_with_tag)));
1441 7 : msg_r2_encrypted_len = msg_r2_encrypted_len_with_tag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES;
1442 :
1443 7 : SuccessOrExit(err = AES_CCM_decrypt(msg_R2_Encrypted.Get(), msg_r2_encrypted_len, nullptr, 0,
1444 : msg_R2_Encrypted.Get() + msg_r2_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,
1445 : sr2k.KeyHandle(), kTBEData2_Nonce, kTBEDataNonceLength, msg_R2_Encrypted.Get()));
1446 :
1447 7 : decryptedDataTlvReader.Init(msg_R2_Encrypted.Get(), msg_r2_encrypted_len);
1448 7 : containerType = TLV::kTLVType_Structure;
1449 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(containerType, TLV::AnonymousTag()));
1450 7 : SuccessOrExit(err = decryptedDataTlvReader.EnterContainer(containerType));
1451 :
1452 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_SenderNOC)));
1453 7 : SuccessOrExit(err = decryptedDataTlvReader.Get(responderNOC));
1454 :
1455 7 : SuccessOrExit(err = decryptedDataTlvReader.Next());
1456 7 : if (TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_SenderICAC)
1457 : {
1458 7 : VerifyOrExit(decryptedDataTlvReader.GetType() == TLV::kTLVType_ByteString, err = CHIP_ERROR_WRONG_TLV_TYPE);
1459 7 : SuccessOrExit(err = decryptedDataTlvReader.Get(responderICAC));
1460 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_Signature)));
1461 : }
1462 :
1463 : // Validate responder identity located in msg_r2_encrypted
1464 : // Constructing responder identity
1465 : {
1466 : CompressedFabricId unused;
1467 : FabricId responderFabricId;
1468 7 : SuccessOrExit(err = SetEffectiveTime());
1469 7 : SuccessOrExit(err = mFabricsTable->VerifyCredentials(mFabricIndex, responderNOC, responderICAC, mValidContext, unused,
1470 : responderFabricId, responderNodeId, responderPublicKey));
1471 7 : VerifyOrExit(fabricId == responderFabricId, err = CHIP_ERROR_INVALID_CASE_PARAMETER);
1472 : // Verify that responderNodeId (from responderNOC) matches one that was included
1473 : // in the computation of the Destination Identifier when generating Sigma1.
1474 7 : VerifyOrExit(mPeerNodeId == responderNodeId, err = CHIP_ERROR_INVALID_CASE_PARAMETER);
1475 : }
1476 :
1477 : // Construct msg_R2_Signed and validate the signature in msg_r2_encrypted
1478 7 : msg_r2_signed_len = TLV::EstimateStructOverhead(sizeof(uint16_t), responderNOC.size(), responderICAC.size(),
1479 : kP256_PublicKey_Length, kP256_PublicKey_Length);
1480 :
1481 7 : VerifyOrExit(msg_R2_Signed.Alloc(msg_r2_signed_len), err = CHIP_ERROR_NO_MEMORY);
1482 :
1483 7 : SuccessOrExit(err = ConstructTBSData(responderNOC, responderICAC, ByteSpan(mRemotePubKey, mRemotePubKey.Length()),
1484 : ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), msg_R2_Signed.Get(),
1485 : msg_r2_signed_len));
1486 :
1487 7 : VerifyOrExit(TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_Signature, err = CHIP_ERROR_INVALID_TLV_TAG);
1488 7 : VerifyOrExit(tbsData2Signature.Capacity() >= decryptedDataTlvReader.GetLength(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1489 7 : tbsData2Signature.SetLength(decryptedDataTlvReader.GetLength());
1490 7 : SuccessOrExit(err = decryptedDataTlvReader.GetBytes(tbsData2Signature.Bytes(), tbsData2Signature.Length()));
1491 :
1492 : // Validate signature
1493 7 : SuccessOrExit(err = responderPublicKey.ECDSA_validate_msg_signature(msg_R2_Signed.Get(), msg_r2_signed_len, tbsData2Signature));
1494 :
1495 : // Retrieve session resumption ID
1496 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_ResumptionID)));
1497 7 : SuccessOrExit(err = decryptedDataTlvReader.GetBytes(mNewResumptionId.data(), mNewResumptionId.size()));
1498 :
1499 : // Retrieve peer CASE Authenticated Tags (CATs) from peer's NOC.
1500 7 : SuccessOrExit(err = ExtractCATsFromOpCert(responderNOC, mPeerCATs));
1501 :
1502 : // Retrieve responderMRPParams if present
1503 7 : if (tlvReader.Next() != CHIP_END_OF_TLV)
1504 : {
1505 7 : SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(kTag_Sigma2_ResponderMRPParams), tlvReader));
1506 7 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
1507 : GetRemoteSessionParameters());
1508 : }
1509 :
1510 0 : exit:
1511 7 : if (err != CHIP_NO_ERROR)
1512 : {
1513 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1514 : }
1515 7 : return err;
1516 7 : }
1517 :
1518 7 : CHIP_ERROR CASESession::SendSigma3a()
1519 : {
1520 : MATTER_TRACE_SCOPE("SendSigma3", "CASESession");
1521 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1522 :
1523 7 : ChipLogDetail(SecureChannel, "Sending Sigma3");
1524 :
1525 7 : auto helper = WorkHelper<SendSigma3Data>::Create(*this, &SendSigma3b, &CASESession::SendSigma3c);
1526 7 : VerifyOrExit(helper, err = CHIP_ERROR_NO_MEMORY);
1527 : {
1528 7 : auto & data = helper->mData;
1529 :
1530 7 : VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1531 7 : data.fabricIndex = mFabricIndex;
1532 7 : data.fabricTable = nullptr;
1533 7 : data.keystore = nullptr;
1534 :
1535 : {
1536 7 : const FabricInfo * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
1537 7 : VerifyOrExit(fabricInfo != nullptr, err = CHIP_ERROR_KEY_NOT_FOUND);
1538 7 : auto * keystore = mFabricsTable->GetOperationalKeystore();
1539 7 : if (!fabricInfo->HasOperationalKey() && keystore != nullptr && keystore->SupportsSignWithOpKeypairInBackground())
1540 : {
1541 : // NOTE: used to sign in background.
1542 0 : data.keystore = keystore;
1543 : }
1544 : else
1545 : {
1546 : // NOTE: used to sign in foreground.
1547 7 : data.fabricTable = mFabricsTable;
1548 : }
1549 : }
1550 :
1551 7 : VerifyOrExit(mEphemeralKey != nullptr, err = CHIP_ERROR_INTERNAL);
1552 :
1553 7 : VerifyOrExit(data.icacBuf.Alloc(kMaxCHIPCertLength), err = CHIP_ERROR_NO_MEMORY);
1554 7 : data.icaCert = MutableByteSpan{ data.icacBuf.Get(), kMaxCHIPCertLength };
1555 :
1556 7 : VerifyOrExit(data.nocBuf.Alloc(kMaxCHIPCertLength), err = CHIP_ERROR_NO_MEMORY);
1557 7 : data.nocCert = MutableByteSpan{ data.nocBuf.Get(), kMaxCHIPCertLength };
1558 :
1559 7 : SuccessOrExit(err = mFabricsTable->FetchICACert(mFabricIndex, data.icaCert));
1560 7 : SuccessOrExit(err = mFabricsTable->FetchNOCCert(mFabricIndex, data.nocCert));
1561 :
1562 : // Prepare Sigma3 TBS Data Blob
1563 7 : data.msg_r3_signed_len =
1564 7 : TLV::EstimateStructOverhead(data.icaCert.size(), data.nocCert.size(), kP256_PublicKey_Length, kP256_PublicKey_Length);
1565 :
1566 7 : VerifyOrExit(data.msg_R3_Signed.Alloc(data.msg_r3_signed_len), err = CHIP_ERROR_NO_MEMORY);
1567 :
1568 7 : SuccessOrExit(err = ConstructTBSData(
1569 : data.nocCert, data.icaCert, ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
1570 : ByteSpan(mRemotePubKey, mRemotePubKey.Length()), data.msg_R3_Signed.Get(), data.msg_r3_signed_len));
1571 :
1572 7 : if (data.keystore != nullptr)
1573 : {
1574 0 : SuccessOrExit(err = helper->ScheduleWork());
1575 0 : mSendSigma3Helper = helper;
1576 0 : mExchangeCtxt.Value()->WillSendMessage();
1577 0 : mState = State::kSendSigma3Pending;
1578 : }
1579 : else
1580 : {
1581 7 : SuccessOrExit(err = helper->DoWork());
1582 : }
1583 : }
1584 :
1585 7 : exit:
1586 7 : if (err != CHIP_NO_ERROR)
1587 : {
1588 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1589 0 : mState = State::kInitialized;
1590 : }
1591 :
1592 7 : return err;
1593 7 : }
1594 :
1595 7 : CHIP_ERROR CASESession::SendSigma3b(SendSigma3Data & data, bool & cancel)
1596 : {
1597 : // Generate a signature
1598 7 : if (data.keystore != nullptr)
1599 : {
1600 : // Recommended case: delegate to operational keystore
1601 0 : ReturnErrorOnFailure(data.keystore->SignWithOpKeypair(
1602 : data.fabricIndex, ByteSpan{ data.msg_R3_Signed.Get(), data.msg_r3_signed_len }, data.tbsData3Signature));
1603 : }
1604 : else
1605 : {
1606 : // Legacy case: delegate to fabric table fabric info
1607 7 : ReturnErrorOnFailure(data.fabricTable->SignWithOpKeypair(
1608 : data.fabricIndex, ByteSpan{ data.msg_R3_Signed.Get(), data.msg_r3_signed_len }, data.tbsData3Signature));
1609 : }
1610 :
1611 : // Prepare Sigma3 TBE Data Blob
1612 7 : data.msg_r3_encrypted_len =
1613 7 : TLV::EstimateStructOverhead(data.nocCert.size(), data.icaCert.size(), data.tbsData3Signature.Length());
1614 :
1615 7 : VerifyOrReturnError(data.msg_R3_Encrypted.Alloc(data.msg_r3_encrypted_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES),
1616 : CHIP_ERROR_NO_MEMORY);
1617 :
1618 : {
1619 7 : TLV::TLVWriter tlvWriter;
1620 7 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
1621 :
1622 7 : tlvWriter.Init(data.msg_R3_Encrypted.Get(), data.msg_r3_encrypted_len);
1623 7 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
1624 7 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderNOC), data.nocCert));
1625 7 : if (!data.icaCert.empty())
1626 : {
1627 7 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderICAC), data.icaCert));
1628 : }
1629 :
1630 : // We are now done with ICAC and NOC certs so we can release the memory.
1631 : {
1632 7 : data.icacBuf.Free();
1633 7 : data.icaCert = MutableByteSpan{};
1634 :
1635 7 : data.nocBuf.Free();
1636 7 : data.nocCert = MutableByteSpan{};
1637 : }
1638 :
1639 7 : ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kTag_TBEData_Signature), data.tbsData3Signature.ConstBytes(),
1640 : static_cast<uint32_t>(data.tbsData3Signature.Length())));
1641 7 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
1642 7 : ReturnErrorOnFailure(tlvWriter.Finalize());
1643 7 : data.msg_r3_encrypted_len = static_cast<size_t>(tlvWriter.GetLengthWritten());
1644 : }
1645 :
1646 7 : return CHIP_NO_ERROR;
1647 : }
1648 :
1649 7 : CHIP_ERROR CASESession::SendSigma3c(SendSigma3Data & data, CHIP_ERROR status)
1650 : {
1651 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1652 :
1653 7 : System::PacketBufferHandle msg_R3;
1654 : size_t data_len;
1655 :
1656 : uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length];
1657 :
1658 7 : AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore());
1659 :
1660 7 : VerifyOrDieWithMsg(data.keystore == nullptr || mState == State::kSendSigma3Pending, SecureChannel, "Bad internal state.");
1661 :
1662 7 : SuccessOrExit(err = status);
1663 :
1664 : // Generate S3K key
1665 : {
1666 7 : MutableByteSpan saltSpan(msg_salt);
1667 7 : SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan));
1668 7 : SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k));
1669 : }
1670 :
1671 : // Generated Encrypted data blob
1672 7 : SuccessOrExit(err =
1673 : AES_CCM_encrypt(data.msg_R3_Encrypted.Get(), data.msg_r3_encrypted_len, nullptr, 0, sr3k.KeyHandle(),
1674 : kTBEData3_Nonce, kTBEDataNonceLength, data.msg_R3_Encrypted.Get(),
1675 : data.msg_R3_Encrypted.Get() + data.msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
1676 :
1677 : // Generate Sigma3 Msg
1678 7 : data_len = TLV::EstimateStructOverhead(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, data.msg_r3_encrypted_len);
1679 :
1680 7 : msg_R3 = System::PacketBufferHandle::New(data_len);
1681 7 : VerifyOrExit(!msg_R3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
1682 :
1683 : {
1684 7 : System::PacketBufferTLVWriter tlvWriter;
1685 7 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
1686 :
1687 7 : tlvWriter.Init(std::move(msg_R3));
1688 7 : err = tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType);
1689 7 : SuccessOrExit(err);
1690 7 : err = tlvWriter.PutBytes(TLV::ContextTag(1), data.msg_R3_Encrypted.Get(),
1691 7 : static_cast<uint32_t>(data.msg_r3_encrypted_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
1692 7 : SuccessOrExit(err);
1693 7 : err = tlvWriter.EndContainer(outerContainerType);
1694 7 : SuccessOrExit(err);
1695 7 : err = tlvWriter.Finalize(&msg_R3);
1696 7 : SuccessOrExit(err);
1697 7 : }
1698 :
1699 7 : err = mCommissioningHash.AddData(ByteSpan{ msg_R3->Start(), msg_R3->DataLength() });
1700 7 : SuccessOrExit(err);
1701 :
1702 : // Call delegate to send the Msg3 to peer
1703 14 : err = mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma3, std::move(msg_R3),
1704 7 : SendFlags(SendMessageFlags::kExpectResponse));
1705 7 : SuccessOrExit(err);
1706 :
1707 7 : ChipLogProgress(SecureChannel, "Sent Sigma3 msg");
1708 :
1709 : {
1710 7 : MutableByteSpan messageDigestSpan(mMessageDigest);
1711 7 : SuccessOrExit(err = mCommissioningHash.Finish(messageDigestSpan));
1712 : }
1713 :
1714 7 : mState = State::kSentSigma3;
1715 :
1716 7 : exit:
1717 7 : mSendSigma3Helper.reset();
1718 :
1719 : // If data.keystore is set, processing occurred in the background, so if an error occurred,
1720 : // need to send status report (normally occurs in SendSigma3a), and discard exchange and
1721 : // abort pending establish (normally occurs in OnMessageReceived).
1722 7 : if (data.keystore != nullptr && err != CHIP_NO_ERROR)
1723 : {
1724 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1725 0 : DiscardExchange();
1726 0 : AbortPendingEstablish(err);
1727 : }
1728 :
1729 7 : return err;
1730 7 : }
1731 :
1732 7 : CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg)
1733 : {
1734 : MATTER_TRACE_SCOPE("HandleSigma3", "CASESession");
1735 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1736 7 : System::PacketBufferTLVReader tlvReader;
1737 7 : TLV::TLVReader decryptedDataTlvReader;
1738 7 : TLV::TLVType containerType = TLV::kTLVType_Structure;
1739 :
1740 7 : const uint8_t * buf = msg->Start();
1741 7 : const size_t bufLen = msg->DataLength();
1742 :
1743 7 : constexpr size_t kCaseOverheadForFutureTbeData = 128;
1744 :
1745 7 : chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Encrypted;
1746 7 : size_t msg_r3_encrypted_len = 0;
1747 7 : size_t msg_r3_encrypted_len_with_tag = 0;
1748 : size_t max_msg_r3_signed_enc_len;
1749 :
1750 7 : AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore());
1751 :
1752 : uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length];
1753 :
1754 7 : ChipLogProgress(SecureChannel, "Received Sigma3 msg");
1755 : MATTER_TRACE_COUNTER("Sigma3");
1756 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err);
1757 :
1758 7 : auto helper = WorkHelper<HandleSigma3Data>::Create(*this, &HandleSigma3b, &CASESession::HandleSigma3c);
1759 7 : VerifyOrExit(helper, err = CHIP_ERROR_NO_MEMORY);
1760 : {
1761 7 : auto & data = helper->mData;
1762 :
1763 : {
1764 7 : VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1765 7 : const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex);
1766 7 : VerifyOrExit(fabricInfo != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
1767 7 : data.fabricId = fabricInfo->GetFabricId();
1768 : }
1769 :
1770 7 : VerifyOrExit(mEphemeralKey != nullptr, err = CHIP_ERROR_INTERNAL);
1771 :
1772 7 : tlvReader.Init(std::move(msg));
1773 7 : SuccessOrExit(err = tlvReader.Next(containerType, TLV::AnonymousTag()));
1774 7 : SuccessOrExit(err = tlvReader.EnterContainer(containerType));
1775 :
1776 : // Fetch encrypted data
1777 7 : max_msg_r3_signed_enc_len = TLV::EstimateStructOverhead(Credentials::kMaxCHIPCertLength, Credentials::kMaxCHIPCertLength,
1778 : data.tbsData3Signature.Length(), kCaseOverheadForFutureTbeData);
1779 :
1780 7 : SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma3_Encrypted3)));
1781 :
1782 7 : msg_r3_encrypted_len_with_tag = tlvReader.GetLength();
1783 :
1784 : // Validate we did not receive a buffer larger than legal
1785 7 : VerifyOrExit(msg_r3_encrypted_len_with_tag <= max_msg_r3_signed_enc_len, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1786 7 : VerifyOrExit(msg_r3_encrypted_len_with_tag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1787 :
1788 7 : VerifyOrExit(msg_R3_Encrypted.Alloc(msg_r3_encrypted_len_with_tag), err = CHIP_ERROR_NO_MEMORY);
1789 7 : SuccessOrExit(err = tlvReader.GetBytes(msg_R3_Encrypted.Get(), static_cast<uint32_t>(msg_r3_encrypted_len_with_tag)));
1790 7 : msg_r3_encrypted_len = msg_r3_encrypted_len_with_tag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES;
1791 :
1792 : // Step 1
1793 : {
1794 7 : MutableByteSpan saltSpan(msg_salt);
1795 7 : SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan));
1796 7 : SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k));
1797 : }
1798 :
1799 7 : SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, bufLen }));
1800 :
1801 : // Step 2 - Decrypt data blob
1802 7 : SuccessOrExit(err = AES_CCM_decrypt(msg_R3_Encrypted.Get(), msg_r3_encrypted_len, nullptr, 0,
1803 : msg_R3_Encrypted.Get() + msg_r3_encrypted_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES,
1804 : sr3k.KeyHandle(), kTBEData3_Nonce, kTBEDataNonceLength, msg_R3_Encrypted.Get()));
1805 :
1806 7 : decryptedDataTlvReader.Init(msg_R3_Encrypted.Get(), msg_r3_encrypted_len);
1807 7 : containerType = TLV::kTLVType_Structure;
1808 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(containerType, TLV::AnonymousTag()));
1809 7 : SuccessOrExit(err = decryptedDataTlvReader.EnterContainer(containerType));
1810 :
1811 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_SenderNOC)));
1812 7 : SuccessOrExit(err = decryptedDataTlvReader.Get(data.initiatorNOC));
1813 :
1814 7 : SuccessOrExit(err = decryptedDataTlvReader.Next());
1815 7 : if (TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_SenderICAC)
1816 : {
1817 7 : VerifyOrExit(decryptedDataTlvReader.GetType() == TLV::kTLVType_ByteString, err = CHIP_ERROR_WRONG_TLV_TYPE);
1818 7 : SuccessOrExit(err = decryptedDataTlvReader.Get(data.initiatorICAC));
1819 7 : SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_Signature)));
1820 : }
1821 :
1822 : // Step 4 - Construct Sigma3 TBS Data
1823 7 : data.msg_r3_signed_len = TLV::EstimateStructOverhead(sizeof(uint16_t), data.initiatorNOC.size(), data.initiatorICAC.size(),
1824 : kP256_PublicKey_Length, kP256_PublicKey_Length);
1825 :
1826 7 : VerifyOrExit(data.msg_R3_Signed.Alloc(data.msg_r3_signed_len), err = CHIP_ERROR_NO_MEMORY);
1827 :
1828 7 : SuccessOrExit(err = ConstructTBSData(data.initiatorNOC, data.initiatorICAC, ByteSpan(mRemotePubKey, mRemotePubKey.Length()),
1829 : ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()),
1830 : data.msg_R3_Signed.Get(), data.msg_r3_signed_len));
1831 :
1832 7 : VerifyOrExit(TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_Signature,
1833 : err = CHIP_ERROR_INVALID_TLV_TAG);
1834 7 : VerifyOrExit(data.tbsData3Signature.Capacity() >= decryptedDataTlvReader.GetLength(), err = CHIP_ERROR_INVALID_TLV_ELEMENT);
1835 7 : data.tbsData3Signature.SetLength(decryptedDataTlvReader.GetLength());
1836 7 : SuccessOrExit(err = decryptedDataTlvReader.GetBytes(data.tbsData3Signature.Bytes(), data.tbsData3Signature.Length()));
1837 :
1838 : // Prepare for Step 5/6
1839 : {
1840 7 : MutableByteSpan fabricRCAC{ data.rootCertBuf };
1841 7 : SuccessOrExit(err = mFabricsTable->FetchRootCert(mFabricIndex, fabricRCAC));
1842 7 : data.fabricRCAC = fabricRCAC;
1843 : // TODO probably should make SetEffectiveTime static and call closer to VerifyCredentials
1844 7 : SuccessOrExit(err = SetEffectiveTime());
1845 : }
1846 :
1847 : // Copy remaining needed data into work structure
1848 : {
1849 7 : data.validContext = mValidContext;
1850 :
1851 : // initiatorNOC and initiatorICAC are spans into msg_R3_Encrypted
1852 : // which is going away, so to save memory, redirect them to their
1853 : // copies in msg_R3_signed, which is staying around
1854 7 : TLV::TLVReader signedDataTlvReader;
1855 7 : signedDataTlvReader.Init(data.msg_R3_Signed.Get(), data.msg_r3_signed_len);
1856 7 : SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
1857 7 : SuccessOrExit(err = signedDataTlvReader.EnterContainer(containerType));
1858 :
1859 7 : SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBSData_SenderNOC)));
1860 7 : SuccessOrExit(err = signedDataTlvReader.Get(data.initiatorNOC));
1861 :
1862 7 : if (!data.initiatorICAC.empty())
1863 : {
1864 7 : SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBSData_SenderICAC)));
1865 7 : SuccessOrExit(err = signedDataTlvReader.Get(data.initiatorICAC));
1866 : }
1867 : }
1868 :
1869 7 : SuccessOrExit(err = helper->ScheduleWork());
1870 7 : mHandleSigma3Helper = helper;
1871 7 : mExchangeCtxt.Value()->WillSendMessage();
1872 7 : mState = State::kHandleSigma3Pending;
1873 : }
1874 :
1875 7 : exit:
1876 7 : if (err != CHIP_NO_ERROR)
1877 : {
1878 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1879 : }
1880 :
1881 7 : return err;
1882 7 : }
1883 :
1884 7 : CHIP_ERROR CASESession::HandleSigma3b(HandleSigma3Data & data, bool & cancel)
1885 : {
1886 : // Step 5/6
1887 : // Validate initiator identity located in msg->Start()
1888 : // Constructing responder identity
1889 : CompressedFabricId unused;
1890 : FabricId initiatorFabricId;
1891 7 : P256PublicKey initiatorPublicKey;
1892 7 : ReturnErrorOnFailure(FabricTable::VerifyCredentials(data.initiatorNOC, data.initiatorICAC, data.fabricRCAC, data.validContext,
1893 : unused, initiatorFabricId, data.initiatorNodeId, initiatorPublicKey));
1894 7 : VerifyOrReturnError(data.fabricId == initiatorFabricId, CHIP_ERROR_INVALID_CASE_PARAMETER);
1895 :
1896 : // TODO - Validate message signature prior to validating the received operational credentials.
1897 : // The op cert check requires traversal of cert chain, that is a more expensive operation.
1898 : // If message signature check fails, the cert chain check will be unnecessary, but with the
1899 : // current flow of code, a malicious node can trigger a DoS style attack on the device.
1900 : // The same change should be made in Sigma2 processing.
1901 : // Step 7 - Validate Signature
1902 7 : ReturnErrorOnFailure(
1903 : initiatorPublicKey.ECDSA_validate_msg_signature(data.msg_R3_Signed.Get(), data.msg_r3_signed_len, data.tbsData3Signature));
1904 :
1905 7 : return CHIP_NO_ERROR;
1906 7 : }
1907 :
1908 7 : CHIP_ERROR CASESession::HandleSigma3c(HandleSigma3Data & data, CHIP_ERROR status)
1909 : {
1910 7 : CHIP_ERROR err = CHIP_NO_ERROR;
1911 :
1912 7 : VerifyOrExit(mState == State::kHandleSigma3Pending, err = CHIP_ERROR_INCORRECT_STATE);
1913 :
1914 7 : SuccessOrExit(err = status);
1915 :
1916 7 : mPeerNodeId = data.initiatorNodeId;
1917 :
1918 : {
1919 7 : MutableByteSpan messageDigestSpan(mMessageDigest);
1920 7 : SuccessOrExit(err = mCommissioningHash.Finish(messageDigestSpan));
1921 : }
1922 :
1923 : // Retrieve peer CASE Authenticated Tags (CATs) from peer's NOC.
1924 : {
1925 7 : SuccessOrExit(err = ExtractCATsFromOpCert(data.initiatorNOC, mPeerCATs));
1926 : }
1927 :
1928 7 : if (mSessionResumptionStorage != nullptr)
1929 : {
1930 3 : CHIP_ERROR err2 = mSessionResumptionStorage->Save(GetPeer(), mNewResumptionId, mSharedSecret, mPeerCATs);
1931 3 : if (err2 != CHIP_NO_ERROR)
1932 : {
1933 0 : ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
1934 : }
1935 : }
1936 :
1937 : MATTER_LOG_METRIC(kMetricDeviceCASESessionSigmaFinished);
1938 7 : SendStatusReport(mExchangeCtxt, kProtocolCodeSuccess);
1939 :
1940 7 : mState = State::kFinished;
1941 7 : Finish();
1942 :
1943 7 : exit:
1944 7 : mHandleSigma3Helper.reset();
1945 :
1946 7 : if (err != CHIP_NO_ERROR)
1947 : {
1948 0 : SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam);
1949 : // Abort the pending establish, which is normally done by CASESession::OnMessageReceived,
1950 : // but in the background processing case must be done here.
1951 0 : DiscardExchange();
1952 0 : AbortPendingEstablish(err);
1953 : }
1954 :
1955 7 : return err;
1956 : }
1957 :
1958 36 : CHIP_ERROR CASESession::DeriveSigmaKey(const ByteSpan & salt, const ByteSpan & info, AutoReleaseSessionKey & key) const
1959 : {
1960 36 : return mSessionManager->GetSessionKeystore()->DeriveKey(mSharedSecret, salt, info, key.KeyHandle());
1961 : }
1962 :
1963 15 : CHIP_ERROR CASESession::ConstructSaltSigma2(const ByteSpan & rand, const Crypto::P256PublicKey & pubkey, const ByteSpan & ipk,
1964 : MutableByteSpan & salt)
1965 : {
1966 : uint8_t md[kSHA256_Hash_Length];
1967 15 : memset(salt.data(), 0, salt.size());
1968 15 : Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
1969 :
1970 15 : bbuf.Put(ipk.data(), ipk.size());
1971 15 : bbuf.Put(rand.data(), kSigmaParamRandomNumberSize);
1972 15 : bbuf.Put(pubkey, pubkey.Length());
1973 15 : MutableByteSpan messageDigestSpan(md);
1974 15 : ReturnErrorOnFailure(mCommissioningHash.GetDigest(messageDigestSpan));
1975 15 : bbuf.Put(messageDigestSpan.data(), messageDigestSpan.size());
1976 :
1977 15 : size_t saltWritten = 0;
1978 15 : VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
1979 15 : salt = salt.SubSpan(0, saltWritten);
1980 :
1981 15 : return CHIP_NO_ERROR;
1982 : }
1983 :
1984 14 : CHIP_ERROR CASESession::ConstructSaltSigma3(const ByteSpan & ipk, MutableByteSpan & salt)
1985 : {
1986 : uint8_t md[kSHA256_Hash_Length];
1987 14 : memset(salt.data(), 0, salt.size());
1988 14 : Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
1989 :
1990 14 : bbuf.Put(ipk.data(), ipk.size());
1991 14 : MutableByteSpan messageDigestSpan(md);
1992 14 : ReturnErrorOnFailure(mCommissioningHash.GetDigest(messageDigestSpan));
1993 14 : bbuf.Put(messageDigestSpan.data(), messageDigestSpan.size());
1994 :
1995 14 : size_t saltWritten = 0;
1996 14 : VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
1997 14 : salt = salt.SubSpan(0, saltWritten);
1998 :
1999 14 : return CHIP_NO_ERROR;
2000 : }
2001 :
2002 7 : CHIP_ERROR CASESession::ConstructSigmaResumeKey(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
2003 : const ByteSpan & skInfo, const ByteSpan & nonce, AutoReleaseSessionKey & resumeKey)
2004 : {
2005 7 : constexpr size_t saltSize = kSigmaParamRandomNumberSize + SessionResumptionStorage::kResumptionIdSize;
2006 : uint8_t salt[saltSize];
2007 :
2008 7 : memset(salt, 0, saltSize);
2009 7 : Encoding::LittleEndian::BufferWriter bbuf(salt, saltSize);
2010 :
2011 7 : bbuf.Put(initiatorRandom.data(), initiatorRandom.size());
2012 7 : bbuf.Put(resumptionID.data(), resumptionID.size());
2013 :
2014 7 : size_t saltWritten = 0;
2015 7 : VerifyOrReturnError(bbuf.Fit(saltWritten), CHIP_ERROR_BUFFER_TOO_SMALL);
2016 :
2017 7 : return DeriveSigmaKey(ByteSpan(salt, saltWritten), skInfo, resumeKey);
2018 : }
2019 :
2020 4 : CHIP_ERROR CASESession::GenerateSigmaResumeMIC(const ByteSpan & initiatorRandom, const ByteSpan & resumptionID,
2021 : const ByteSpan & skInfo, const ByteSpan & nonce, MutableByteSpan & resumeMIC)
2022 : {
2023 4 : VerifyOrReturnError(resumeMIC.size() >= CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
2024 :
2025 4 : AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore());
2026 4 : ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk));
2027 4 : ReturnErrorOnFailure(AES_CCM_encrypt(nullptr, 0, nullptr, 0, srk.KeyHandle(), nonce.data(), nonce.size(), nullptr,
2028 : resumeMIC.data(), CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES));
2029 4 : resumeMIC.reduce_size(CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES);
2030 :
2031 4 : return CHIP_NO_ERROR;
2032 4 : }
2033 :
2034 3 : CHIP_ERROR CASESession::ValidateSigmaResumeMIC(const ByteSpan & resumeMIC, const ByteSpan & initiatorRandom,
2035 : const ByteSpan & resumptionID, const ByteSpan & skInfo, const ByteSpan & nonce)
2036 : {
2037 3 : VerifyOrReturnError(resumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_BUFFER_TOO_SMALL);
2038 :
2039 3 : AutoReleaseSessionKey srk(*mSessionManager->GetSessionKeystore());
2040 3 : ReturnErrorOnFailure(ConstructSigmaResumeKey(initiatorRandom, resumptionID, skInfo, nonce, srk));
2041 3 : ReturnErrorOnFailure(AES_CCM_decrypt(nullptr, 0, nullptr, 0, resumeMIC.data(), resumeMIC.size(), srk.KeyHandle(), nonce.data(),
2042 : nonce.size(), nullptr));
2043 :
2044 2 : return CHIP_NO_ERROR;
2045 3 : }
2046 :
2047 29 : CHIP_ERROR CASESession::ConstructTBSData(const ByteSpan & senderNOC, const ByteSpan & senderICAC, const ByteSpan & senderPubKey,
2048 : const ByteSpan & receiverPubKey, uint8_t * tbsData, size_t & tbsDataLen)
2049 : {
2050 29 : TLV::TLVWriter tlvWriter;
2051 29 : TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;
2052 :
2053 29 : tlvWriter.Init(tbsData, tbsDataLen);
2054 29 : ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
2055 29 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderNOC), senderNOC));
2056 29 : if (!senderICAC.empty())
2057 : {
2058 29 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderICAC), senderICAC));
2059 : }
2060 29 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderPubKey), senderPubKey));
2061 29 : ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_ReceiverPubKey), receiverPubKey));
2062 29 : ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
2063 29 : ReturnErrorOnFailure(tlvWriter.Finalize());
2064 29 : tbsDataLen = static_cast<size_t>(tlvWriter.GetLengthWritten());
2065 :
2066 29 : return CHIP_NO_ERROR;
2067 : }
2068 :
2069 14 : CHIP_ERROR CASESession::SetEffectiveTime()
2070 : {
2071 : System::Clock::Milliseconds64 currentUnixTimeMS;
2072 14 : CHIP_ERROR err = System::SystemClock().GetClock_RealTimeMS(currentUnixTimeMS);
2073 :
2074 14 : if (err == CHIP_NO_ERROR)
2075 : {
2076 : // If the system has given us a wall clock time, we must use it or
2077 : // fail. Conversion failures here are therefore always an error.
2078 14 : System::Clock::Seconds32 currentUnixTime = std::chrono::duration_cast<System::Clock::Seconds32>(currentUnixTimeMS);
2079 14 : ReturnErrorOnFailure(mValidContext.SetEffectiveTimeFromUnixTime<CurrentChipEpochTime>(currentUnixTime));
2080 : }
2081 : else
2082 : {
2083 : // If we don't have wall clock time, the spec dictates that we should
2084 : // fall back to Last Known Good Time. Ultimately, the calling application's
2085 : // validity policy will determine whether this is permissible.
2086 : System::Clock::Seconds32 lastKnownGoodChipEpochTime;
2087 0 : ChipLogError(SecureChannel,
2088 : "The device does not support GetClock_RealTimeMS() API: %" CHIP_ERROR_FORMAT
2089 : ". Falling back to Last Known Good UTC Time",
2090 : err.Format());
2091 0 : VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE);
2092 0 : err = mFabricsTable->GetLastKnownGoodChipEpochTime(lastKnownGoodChipEpochTime);
2093 0 : if (err != CHIP_NO_ERROR)
2094 : {
2095 : // If we have no time available, the Validity Policy will
2096 : // determine what to do.
2097 0 : ChipLogError(SecureChannel, "Failed to retrieve Last Known Good UTC Time");
2098 : }
2099 : else
2100 : {
2101 0 : mValidContext.SetEffectiveTime<LastKnownGoodChipEpochTime>(lastKnownGoodChipEpochTime);
2102 : }
2103 : }
2104 14 : return CHIP_NO_ERROR;
2105 : }
2106 :
2107 8 : void CASESession::OnSuccessStatusReport()
2108 : {
2109 8 : ChipLogProgress(SecureChannel, "Success status report received. Session was established");
2110 :
2111 8 : if (mSessionResumptionStorage != nullptr)
2112 : {
2113 4 : CHIP_ERROR err2 = mSessionResumptionStorage->Save(GetPeer(), mNewResumptionId, mSharedSecret, mPeerCATs);
2114 4 : if (err2 != CHIP_NO_ERROR)
2115 0 : ChipLogError(SecureChannel, "Unable to save session resumption state: %" CHIP_ERROR_FORMAT, err2.Format());
2116 : }
2117 :
2118 8 : switch (mState)
2119 : {
2120 7 : case State::kSentSigma3:
2121 7 : mState = State::kFinished;
2122 7 : break;
2123 1 : case State::kSentSigma2Resume:
2124 1 : mState = State::kFinishedViaResume;
2125 1 : break;
2126 0 : default:
2127 0 : VerifyOrDie(false && "Reached invalid internal state keeping in CASE session");
2128 : break;
2129 : }
2130 :
2131 8 : Finish();
2132 8 : }
2133 :
2134 1 : CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralStatusCode generalCode, uint16_t protocolCode,
2135 : Optional<uintptr_t> protocolData)
2136 : {
2137 1 : CHIP_ERROR err = CHIP_NO_ERROR;
2138 1 : switch (protocolCode)
2139 : {
2140 0 : case kProtocolCodeInvalidParam:
2141 0 : err = CHIP_ERROR_INVALID_CASE_PARAMETER;
2142 0 : break;
2143 :
2144 0 : case kProtocolCodeNoSharedRoot:
2145 0 : err = CHIP_ERROR_NO_SHARED_TRUSTED_ROOT;
2146 0 : break;
2147 :
2148 1 : case kProtocolCodeBusy:
2149 1 : err = CHIP_ERROR_BUSY;
2150 1 : if (protocolData.HasValue())
2151 : {
2152 1 : mDelegate->OnResponderBusy(System::Clock::Milliseconds16(static_cast<uint16_t>(protocolData.Value())));
2153 : }
2154 1 : break;
2155 :
2156 0 : default:
2157 0 : err = CHIP_ERROR_INTERNAL;
2158 0 : break;
2159 : };
2160 1 : mState = State::kInitialized;
2161 1 : ChipLogError(SecureChannel, "Received error (protocol code %d) during pairing process: %" CHIP_ERROR_FORMAT, protocolCode,
2162 : err.Format());
2163 1 : return err;
2164 : }
2165 :
2166 26 : CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ByteSpan & initiatorRandom,
2167 : uint16_t & initiatorSessionId, ByteSpan & destinationId, ByteSpan & initiatorEphPubKey,
2168 : bool & resumptionRequested, ByteSpan & resumptionId, ByteSpan & initiatorResumeMIC)
2169 : {
2170 : using namespace TLV;
2171 :
2172 26 : constexpr uint8_t kInitiatorRandomTag = 1;
2173 26 : constexpr uint8_t kInitiatorSessionIdTag = 2;
2174 26 : constexpr uint8_t kDestinationIdTag = 3;
2175 26 : constexpr uint8_t kInitiatorPubKeyTag = 4;
2176 26 : constexpr uint8_t kInitiatorMRPParamsTag = 5;
2177 26 : constexpr uint8_t kResumptionIDTag = 6;
2178 26 : constexpr uint8_t kResume1MICTag = 7;
2179 :
2180 26 : TLVType containerType = kTLVType_Structure;
2181 26 : ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag()));
2182 26 : ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));
2183 :
2184 26 : ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorRandomTag)));
2185 25 : ReturnErrorOnFailure(tlvReader.GetByteView(initiatorRandom));
2186 25 : VerifyOrReturnError(initiatorRandom.size() == kSigmaParamRandomNumberSize, CHIP_ERROR_INVALID_CASE_PARAMETER);
2187 :
2188 23 : ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorSessionIdTag)));
2189 23 : ReturnErrorOnFailure(tlvReader.Get(initiatorSessionId));
2190 :
2191 22 : ReturnErrorOnFailure(tlvReader.Next(ContextTag(kDestinationIdTag)));
2192 22 : ReturnErrorOnFailure(tlvReader.GetByteView(destinationId));
2193 22 : VerifyOrReturnError(destinationId.size() == kSHA256_Hash_Length, CHIP_ERROR_INVALID_CASE_PARAMETER);
2194 :
2195 20 : ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorPubKeyTag)));
2196 20 : ReturnErrorOnFailure(tlvReader.GetByteView(initiatorEphPubKey));
2197 20 : VerifyOrReturnError(initiatorEphPubKey.size() == kP256_PublicKey_Length, CHIP_ERROR_INVALID_CASE_PARAMETER);
2198 :
2199 : // Optional members start here.
2200 18 : CHIP_ERROR err = tlvReader.Next();
2201 18 : if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kInitiatorMRPParamsTag))
2202 : {
2203 9 : ReturnErrorOnFailure(DecodeMRPParametersIfPresent(TLV::ContextTag(kInitiatorMRPParamsTag), tlvReader));
2204 9 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters(
2205 : GetRemoteSessionParameters());
2206 9 : err = tlvReader.Next();
2207 : }
2208 :
2209 18 : bool resumptionIDTagFound = false;
2210 18 : bool resume1MICTagFound = false;
2211 :
2212 18 : if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kResumptionIDTag))
2213 : {
2214 8 : resumptionIDTagFound = true;
2215 8 : ReturnErrorOnFailure(tlvReader.GetByteView(resumptionId));
2216 8 : VerifyOrReturnError(resumptionId.size() == SessionResumptionStorage::kResumptionIdSize, CHIP_ERROR_INVALID_CASE_PARAMETER);
2217 5 : err = tlvReader.Next();
2218 : }
2219 :
2220 15 : if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kResume1MICTag))
2221 : {
2222 5 : resume1MICTagFound = true;
2223 5 : ReturnErrorOnFailure(tlvReader.GetByteView(initiatorResumeMIC));
2224 5 : VerifyOrReturnError(initiatorResumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_CASE_PARAMETER);
2225 4 : err = tlvReader.Next();
2226 : }
2227 :
2228 14 : if (err == CHIP_END_OF_TLV)
2229 : {
2230 : // We ran out of struct members, but that's OK, because they were optional.
2231 14 : err = CHIP_NO_ERROR;
2232 : }
2233 :
2234 14 : ReturnErrorOnFailure(err);
2235 14 : ReturnErrorOnFailure(tlvReader.ExitContainer(containerType));
2236 :
2237 13 : if (resumptionIDTagFound && resume1MICTagFound)
2238 : {
2239 4 : resumptionRequested = true;
2240 : }
2241 9 : else if (!resumptionIDTagFound && !resume1MICTagFound)
2242 : {
2243 9 : resumptionRequested = false;
2244 : }
2245 : else
2246 : {
2247 0 : return CHIP_ERROR_UNEXPECTED_TLV_ELEMENT;
2248 : }
2249 :
2250 13 : return CHIP_NO_ERROR;
2251 : }
2252 :
2253 35 : CHIP_ERROR CASESession::ValidateReceivedMessage(ExchangeContext * ec, const PayloadHeader & payloadHeader,
2254 : const System::PacketBufferHandle & msg)
2255 : {
2256 35 : VerifyOrReturnError(ec != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
2257 :
2258 : // mExchangeCtxt can be nullptr if this is the first message (CASE_Sigma1) received by CASESession
2259 : // via UnsolicitedMessageHandler. The exchange context is allocated by exchange manager and provided
2260 : // to the handler (CASESession object).
2261 35 : if (mExchangeCtxt.HasValue())
2262 : {
2263 25 : if (&mExchangeCtxt.Value().Get() != ec)
2264 : {
2265 0 : ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
2266 : }
2267 : }
2268 : else
2269 : {
2270 10 : mExchangeCtxt.Emplace(*ec);
2271 : }
2272 35 : mExchangeCtxt.Value()->UseSuggestedResponseTimeout(kExpectedHighProcessingTime);
2273 :
2274 35 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
2275 35 : return CHIP_NO_ERROR;
2276 : }
2277 :
2278 35 : CHIP_ERROR CASESession::OnMessageReceived(ExchangeContext * ec, const PayloadHeader & payloadHeader,
2279 : System::PacketBufferHandle && msg)
2280 : {
2281 : MATTER_TRACE_SCOPE("OnMessageReceived", "CASESession");
2282 35 : CHIP_ERROR err = ValidateReceivedMessage(ec, payloadHeader, msg);
2283 35 : Protocols::SecureChannel::MsgType msgType = static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType());
2284 35 : SuccessOrExit(err);
2285 :
2286 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
2287 35 : if (mStopHandshakeAtState.HasValue() && mState == mStopHandshakeAtState.Value())
2288 : {
2289 1 : mStopHandshakeAtState = Optional<State>::Missing();
2290 : // For testing purposes we are trying to stop a successful CASESession from happening by dropping part of the
2291 : // handshake in the middle. We are trying to keep both sides of the CASESession establishment in an active
2292 : // pending state. In order to keep this side open we have to tell the exchange context that we will send an
2293 : // async message.
2294 : //
2295 : // Should you need to resume the CASESession, you could theoretically pass along the msg to a callback that gets
2296 : // registered when setting mStopHandshakeAtState.
2297 1 : mExchangeCtxt.Value()->WillSendMessage();
2298 1 : return CHIP_NO_ERROR;
2299 : }
2300 : #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST
2301 :
2302 : #if CHIP_CONFIG_SLOW_CRYPTO
2303 : if ((msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1 || msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2 ||
2304 : msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2Resume ||
2305 : msgType == Protocols::SecureChannel::MsgType::CASE_Sigma3) &&
2306 : mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress().GetTransportType() !=
2307 : Transport::Type::kTcp)
2308 : {
2309 : // TODO: Rename FlushAcks() to something more semantically correct and
2310 : // call unconditionally for TCP or MRP from here. Inside, the
2311 : // PeerAddress type could be consulted to selectively flush MRP Acks
2312 : // when transport is not TCP. Issue #33183
2313 : SuccessOrExit(err = mExchangeCtxt.Value()->FlushAcks());
2314 : }
2315 : #endif // CHIP_CONFIG_SLOW_CRYPTO
2316 :
2317 : // By default, CHIP_ERROR_INVALID_MESSAGE_TYPE is returned if in the current state
2318 : // a message handler is not defined for the received message type.
2319 34 : err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
2320 :
2321 34 : switch (mState)
2322 : {
2323 10 : case State::kInitialized:
2324 10 : if (msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1)
2325 : {
2326 10 : err = HandleSigma1_and_SendSigma2(std::move(msg));
2327 : }
2328 10 : break;
2329 6 : case State::kSentSigma1:
2330 6 : switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
2331 : {
2332 5 : case Protocols::SecureChannel::MsgType::CASE_Sigma2:
2333 5 : err = HandleSigma2_and_SendSigma3(std::move(msg));
2334 5 : break;
2335 :
2336 1 : case MsgType::StatusReport:
2337 1 : err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
2338 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
2339 1 : break;
2340 :
2341 0 : default:
2342 : // Return the default error that was set above
2343 0 : break;
2344 : };
2345 6 : break;
2346 3 : case State::kSentSigma1Resume:
2347 3 : switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
2348 : {
2349 2 : case Protocols::SecureChannel::MsgType::CASE_Sigma2:
2350 2 : err = HandleSigma2_and_SendSigma3(std::move(msg));
2351 2 : break;
2352 :
2353 1 : case Protocols::SecureChannel::MsgType::CASE_Sigma2Resume:
2354 1 : err = HandleSigma2Resume(std::move(msg));
2355 1 : break;
2356 :
2357 0 : case MsgType::StatusReport:
2358 0 : err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
2359 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma1, err);
2360 0 : break;
2361 :
2362 0 : default:
2363 : // Return the default error that was set above
2364 0 : break;
2365 : };
2366 3 : break;
2367 7 : case State::kSentSigma2:
2368 7 : switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
2369 : {
2370 7 : case Protocols::SecureChannel::MsgType::CASE_Sigma3:
2371 7 : err = HandleSigma3a(std::move(msg));
2372 7 : break;
2373 :
2374 0 : case MsgType::StatusReport:
2375 0 : err = HandleStatusReport(std::move(msg), /* successExpected*/ false);
2376 : MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err);
2377 0 : break;
2378 :
2379 0 : default:
2380 : // Return the default error that was set above
2381 0 : break;
2382 : };
2383 7 : break;
2384 8 : case State::kSentSigma3:
2385 : case State::kSentSigma2Resume:
2386 8 : if (msgType == Protocols::SecureChannel::MsgType::StatusReport)
2387 : {
2388 : // Need to capture before invoking status report since 'this' might be deallocated on successful completion of sigma3
2389 8 : MetricKey key = (mState == State::kSentSigma3) ? kMetricDeviceCASESessionSigma3 : kMetricDeviceCASESessionSigma2Resume;
2390 8 : err = HandleStatusReport(std::move(msg), /* successExpected*/ true);
2391 : MATTER_LOG_METRIC_END(key, err);
2392 : IgnoreUnusedVariable(key);
2393 : }
2394 8 : break;
2395 0 : default:
2396 : // Return the default error that was set above
2397 0 : break;
2398 : };
2399 :
2400 34 : exit:
2401 :
2402 34 : if (err == CHIP_ERROR_INVALID_MESSAGE_TYPE)
2403 : {
2404 0 : ChipLogError(SecureChannel, "Received message (type %d) cannot be handled in %d state.", to_underlying(msgType),
2405 : to_underlying(mState));
2406 : }
2407 :
2408 : // Call delegate to indicate session establishment failure.
2409 34 : if (err != CHIP_NO_ERROR)
2410 : {
2411 : // Discard the exchange so that Clear() doesn't try aborting it. The
2412 : // exchange will handle that.
2413 2 : DiscardExchange();
2414 2 : AbortPendingEstablish(err);
2415 : }
2416 34 : return err;
2417 : }
2418 :
2419 : namespace {
2420 1 : System::Clock::Timeout ComputeRoundTripTimeout(ExchangeContext::Timeout serverProcessingTime,
2421 : const ReliableMessageProtocolConfig & remoteMrpConfig)
2422 : {
2423 : // TODO: This is duplicating logic from Session::ComputeRoundTripTimeout. Unfortunately, it's called by
2424 : // consumers who do not have a session.
2425 1 : const auto & maybeLocalMRPConfig = GetLocalMRPConfig();
2426 1 : const auto & defaultMRRPConfig = GetDefaultMRPConfig();
2427 1 : const auto & localMRPConfig = maybeLocalMRPConfig.ValueOr(defaultMRRPConfig);
2428 1 : return GetRetransmissionTimeout(remoteMrpConfig.mActiveRetransTimeout, remoteMrpConfig.mIdleRetransTimeout,
2429 : // Assume peer is idle, as a worst-case assumption (probably true for
2430 : // Sigma1, since that will be our initial message on the session, but less
2431 : // so for Sigma2).
2432 1 : System::Clock::kZero, remoteMrpConfig.mActiveThresholdTime) +
2433 1 : serverProcessingTime +
2434 1 : GetRetransmissionTimeout(localMRPConfig.mActiveRetransTimeout, localMRPConfig.mIdleRetransTimeout,
2435 : // Peer will assume we are active, since it's
2436 : // responding to our message.
2437 2 : System::SystemClock().GetMonotonicTimestamp(), localMRPConfig.mActiveThresholdTime);
2438 1 : }
2439 : } // anonymous namespace
2440 :
2441 0 : System::Clock::Timeout CASESession::ComputeSigma1ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig)
2442 : {
2443 0 : return ComputeRoundTripTimeout(kExpectedSigma1ProcessingTime, remoteMrpConfig);
2444 : }
2445 :
2446 1 : System::Clock::Timeout CASESession::ComputeSigma2ResponseTimeout(const ReliableMessageProtocolConfig & remoteMrpConfig)
2447 : {
2448 1 : return ComputeRoundTripTimeout(kExpectedHighProcessingTime, remoteMrpConfig);
2449 : }
2450 :
2451 1 : bool CASESession::InvokeBackgroundWorkWatchdog()
2452 : {
2453 1 : bool watchdogFired = false;
2454 :
2455 1 : if (mSendSigma3Helper && mSendSigma3Helper->UnableToScheduleAfterWorkCallback())
2456 : {
2457 0 : ChipLogError(SecureChannel, "SendSigma3Helper was unable to schedule the AfterWorkCallback");
2458 0 : mSendSigma3Helper->DoAfterWork();
2459 0 : watchdogFired = true;
2460 : }
2461 :
2462 1 : if (mHandleSigma3Helper && mHandleSigma3Helper->UnableToScheduleAfterWorkCallback())
2463 : {
2464 0 : ChipLogError(SecureChannel, "HandleSigma3Helper was unable to schedule the AfterWorkCallback");
2465 0 : mHandleSigma3Helper->DoAfterWork();
2466 0 : watchdogFired = true;
2467 : }
2468 :
2469 1 : return watchdogFired;
2470 : }
2471 :
2472 : // Helper function to map CASESession::State to SessionEstablishmentStage
2473 4 : SessionEstablishmentStage CASESession::MapCASEStateToSessionEstablishmentStage(State caseState)
2474 : {
2475 4 : switch (caseState)
2476 : {
2477 2 : case State::kInitialized:
2478 2 : return SessionEstablishmentStage::kNotInKeyExchange;
2479 1 : case State::kSentSigma1:
2480 : case State::kSentSigma1Resume:
2481 1 : return SessionEstablishmentStage::kSentSigma1;
2482 1 : case State::kSentSigma2:
2483 : case State::kSentSigma2Resume:
2484 1 : return SessionEstablishmentStage::kSentSigma2;
2485 0 : case State::kSendSigma3Pending:
2486 0 : return SessionEstablishmentStage::kReceivedSigma2;
2487 0 : case State::kSentSigma3:
2488 0 : return SessionEstablishmentStage::kSentSigma3;
2489 0 : case State::kHandleSigma3Pending:
2490 0 : return SessionEstablishmentStage::kReceivedSigma3;
2491 : // Add more mappings here for other states
2492 0 : default:
2493 0 : return SessionEstablishmentStage::kUnknown; // Default mapping
2494 : }
2495 : }
2496 :
2497 : } // namespace chip
|