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