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