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