diff --git a/src/lib/support/CodeUtils.h b/src/lib/support/CodeUtils.h index 01cc80bffcbe6c..cd07370fa92ec4 100644 --- a/src/lib/support/CodeUtils.h +++ b/src/lib/support/CodeUtils.h @@ -156,6 +156,33 @@ } \ } while (false) +/** + * @def ReturnErrorVariantOnFailure(expr) + * + * @brief + * This is for use when the calling function returns a Variant type. It returns a CHIP_ERROR variant with the corresponding error + * code if the expression returns an error. + * + * Example usage: + * + * @code + * ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1)); + * @endcode + * + * @param[in] variantType The Variant type that the calling function returns. + * @param[in] expr An expression to be tested. + + */ +#define ReturnErrorVariantOnFailure(variantType, expr) \ + do \ + { \ + auto __err = (expr); \ + if (!::chip::ChipError::IsSuccess(__err)) \ + { \ + return variantType::Create(__err); \ + } \ + } while (false) + /** * @def ReturnLogErrorOnFailure(expr) * diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index a012d12fcc56b4..6242cc2aa6199c 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -45,54 +45,71 @@ #include #include #include -#include #include #include #include namespace { +// TBEDataTags works for both sigma-2-tbedata and sigma-3-tbedata as they have the same tag numbers for the elements common between +// them. +enum class TBEDataTags : uint8_t +{ + kSenderNOC = 1, + kSenderICAC = 2, + kSignature = 3, + kResumptionID = 4, +}; -enum +// TBSDataTags works for both sigma-2-tbsdata and sigma-3-tbsdata as they have the same tag numbers for the elements common between +// them. +enum class TBSDataTags : uint8_t { - kTag_TBEData_SenderNOC = 1, - kTag_TBEData_SenderICAC = 2, - kTag_TBEData_Signature = 3, - kTag_TBEData_ResumptionID = 4, + kSenderNOC = 1, + kSenderICAC = 2, + kSenderPubKey = 3, + kReceiverPubKey = 4, }; -enum +enum class Sigma1Tags : uint8_t { - kTag_TBSData_SenderNOC = 1, - kTag_TBSData_SenderICAC = 2, - kTag_TBSData_SenderPubKey = 3, - kTag_TBSData_ReceiverPubKey = 4, + kInitiatorRandom = 1, + kInitiatorSessionId = 2, + kDestinationId = 3, + kInitiatorEphPubKey = 4, + kInitiatorSessionParams = 5, + kResumptionID = 6, + kResume1MIC = 7, }; -enum +enum class Sigma2Tags : uint8_t { - kTag_Sigma1_InitiatorRandom = 1, - kTag_Sigma1_InitiatorSessionId = 2, - kTag_Sigma1_DestinationId = 3, - kTag_Sigma1_InitiatorEphPubKey = 4, - kTag_Sigma1_InitiatorMRPParams = 5, - kTag_Sigma1_ResumptionID = 6, - kTag_Sigma1_InitiatorResumeMIC = 7, + kResponderRandom = 1, + kResponderSessionId = 2, + kResponderEphPubKey = 3, + kEncrypted2 = 4, + kResponderSessionParams = 5, }; -enum +enum class Sigma2ResumeTags : uint8_t { - kTag_Sigma2_ResponderRandom = 1, - kTag_Sigma2_ResponderSessionId = 2, - kTag_Sigma2_ResponderEphPubKey = 3, - kTag_Sigma2_Encrypted2 = 4, - kTag_Sigma2_ResponderMRPParams = 5, + kResumptionID = 1, + kSigma2ResumeMIC = 2, + kResponderSessionID = 3, + kResponderSessionParams = 4, }; -enum +enum class Sigma3Tags : uint8_t { - kTag_Sigma3_Encrypted3 = 1, + kEncrypted3 = 1, }; +// Utility to extract the underlying value of TLV Tag enum classes, used in TLV encoding and parsing. +template +constexpr chip::TLV::Tag AsTlvContextTag(Enum e) +{ + return chip::TLV::ContextTag(chip::to_underlying(e)); +} + } // namespace namespace chip { @@ -103,6 +120,7 @@ using namespace Messaging; using namespace Encoding; using namespace Protocols::SecureChannel; using namespace Tracing; +using namespace TLV; constexpr uint8_t kKDFSR2Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x32 }; constexpr uint8_t kKDFSR3Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x33 }; @@ -778,42 +796,29 @@ void CASESession::HandleConnectionClosed(Transport::ActiveTCPConnectionState * c CHIP_ERROR CASESession::SendSigma1() { MATTER_TRACE_SCOPE("SendSigma1", "CASESession"); - size_t data_len = TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, // initiatorRandom - sizeof(uint16_t), // initiatorSessionId, - kSHA256_Hash_Length, // destinationId - kP256_PublicKey_Length, // InitiatorEphPubKey, - SessionParameters::kEstimatedTLVSize, // initiatorSessionParams - SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES); - System::PacketBufferTLVWriter tlvWriter; - System::PacketBufferHandle msg_R1; - TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; uint8_t destinationIdentifier[kSHA256_Hash_Length] = { 0 }; + // Struct that will be used as input to EncodeSigma1() method + EncodeSigma1Inputs encodeSigma1Inputs; + // Lookup fabric info. const auto * fabricInfo = mFabricsTable->FindFabricWithIndex(mFabricIndex); VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INCORRECT_STATE); // Validate that we have a session ID allocated. VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE); + encodeSigma1Inputs.initiatorSessionId = GetLocalSessionId().Value(); // Generate an ephemeral keypair mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE(); VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY); ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH)); + encodeSigma1Inputs.initiatorEphPubKey = &mEphemeralKey->Pubkey(); // Fill in the random value ReturnErrorOnFailure(DRBG_get_bytes(mInitiatorRandom, sizeof(mInitiatorRandom))); - - // Construct Sigma1 Msg - msg_R1 = System::PacketBufferHandle::New(data_len); - VerifyOrReturnError(!msg_R1.IsNull(), CHIP_ERROR_NO_MEMORY); - - tlvWriter.Init(std::move(msg_R1)); - ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), ByteSpan(mInitiatorRandom))); - // Retrieve Session Identifier - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), GetLocalSessionId().Value())); + encodeSigma1Inputs.initiatorRandom = ByteSpan(mInitiatorRandom); // Generate a Destination Identifier based on the node we are attempting to reach { @@ -827,19 +832,15 @@ CHIP_ERROR CASESession::SendSigma1() Credentials::P256PublicKeySpan rootPubKeySpan{ rootPubKey.ConstBytes() }; MutableByteSpan destinationIdSpan(destinationIdentifier); - ReturnErrorOnFailure(GenerateCaseDestinationId(ByteSpan(mIPK), ByteSpan(mInitiatorRandom), rootPubKeySpan, fabricId, + ReturnErrorOnFailure(GenerateCaseDestinationId(ByteSpan(mIPK), encodeSigma1Inputs.initiatorRandom, rootPubKeySpan, fabricId, mPeerNodeId, destinationIdSpan)); + encodeSigma1Inputs.destinationId = destinationIdSpan; } - ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(3), destinationIdentifier, sizeof(destinationIdentifier))); - - ReturnErrorOnFailure( - tlvWriter.PutBytes(TLV::ContextTag(4), mEphemeralKey->Pubkey(), static_cast(mEphemeralKey->Pubkey().Length()))); VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter)); + encodeSigma1Inputs.initiatorMrpConfig = &mLocalMRPConfig.Value(); // Try to find persistent session, and resume it. - bool resuming = false; if (mSessionResumptionStorage != nullptr) { CHIP_ERROR err = mSessionResumptionStorage->FindByScopedNodeId(fabricInfo->GetScopedNodeIdForNode(mPeerNodeId), @@ -847,28 +848,28 @@ CHIP_ERROR CASESession::SendSigma1() if (err == CHIP_NO_ERROR) { // Found valid resumption state, try to resume the session. - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(6), mResumeResumptionId)); - - uint8_t initiatorResume1MIC[CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES]; - MutableByteSpan resumeMICSpan(initiatorResume1MIC); - ReturnErrorOnFailure(GenerateSigmaResumeMIC(ByteSpan(mInitiatorRandom), ByteSpan(mResumeResumptionId), + encodeSigma1Inputs.resumptionId = mResumeResumptionId; + MutableByteSpan resumeMICSpan(encodeSigma1Inputs.initiatorResume1MICBuffer); + ReturnErrorOnFailure(GenerateSigmaResumeMIC(encodeSigma1Inputs.initiatorRandom, encodeSigma1Inputs.resumptionId, ByteSpan(kKDFS1RKeyInfo), ByteSpan(kResume1MIC_Nonce), resumeMICSpan)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(7), resumeMICSpan)); - resuming = true; + encodeSigma1Inputs.initiatorResumeMIC = resumeMICSpan; + encodeSigma1Inputs.sessionResumptionRequested = true; } } - ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Finalize(&msg_R1)); + System::PacketBufferHandle msgR1; + + // Encode Sigma1 in CHIP TLV Format + ReturnErrorOnFailure(EncodeSigma1(msgR1, encodeSigma1Inputs)); - ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msg_R1->Start(), msg_R1->DataLength() })); + ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msgR1->Start(), msgR1->DataLength() })); // Call delegate to send the msg to peer - ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma1, std::move(msg_R1), + ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma1, std::move(msgR1), SendFlags(SendMessageFlags::kExpectResponse))); - if (resuming) + if (encodeSigma1Inputs.sessionResumptionRequested) { mState = State::kSentSigma1Resume; @@ -892,12 +893,109 @@ CHIP_ERROR CASESession::SendSigma1() return CHIP_NO_ERROR; } +CHIP_ERROR CASESession::EncodeSigma1(System::PacketBufferHandle & msg, EncodeSigma1Inputs & input) +{ + MATTER_TRACE_SCOPE("EncodeSigma1", "CASESession"); + + VerifyOrReturnError(input.initiatorEphPubKey != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + size_t dataLen = EstimateStructOverhead(kSigmaParamRandomNumberSize, // initiatorRandom + sizeof(uint16_t), // initiatorSessionId, + kSHA256_Hash_Length, // destinationId + kP256_PublicKey_Length, // InitiatorEphPubKey, + SessionParameters::kEstimatedTLVSize, // initiatorSessionParams + SessionResumptionStorage::kResumptionIdSize, // resumptionId + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES // initiatorResumeMIC + ); + + msg = System::PacketBufferHandle::New(dataLen); + VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_NO_MEMORY); + + System::PacketBufferTLVWriter tlvWriter; + tlvWriter.Init(std::move(msg)); + + TLVType outerContainerType = kTLVType_NotSpecified; + ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kInitiatorRandom), input.initiatorRandom)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kInitiatorSessionId), input.initiatorSessionId)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kDestinationId), input.destinationId)); + + ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(Sigma1Tags::kInitiatorEphPubKey), *input.initiatorEphPubKey, + static_cast(input.initiatorEphPubKey->Length()))); + + VerifyOrReturnError(input.initiatorMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + ReturnErrorOnFailure( + EncodeSessionParameters(AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams), *input.initiatorMrpConfig, tlvWriter)); + + if (input.sessionResumptionRequested) + { + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kResumptionID), input.resumptionId)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma1Tags::kResume1MIC), input.initiatorResumeMIC)); + } + + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Finalize(&msg)); + + return CHIP_NO_ERROR; +} + CHIP_ERROR CASESession::HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg) { MATTER_TRACE_SCOPE("HandleSigma1_and_SendSigma2", "CASESession"); - ReturnErrorOnFailure(HandleSigma1(std::move(msg))); - return CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + + // Parse and Validate Received Sigma1, and decide next step + NextStep nextStep = HandleSigma1(std::move(msg)); + VerifyOrExit(nextStep.Is(), err = nextStep.Get()); + + switch (nextStep.Get()) + { + case Step::kSendSigma2: { + + System::PacketBufferHandle msgR2; + EncodeSigma2Inputs encodeSigma2; + + SuccessOrExit(err = PrepareSigma2(encodeSigma2)); + SuccessOrExit(err = EncodeSigma2(msgR2, encodeSigma2)); + + MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2); + SuccessOrExitAction(err = SendSigma2(std::move(msgR2)), MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err)); + + mDelegate->OnSessionEstablishmentStarted(); + break; + } + case Step::kSendSigma2Resume: { + + System::PacketBufferHandle msgR2Resume; + EncodeSigma2ResumeInputs encodeSigma2Resume; + + SuccessOrExit(err = PrepareSigma2Resume(encodeSigma2Resume)); + SuccessOrExit(err = EncodeSigma2Resume(msgR2Resume, encodeSigma2Resume)); + + MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2Resume); + SuccessOrExitAction(err = SendSigma2Resume(std::move(msgR2Resume)), + MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2Resume, err)); + + mDelegate->OnSessionEstablishmentStarted(); + break; + } + default: + break; + } + +exit: + if (err == CHIP_ERROR_KEY_NOT_FOUND) + { + SendStatusReport(mExchangeCtxt, kProtocolCodeNoSharedRoot); + mState = State::kInitialized; + } + else if (err != CHIP_NO_ERROR) + { + SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam); + mState = State::kInitialized; + } + return err; } CHIP_ERROR CASESession::FindLocalNodeFromDestinationId(const ByteSpan & destinationId, const ByteSpan & initiatorRandom) @@ -931,7 +1029,7 @@ CHIP_ERROR CASESession::FindLocalNodeFromDestinationId(const ByteSpan & destinat MutableByteSpan candidateDestinationIdSpan(candidateDestinationId); ByteSpan candidateIpkSpan(ipkKeySet.epoch_keys[keyIdx].key); - err = GenerateCaseDestinationId(ByteSpan(candidateIpkSpan), ByteSpan(initiatorRandom), rootPubKeySpan, fabricId, nodeId, + err = GenerateCaseDestinationId(candidateIpkSpan, initiatorRandom, rootPubKeySpan, fabricId, nodeId, candidateDestinationIdSpan); if ((err == CHIP_NO_ERROR) && (candidateDestinationIdSpan.data_equal(destinationId))) { @@ -978,60 +1076,56 @@ CHIP_ERROR CASESession::TryResumeSession(SessionResumptionStorage::ConstResumpti return CHIP_NO_ERROR; } - -CHIP_ERROR CASESession::HandleSigma1(System::PacketBufferHandle && msg) +CASESession::NextStep CASESession::HandleSigma1(System::PacketBufferHandle && msg) { MATTER_TRACE_SCOPE("HandleSigma1", "CASESession"); - CHIP_ERROR err = CHIP_NO_ERROR; - System::PacketBufferTLVReader tlvReader; - - uint16_t initiatorSessionId; - ByteSpan destinationIdentifier; - ByteSpan initiatorRandom; - ChipLogProgress(SecureChannel, "Received Sigma1 msg"); MATTER_TRACE_COUNTER("Sigma1"); - bool sessionResumptionRequested = false; - ByteSpan resumptionId; - ByteSpan resume1MIC; - ByteSpan initiatorPubKey; + VerifyOrReturnError(mFabricsTable != nullptr, NextStep::Create(CHIP_ERROR_INCORRECT_STATE)); - SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() })); + ReturnErrorVariantOnFailure(NextStep, mCommissioningHash.AddData(ByteSpan{ msg->Start(), msg->DataLength() })); + System::PacketBufferTLVReader tlvReader; tlvReader.Init(std::move(msg)); - SuccessOrExit(err = ParseSigma1(tlvReader, initiatorRandom, initiatorSessionId, destinationIdentifier, initiatorPubKey, - sessionResumptionRequested, resumptionId, resume1MIC)); - ChipLogDetail(SecureChannel, "Peer assigned session key ID %d", initiatorSessionId); - SetPeerSessionId(initiatorSessionId); + // Struct that will serve as output in ParseSigma1 + ParsedSigma1 parsedSigma1; + + ReturnErrorVariantOnFailure(NextStep, ParseSigma1(tlvReader, parsedSigma1)); + + ChipLogDetail(SecureChannel, "Peer assigned session key ID %d", parsedSigma1.initiatorSessionId); + SetPeerSessionId(parsedSigma1.initiatorSessionId); - VerifyOrExit(mFabricsTable != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + // Set the MRP parameters provided in the Sigma1 message + if (parsedSigma1.initiatorMrpParamsPresent) + { + mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters( + GetRemoteSessionParameters()); + } - if (sessionResumptionRequested && resumptionId.size() == SessionResumptionStorage::kResumptionIdSize && + if (parsedSigma1.sessionResumptionRequested && + parsedSigma1.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize && CHIP_NO_ERROR == - TryResumeSession(SessionResumptionStorage::ConstResumptionIdView(resumptionId.data()), resume1MIC, initiatorRandom)) + TryResumeSession(SessionResumptionStorage::ConstResumptionIdView(parsedSigma1.resumptionId.data()), + parsedSigma1.initiatorResumeMIC, parsedSigma1.initiatorRandom)) { - std::copy(initiatorRandom.begin(), initiatorRandom.end(), mInitiatorRandom); - std::copy(resumptionId.begin(), resumptionId.end(), mResumeResumptionId.begin()); + std::copy(parsedSigma1.initiatorRandom.begin(), parsedSigma1.initiatorRandom.end(), mInitiatorRandom); + std::copy(parsedSigma1.resumptionId.begin(), parsedSigma1.resumptionId.end(), mResumeResumptionId.begin()); - // Send Sigma2Resume message to the initiator - MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2Resume); - err = SendSigma2Resume(); - if (CHIP_NO_ERROR != err) - { - MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2Resume, err); - } - SuccessOrExit(err); + // Early returning here, since the next Step is known to be Sigma2Resume, and no further processing is needed for the + // Sigma1 message + return NextStep::Create(Step::kSendSigma2Resume); + } - mDelegate->OnSessionEstablishmentStarted(); + // ParseSigma1 ensures that: + // mRemotePubKey.Length() == initiatorPubKey.size() == kP256_PublicKey_Length. + memcpy(mRemotePubKey.Bytes(), parsedSigma1.initiatorEphPubKey.data(), mRemotePubKey.Length()); - // Early returning here, since we have sent Sigma2Resume, and no further processing is needed for the Sigma1 message - return CHIP_NO_ERROR; - } + CHIP_ERROR err = CHIP_NO_ERROR; // Attempt to match the initiator's desired destination based on local fabric table. - err = FindLocalNodeFromDestinationId(destinationIdentifier, initiatorRandom); + err = FindLocalNodeFromDestinationId(parsedSigma1.destinationId, parsedSigma1.initiatorRandom); if (err == CHIP_NO_ERROR) { ChipLogProgress(SecureChannel, "CASE matched destination ID: fabricIndex %u, NodeID 0x" ChipLogFormatX64, @@ -1039,87 +1133,82 @@ CHIP_ERROR CASESession::HandleSigma1(System::PacketBufferHandle && msg) // Side-effect of FindLocalNodeFromDestinationId success was that mFabricIndex/mLocalNodeId are now // set to the local fabric and associated NodeId that was targeted by the initiator. - } - else - { - ChipLogError(SecureChannel, "CASE failed to match destination ID with local fabrics"); - ChipLogByteSpan(SecureChannel, destinationIdentifier); - } - SuccessOrExit(err); - - // ParseSigma1 ensures that: - // mRemotePubKey.Length() == initiatorPubKey.size() == kP256_PublicKey_Length. - memcpy(mRemotePubKey.Bytes(), initiatorPubKey.data(), mRemotePubKey.Length()); - MATTER_LOG_METRIC_BEGIN(kMetricDeviceCASESessionSigma2); - err = SendSigma2(); - if (CHIP_NO_ERROR != err) - { - MATTER_LOG_METRIC_END(kMetricDeviceCASESessionSigma2, err); + return NextStep::Create(Step::kSendSigma2); } - SuccessOrExit(err); - mDelegate->OnSessionEstablishmentStarted(); + ChipLogError(SecureChannel, "CASE failed to match destination ID with local fabrics"); + ChipLogByteSpan(SecureChannel, parsedSigma1.destinationId); -exit: + // FindLocalNodeFromDestinationId returns CHIP_ERROR_KEY_NOT_FOUND if Sigma1's DestinationId does not match any + // candidateDestinationId, this will trigger a status Report with ProtocolCode = NoSharedTrustRoots. - if (err == CHIP_ERROR_KEY_NOT_FOUND) - { - SendStatusReport(mExchangeCtxt, kProtocolCodeNoSharedRoot); - mState = State::kInitialized; - } - else if (err != CHIP_NO_ERROR) - { - SendStatusReport(mExchangeCtxt, kProtocolCodeInvalidParam); - mState = State::kInitialized; - } - return err; + // Returning a CHIP_ERROR variant that will trigger a corresponding Status Report. + return NextStep::Create(err); } -CHIP_ERROR CASESession::SendSigma2Resume() +CHIP_ERROR CASESession::PrepareSigma2Resume(EncodeSigma2ResumeInputs & outSigma2ResData) { - MATTER_TRACE_SCOPE("SendSigma2Resume", "CASESession"); - size_t max_sigma2_resume_data_len = - TLV::EstimateStructOverhead(SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, - sizeof(uint16_t), SessionParameters::kEstimatedTLVSize); + MATTER_TRACE_SCOPE("PrepareSigma2Resume", "CASESession"); - System::PacketBufferTLVWriter tlvWriter; - System::PacketBufferHandle msg_R2_resume; - TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; + VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE); // Validate that we have a session ID allocated. VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE); - - msg_R2_resume = System::PacketBufferHandle::New(max_sigma2_resume_data_len); - VerifyOrReturnError(!msg_R2_resume.IsNull(), CHIP_ERROR_NO_MEMORY); - - tlvWriter.Init(std::move(msg_R2_resume)); + outSigma2ResData.responderSessionId = GetLocalSessionId().Value(); // Generate a new resumption ID ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size())); + outSigma2ResData.resumptionId = mNewResumptionId; - ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), mNewResumptionId)); - - uint8_t sigma2ResumeMIC[CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES]; - MutableByteSpan resumeMICSpan(sigma2ResumeMIC); ReturnErrorOnFailure(GenerateSigmaResumeMIC(ByteSpan(mInitiatorRandom), mNewResumptionId, ByteSpan(kKDFS2RKeyInfo), - ByteSpan(kResume2MIC_Nonce), resumeMICSpan)); + ByteSpan(kResume2MIC_Nonce), outSigma2ResData.resumeMIC)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), resumeMICSpan)); + outSigma2ResData.responderMrpConfig = &mLocalMRPConfig.Value(); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), GetLocalSessionId().Value())); + return CHIP_NO_ERROR; +} - VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(4), mLocalMRPConfig.Value(), tlvWriter)); +CHIP_ERROR CASESession::EncodeSigma2Resume(System::PacketBufferHandle & msgR2Resume, EncodeSigma2ResumeInputs & input) +{ + MATTER_TRACE_SCOPE("EncodeSigma2Resume", "CASESession"); + + VerifyOrReturnError(input.responderMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + size_t maxDatalLen = EstimateStructOverhead(SessionResumptionStorage::kResumptionIdSize, // resumptionID + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, // sigma2ResumeMIC + sizeof(uint16_t), // responderSessionID + SessionParameters::kEstimatedTLVSize // responderSessionParams + ); + + msgR2Resume = System::PacketBufferHandle::New(maxDatalLen); + VerifyOrReturnError(!msgR2Resume.IsNull(), CHIP_ERROR_NO_MEMORY); + + System::PacketBufferTLVWriter tlvWriter; + tlvWriter.Init(std::move(msgR2Resume)); + + TLVType outerContainerType = kTLVType_NotSpecified; + + ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kResumptionID), input.resumptionId)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kSigma2ResumeMIC), input.resumeMIC)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionID), input.responderSessionId)); + + ReturnErrorOnFailure( + EncodeSessionParameters(AsTlvContextTag(Sigma2ResumeTags::kResponderSessionParams), *input.responderMrpConfig, tlvWriter)); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Finalize(&msg_R2_resume)); + ReturnErrorOnFailure(tlvWriter.Finalize(&msgR2Resume)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR CASESession::SendSigma2Resume(System::PacketBufferHandle && msgR2Resume) +{ // Call delegate to send the msg to peer ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2Resume, - std::move(msg_R2_resume), - SendFlags(SendMessageFlags::kExpectResponse))); + std::move(msgR2Resume), SendFlags(SendMessageFlags::kExpectResponse))); mState = State::kSentSigma2Resume; @@ -1128,12 +1217,15 @@ CHIP_ERROR CASESession::SendSigma2Resume() return CHIP_NO_ERROR; } -CHIP_ERROR CASESession::SendSigma2() +CHIP_ERROR CASESession::PrepareSigma2(EncodeSigma2Inputs & outSigma2Data) { - MATTER_TRACE_SCOPE("SendSigma2", "CASESession"); - VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE); + MATTER_TRACE_SCOPE("PrepareSigma2", "CASESession"); + VerifyOrReturnError(mFabricsTable != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(GetLocalSessionId().HasValue(), CHIP_ERROR_INCORRECT_STATE); + outSigma2Data.responderSessionId = GetLocalSessionId().Value(); chip::Platform::ScopedMemoryBuffer icacBuf; VerifyOrReturnError(icacBuf.Alloc(kMaxCHIPCertLength), CHIP_ERROR_NO_MEMORY); @@ -1148,57 +1240,65 @@ CHIP_ERROR CASESession::SendSigma2() ReturnErrorOnFailure(mFabricsTable->FetchNOCCert(mFabricIndex, nocCert)); // Fill in the random value - uint8_t msg_rand[kSigmaParamRandomNumberSize]; - ReturnErrorOnFailure(DRBG_get_bytes(&msg_rand[0], sizeof(msg_rand))); + ReturnErrorOnFailure(DRBG_get_bytes(&outSigma2Data.responderRandom[0], sizeof(outSigma2Data.responderRandom))); // Generate an ephemeral keypair mEphemeralKey = mFabricsTable->AllocateEphemeralKeypairForCASE(); VerifyOrReturnError(mEphemeralKey != nullptr, CHIP_ERROR_NO_MEMORY); ReturnErrorOnFailure(mEphemeralKey->Initialize(ECPKeyTarget::ECDH)); + outSigma2Data.responderEphPubKey = &mEphemeralKey->Pubkey(); // Generate a Shared Secret ReturnErrorOnFailure(mEphemeralKey->ECDH_derive_secret(mRemotePubKey, mSharedSecret)); - uint8_t msg_salt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length]; + uint8_t msgSalt[kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length]; - MutableByteSpan saltSpan(msg_salt); - ReturnErrorOnFailure(ConstructSaltSigma2(ByteSpan(msg_rand), mEphemeralKey->Pubkey(), ByteSpan(mIPK), saltSpan)); + MutableByteSpan saltSpan(msgSalt); + ReturnErrorOnFailure( + ConstructSaltSigma2(ByteSpan(outSigma2Data.responderRandom), mEphemeralKey->Pubkey(), ByteSpan(mIPK), saltSpan)); AutoReleaseSessionKey sr2k(*mSessionManager->GetSessionKeystore()); ReturnErrorOnFailure(DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR2Info), sr2k)); // Construct Sigma2 TBS Data - size_t msg_r2_signed_len = - TLV::EstimateStructOverhead(kMaxCHIPCertLength, kMaxCHIPCertLength, kP256_PublicKey_Length, kP256_PublicKey_Length); + size_t msgR2SignedLen = EstimateStructOverhead(kMaxCHIPCertLength, // responderNoc + kMaxCHIPCertLength, // responderICAC + kP256_PublicKey_Length, // responderEphPubKey + kP256_PublicKey_Length // InitiatorEphPubKey + ); - chip::Platform::ScopedMemoryBuffer msg_R2_Signed; - VerifyOrReturnError(msg_R2_Signed.Alloc(msg_r2_signed_len), CHIP_ERROR_NO_MEMORY); - - ReturnErrorOnFailure(ConstructTBSData(nocCert, icaCert, ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), - ByteSpan(mRemotePubKey, mRemotePubKey.Length()), msg_R2_Signed.Get(), msg_r2_signed_len)); - - // Generate a Signature P256ECDSASignature tbsData2Signature; - ReturnErrorOnFailure( - mFabricsTable->SignWithOpKeypair(mFabricIndex, ByteSpan{ msg_R2_Signed.Get(), msg_r2_signed_len }, tbsData2Signature)); - msg_R2_Signed.Free(); + { + chip::Platform::ScopedMemoryBuffer msgR2Signed; + VerifyOrReturnError(msgR2Signed.Alloc(msgR2SignedLen), CHIP_ERROR_NO_MEMORY); + + ReturnErrorOnFailure(ConstructTBSData(nocCert, icaCert, ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), + ByteSpan(mRemotePubKey, mRemotePubKey.Length()), msgR2Signed.Get(), msgR2SignedLen)); + // Generate a Signature + ReturnErrorOnFailure( + mFabricsTable->SignWithOpKeypair(mFabricIndex, ByteSpan{ msgR2Signed.Get(), msgR2SignedLen }, tbsData2Signature)); + } // Construct Sigma2 TBE Data - size_t msg_r2_signed_enc_len = TLV::EstimateStructOverhead(nocCert.size(), icaCert.size(), tbsData2Signature.Length(), - SessionResumptionStorage::kResumptionIdSize); + size_t msgR2SignedEncLen = EstimateStructOverhead(nocCert.size(), // responderNoc + icaCert.size(), // responderICAC + tbsData2Signature.Length(), // signature + SessionResumptionStorage::kResumptionIdSize // resumptionID + ); - chip::Platform::ScopedMemoryBuffer msg_R2_Encrypted; - VerifyOrReturnError(msg_R2_Encrypted.Alloc(msg_r2_signed_enc_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES), CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(outSigma2Data.msgR2Encrypted.Alloc(msgR2SignedEncLen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES), + CHIP_ERROR_NO_MEMORY); - TLV::TLVWriter tlvWriter; - TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified; + TLVWriter tlvWriter; + tlvWriter.Init(outSigma2Data.msgR2Encrypted.Get(), msgR2SignedEncLen); - tlvWriter.Init(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len); - ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderNOC), nocCert)); + TLVType outerContainerType = kTLVType_NotSpecified; + + ReturnErrorOnFailure(tlvWriter.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderNOC), nocCert)); if (!icaCert.empty()) { - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderICAC), icaCert)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderICAC), icaCert)); } // We are now done with ICAC and NOC certs so we can release the memory. @@ -1210,53 +1310,81 @@ CHIP_ERROR CASESession::SendSigma2() nocCert = MutableByteSpan{}; } - ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kTag_TBEData_Signature), tbsData2Signature.ConstBytes(), + ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(TBEDataTags::kSignature), tbsData2Signature.ConstBytes(), static_cast(tbsData2Signature.Length()))); // Generate a new resumption ID ReturnErrorOnFailure(DRBG_get_bytes(mNewResumptionId.data(), mNewResumptionId.size())); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_ResumptionID), mNewResumptionId)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kResumptionID), mNewResumptionId)); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize()); - msg_r2_signed_enc_len = static_cast(tlvWriter.GetLengthWritten()); - + msgR2SignedEncLen = static_cast(tlvWriter.GetLengthWritten()); + outSigma2Data.encrypted2Length = msgR2SignedEncLen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; // Generate the encrypted data blob - ReturnErrorOnFailure(AES_CCM_encrypt(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len, nullptr, 0, sr2k.KeyHandle(), - kTBEData2_Nonce, kTBEDataNonceLength, msg_R2_Encrypted.Get(), - msg_R2_Encrypted.Get() + msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); + ReturnErrorOnFailure(AES_CCM_encrypt(outSigma2Data.msgR2Encrypted.Get(), msgR2SignedEncLen, nullptr, 0, sr2k.KeyHandle(), + kTBEData2_Nonce, kTBEDataNonceLength, outSigma2Data.msgR2Encrypted.Get(), + outSigma2Data.msgR2Encrypted.Get() + msgR2SignedEncLen, + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); + + outSigma2Data.responderMrpConfig = &mLocalMRPConfig.Value(); - // Construct Sigma2 Msg - size_t size_of_local_session_id = sizeof(uint16_t); - size_t data_len = - TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, size_of_local_session_id, kP256_PublicKey_Length, - msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, SessionParameters::kEstimatedTLVSize); + return CHIP_NO_ERROR; +} - System::PacketBufferHandle msg_R2 = System::PacketBufferHandle::New(data_len); - VerifyOrReturnError(!msg_R2.IsNull(), CHIP_ERROR_NO_MEMORY); +CHIP_ERROR CASESession::EncodeSigma2(System::PacketBufferHandle & msgR2, EncodeSigma2Inputs & input) +{ + VerifyOrReturnError(input.responderEphPubKey != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(input.msgR2Encrypted, CHIP_ERROR_INCORRECT_STATE); + // Check if length of msgR2Encrypted is set and is at least larger than the MIC length + VerifyOrReturnError(input.encrypted2Length > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(input.responderMrpConfig != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + size_t dataLen = EstimateStructOverhead(kSigmaParamRandomNumberSize, // responderRandom + sizeof(uint16_t), // responderSessionId + kP256_PublicKey_Length, // responderEphPubKey + input.encrypted2Length, // encrypted2 + SessionParameters::kEstimatedTLVSize // responderSessionParams + ); + + msgR2 = System::PacketBufferHandle::New(dataLen); + VerifyOrReturnError(!msgR2.IsNull(), CHIP_ERROR_NO_MEMORY); System::PacketBufferTLVWriter tlvWriterMsg2; - outerContainerType = TLV::kTLVType_NotSpecified; + tlvWriterMsg2.Init(std::move(msgR2)); - tlvWriterMsg2.Init(std::move(msg_R2)); - ReturnErrorOnFailure(tlvWriterMsg2.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(1), &msg_rand[0], sizeof(msg_rand))); - ReturnErrorOnFailure(tlvWriterMsg2.Put(TLV::ContextTag(2), GetLocalSessionId().Value())); - ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(3), mEphemeralKey->Pubkey(), - static_cast(mEphemeralKey->Pubkey().Length()))); - ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(TLV::ContextTag(4), msg_R2_Encrypted.Get(), - static_cast(msg_r2_signed_enc_len + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES))); + TLVType outerContainerType = kTLVType_NotSpecified; - VerifyOrReturnError(mLocalMRPConfig.HasValue(), CHIP_ERROR_INCORRECT_STATE); - ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriterMsg2)); + ReturnErrorOnFailure(tlvWriterMsg2.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType)); + + ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kResponderRandom), &input.responderRandom[0], + sizeof(input.responderRandom))); + ReturnErrorOnFailure(tlvWriterMsg2.Put(AsTlvContextTag(Sigma2Tags::kResponderSessionId), input.responderSessionId)); + + ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kResponderEphPubKey), *input.responderEphPubKey, + static_cast(input.responderEphPubKey->Length()))); + + ReturnErrorOnFailure(tlvWriterMsg2.PutBytes(AsTlvContextTag(Sigma2Tags::kEncrypted2), input.msgR2Encrypted.Get(), + static_cast(input.encrypted2Length))); + input.msgR2Encrypted.Free(); + + ReturnErrorOnFailure( + EncodeSessionParameters(AsTlvContextTag(Sigma2Tags::kResponderSessionParams), *input.responderMrpConfig, tlvWriterMsg2)); ReturnErrorOnFailure(tlvWriterMsg2.EndContainer(outerContainerType)); - ReturnErrorOnFailure(tlvWriterMsg2.Finalize(&msg_R2)); + ReturnErrorOnFailure(tlvWriterMsg2.Finalize(&msgR2)); + + return CHIP_NO_ERROR; +} - ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msg_R2->Start(), msg_R2->DataLength() })); +CHIP_ERROR CASESession::SendSigma2(System::PacketBufferHandle && msgR2) +{ + MATTER_TRACE_SCOPE("SendSigma2", "CASESession"); + + ReturnErrorOnFailure(mCommissioningHash.AddData(ByteSpan{ msgR2->Start(), msgR2->DataLength() })); // Call delegate to send the msg to peer - ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2, std::move(msg_R2), + ReturnErrorOnFailure(mExchangeCtxt.Value()->SendMessage(Protocols::SecureChannel::MsgType::CASE_Sigma2, std::move(msgR2), SendFlags(SendMessageFlags::kExpectResponse))); mState = State::kSentSigma2; @@ -1406,18 +1534,18 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) SuccessOrExit(err = tlvReader.EnterContainer(containerType)); // Retrieve Responder's Random value - SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_ResponderRandom))); + SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(Sigma2Tags::kResponderRandom))); SuccessOrExit(err = tlvReader.GetBytes(responderRandom, sizeof(responderRandom))); // Assign Session ID - SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_UnsignedInteger, TLV::ContextTag(kTag_Sigma2_ResponderSessionId))); + SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_UnsignedInteger, AsTlvContextTag(Sigma2Tags::kResponderSessionId))); SuccessOrExit(err = tlvReader.Get(responderSessionId)); ChipLogDetail(SecureChannel, "Peer assigned session session ID %d", responderSessionId); SetPeerSessionId(responderSessionId); // Retrieve Responder's Ephemeral Pubkey - SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_ResponderEphPubKey))); + SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(Sigma2Tags::kResponderEphPubKey))); SuccessOrExit(err = tlvReader.GetBytes(mRemotePubKey, static_cast(mRemotePubKey.Length()))); // Generate a Shared Secret @@ -1433,7 +1561,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, buflen })); // Generate decrypted data - SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma2_Encrypted2))); + SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(Sigma2Tags::kEncrypted2))); max_msg_r2_signed_enc_len = TLV::EstimateStructOverhead(Credentials::kMaxCHIPCertLength, Credentials::kMaxCHIPCertLength, tbsData2Signature.Length(), @@ -1457,15 +1585,15 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) SuccessOrExit(err = decryptedDataTlvReader.Next(containerType, TLV::AnonymousTag())); SuccessOrExit(err = decryptedDataTlvReader.EnterContainer(containerType)); - SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_SenderNOC))); + SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSenderNOC))); SuccessOrExit(err = decryptedDataTlvReader.Get(responderNOC)); SuccessOrExit(err = decryptedDataTlvReader.Next()); - if (TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_SenderICAC) + if (decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSenderICAC)) { VerifyOrExit(decryptedDataTlvReader.GetType() == TLV::kTLVType_ByteString, err = CHIP_ERROR_WRONG_TLV_TYPE); SuccessOrExit(err = decryptedDataTlvReader.Get(responderICAC)); - SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_Signature))); + SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSignature))); } // Validate responder identity located in msg_r2_encrypted @@ -1492,7 +1620,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), msg_R2_Signed.Get(), msg_r2_signed_len)); - VerifyOrExit(TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_Signature, err = CHIP_ERROR_INVALID_TLV_TAG); + VerifyOrExit(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), err = CHIP_ERROR_INVALID_TLV_TAG); VerifyOrExit(tbsData2Signature.Capacity() >= decryptedDataTlvReader.GetLength(), err = CHIP_ERROR_INVALID_TLV_ELEMENT); tbsData2Signature.SetLength(decryptedDataTlvReader.GetLength()); SuccessOrExit(err = decryptedDataTlvReader.GetBytes(tbsData2Signature.Bytes(), tbsData2Signature.Length())); @@ -1501,7 +1629,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) SuccessOrExit(err = responderPublicKey.ECDSA_validate_msg_signature(msg_R2_Signed.Get(), msg_r2_signed_len, tbsData2Signature)); // Retrieve session resumption ID - SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_ResumptionID))); + SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kResumptionID))); SuccessOrExit(err = decryptedDataTlvReader.GetBytes(mNewResumptionId.data(), mNewResumptionId.size())); // Retrieve peer CASE Authenticated Tags (CATs) from peer's NOC. @@ -1510,7 +1638,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) // Retrieve responderMRPParams if present if (tlvReader.Next() != CHIP_END_OF_TLV) { - SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(kTag_Sigma2_ResponderMRPParams), tlvReader)); + SuccessOrExit(err = DecodeMRPParametersIfPresent(AsTlvContextTag(Sigma2Tags::kResponderSessionParams), tlvReader)); mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters( GetRemoteSessionParameters()); } @@ -1629,10 +1757,10 @@ CHIP_ERROR CASESession::SendSigma3b(SendSigma3Data & data, bool & cancel) tlvWriter.Init(data.msg_R3_Encrypted.Get(), data.msg_r3_encrypted_len); ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderNOC), data.nocCert)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderNOC), data.nocCert)); if (!data.icaCert.empty()) { - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBEData_SenderICAC), data.icaCert)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBEDataTags::kSenderICAC), data.icaCert)); } // We are now done with ICAC and NOC certs so we can release the memory. @@ -1644,7 +1772,7 @@ CHIP_ERROR CASESession::SendSigma3b(SendSigma3Data & data, bool & cancel) data.nocCert = MutableByteSpan{}; } - ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kTag_TBEData_Signature), data.tbsData3Signature.ConstBytes(), + ReturnErrorOnFailure(tlvWriter.PutBytes(AsTlvContextTag(TBEDataTags::kSignature), data.tbsData3Signature.ConstBytes(), static_cast(data.tbsData3Signature.Length()))); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize()); @@ -1785,7 +1913,7 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) max_msg_r3_signed_enc_len = TLV::EstimateStructOverhead(Credentials::kMaxCHIPCertLength, Credentials::kMaxCHIPCertLength, data.tbsData3Signature.Length(), kCaseOverheadForFutureTbeData); - SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_Sigma3_Encrypted3))); + SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(Sigma3Tags::kEncrypted3))); msg_r3_encrypted_len_with_tag = tlvReader.GetLength(); @@ -1816,15 +1944,15 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) SuccessOrExit(err = decryptedDataTlvReader.Next(containerType, TLV::AnonymousTag())); SuccessOrExit(err = decryptedDataTlvReader.EnterContainer(containerType)); - SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_SenderNOC))); + SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSenderNOC))); SuccessOrExit(err = decryptedDataTlvReader.Get(data.initiatorNOC)); SuccessOrExit(err = decryptedDataTlvReader.Next()); - if (TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_SenderICAC) + if (decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSenderICAC)) { VerifyOrExit(decryptedDataTlvReader.GetType() == TLV::kTLVType_ByteString, err = CHIP_ERROR_WRONG_TLV_TYPE); SuccessOrExit(err = decryptedDataTlvReader.Get(data.initiatorICAC)); - SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBEData_Signature))); + SuccessOrExit(err = decryptedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBEDataTags::kSignature))); } // Step 4 - Construct Sigma3 TBS Data @@ -1837,8 +1965,7 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) ByteSpan(mEphemeralKey->Pubkey(), mEphemeralKey->Pubkey().Length()), data.msg_R3_Signed.Get(), data.msg_r3_signed_len)); - VerifyOrExit(TLV::TagNumFromTag(decryptedDataTlvReader.GetTag()) == kTag_TBEData_Signature, - err = CHIP_ERROR_INVALID_TLV_TAG); + VerifyOrExit(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), err = CHIP_ERROR_INVALID_TLV_TAG); VerifyOrExit(data.tbsData3Signature.Capacity() >= decryptedDataTlvReader.GetLength(), err = CHIP_ERROR_INVALID_TLV_ELEMENT); data.tbsData3Signature.SetLength(decryptedDataTlvReader.GetLength()); SuccessOrExit(err = decryptedDataTlvReader.GetBytes(data.tbsData3Signature.Bytes(), data.tbsData3Signature.Length())); @@ -1864,12 +1991,12 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); SuccessOrExit(err = signedDataTlvReader.EnterContainer(containerType)); - SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBSData_SenderNOC))); + SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBSDataTags::kSenderNOC))); SuccessOrExit(err = signedDataTlvReader.Get(data.initiatorNOC)); if (!data.initiatorICAC.empty()) { - SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, TLV::ContextTag(kTag_TBSData_SenderICAC))); + SuccessOrExit(err = signedDataTlvReader.Next(TLV::kTLVType_ByteString, AsTlvContextTag(TBSDataTags::kSenderICAC))); SuccessOrExit(err = signedDataTlvReader.Get(data.initiatorICAC)); } } @@ -2060,13 +2187,13 @@ CHIP_ERROR CASESession::ConstructTBSData(const ByteSpan & senderNOC, const ByteS tlvWriter.Init(tbsData, tbsDataLen); ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderNOC), senderNOC)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderNOC), senderNOC)); if (!senderICAC.empty()) { - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderICAC), senderICAC)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderICAC), senderICAC)); } - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_SenderPubKey), senderPubKey)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kTag_TBSData_ReceiverPubKey), receiverPubKey)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kSenderPubKey), senderPubKey)); + ReturnErrorOnFailure(tlvWriter.Put(AsTlvContextTag(TBSDataTags::kReceiverPubKey), receiverPubKey)); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize()); tbsDataLen = static_cast(tlvWriter.GetLengthWritten()); @@ -2171,65 +2298,56 @@ CHIP_ERROR CASESession::OnFailureStatusReport(Protocols::SecureChannel::GeneralS return err; } -CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ByteSpan & initiatorRandom, - uint16_t & initiatorSessionId, ByteSpan & destinationId, ByteSpan & initiatorEphPubKey, - bool & resumptionRequested, ByteSpan & resumptionId, ByteSpan & initiatorResumeMIC) +CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma1 & outParsedSigma1) { - using namespace TLV; - - constexpr uint8_t kInitiatorRandomTag = 1; - constexpr uint8_t kInitiatorSessionIdTag = 2; - constexpr uint8_t kDestinationIdTag = 3; - constexpr uint8_t kInitiatorPubKeyTag = 4; - constexpr uint8_t kInitiatorMRPParamsTag = 5; - constexpr uint8_t kResumptionIDTag = 6; - constexpr uint8_t kResume1MICTag = 7; TLVType containerType = kTLVType_Structure; ReturnErrorOnFailure(tlvReader.Next(containerType, AnonymousTag())); ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); - ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorRandomTag))); - ReturnErrorOnFailure(tlvReader.GetByteView(initiatorRandom)); - VerifyOrReturnError(initiatorRandom.size() == kSigmaParamRandomNumberSize, CHIP_ERROR_INVALID_CASE_PARAMETER); + ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorRandom))); + ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorRandom)); + VerifyOrReturnError(outParsedSigma1.initiatorRandom.size() == kSigmaParamRandomNumberSize, CHIP_ERROR_INVALID_CASE_PARAMETER); - ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorSessionIdTag))); - ReturnErrorOnFailure(tlvReader.Get(initiatorSessionId)); + ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorSessionId))); + ReturnErrorOnFailure(tlvReader.Get(outParsedSigma1.initiatorSessionId)); - ReturnErrorOnFailure(tlvReader.Next(ContextTag(kDestinationIdTag))); - ReturnErrorOnFailure(tlvReader.GetByteView(destinationId)); - VerifyOrReturnError(destinationId.size() == kSHA256_Hash_Length, CHIP_ERROR_INVALID_CASE_PARAMETER); + ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kDestinationId))); + ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.destinationId)); + VerifyOrReturnError(outParsedSigma1.destinationId.size() == kSHA256_Hash_Length, CHIP_ERROR_INVALID_CASE_PARAMETER); - ReturnErrorOnFailure(tlvReader.Next(ContextTag(kInitiatorPubKeyTag))); - ReturnErrorOnFailure(tlvReader.GetByteView(initiatorEphPubKey)); - VerifyOrReturnError(initiatorEphPubKey.size() == kP256_PublicKey_Length, CHIP_ERROR_INVALID_CASE_PARAMETER); + ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma1Tags::kInitiatorEphPubKey))); + ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorEphPubKey)); + VerifyOrReturnError(outParsedSigma1.initiatorEphPubKey.size() == kP256_PublicKey_Length, CHIP_ERROR_INVALID_CASE_PARAMETER); // Optional members start here. CHIP_ERROR err = tlvReader.Next(); - if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kInitiatorMRPParamsTag)) + if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams)) { - ReturnErrorOnFailure(DecodeMRPParametersIfPresent(TLV::ContextTag(kInitiatorMRPParamsTag), tlvReader)); - mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteSessionParameters( - GetRemoteSessionParameters()); + ReturnErrorOnFailure(DecodeMRPParametersIfPresent(AsTlvContextTag(Sigma1Tags::kInitiatorSessionParams), tlvReader)); + outParsedSigma1.initiatorMrpParamsPresent = true; + err = tlvReader.Next(); } bool resumptionIDTagFound = false; bool resume1MICTagFound = false; - if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kResumptionIDTag)) + if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kResumptionID)) { resumptionIDTagFound = true; - ReturnErrorOnFailure(tlvReader.GetByteView(resumptionId)); - VerifyOrReturnError(resumptionId.size() == SessionResumptionStorage::kResumptionIdSize, CHIP_ERROR_INVALID_CASE_PARAMETER); + ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.resumptionId)); + VerifyOrReturnError(outParsedSigma1.resumptionId.size() == SessionResumptionStorage::kResumptionIdSize, + CHIP_ERROR_INVALID_CASE_PARAMETER); err = tlvReader.Next(); } - if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kResume1MICTag)) + if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma1Tags::kResume1MIC)) { resume1MICTagFound = true; - ReturnErrorOnFailure(tlvReader.GetByteView(initiatorResumeMIC)); - VerifyOrReturnError(initiatorResumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_CASE_PARAMETER); + ReturnErrorOnFailure(tlvReader.GetByteView(outParsedSigma1.initiatorResumeMIC)); + VerifyOrReturnError(outParsedSigma1.initiatorResumeMIC.size() == CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, + CHIP_ERROR_INVALID_CASE_PARAMETER); err = tlvReader.Next(); } @@ -2244,11 +2362,11 @@ CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, if (resumptionIDTagFound && resume1MICTagFound) { - resumptionRequested = true; + outParsedSigma1.sessionResumptionRequested = true; } else if (!resumptionIDTagFound && !resume1MICTagFound) { - resumptionRequested = false; + outParsedSigma1.sessionResumptionRequested = false; } else { diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index 045d1982dd723c..a9d43194d0f56d 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -117,28 +118,6 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, */ void SetGroupDataProvider(Credentials::GroupDataProvider * groupDataProvider) { mGroupDataProvider = groupDataProvider; } - /** - * Parse a sigma1 message. This function will return success only if the - * message passes schema checks. Specifically: - * * The tags come in order. - * * The required tags are present. - * * The values for the tags that are present satisfy schema requirements - * (e.g. constraints on octet string lengths) - * * Either resumptionID and initiatorResume1MIC are both present or both - * absent. - * - * On success, the initiatorRandom, initiatorSessionId, destinationId, - * initiatorEphPubKey outparams will be set to the corresponding values in - * the message. - * - * On success, either the resumptionRequested outparam will be set to true - * and the resumptionID and initiatorResumeMIC outparams will be set to - * valid values, or the resumptionRequested outparam will be set to false. - */ - CHIP_ERROR ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ByteSpan & initiatorRandom, uint16_t & initiatorSessionId, - ByteSpan & destinationId, ByteSpan & initiatorEphPubKey, bool & resumptionRequested, - ByteSpan & resumptionId, ByteSpan & initiatorResumeMIC); - /** * @brief * Derive a secure session from the established session. The API will return error if called before session is established. @@ -211,6 +190,118 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, // If this function returns true, the CASE session has been reset and is ready for a new session establishment. bool InvokeBackgroundWorkWatchdog(); +protected: + // Helper Enum for use in HandleSigma1_and_SendSigma2 + enum class Step : uint8_t + { + kSendSigma2, + kSendSigma2Resume, + }; + // Making NextStep a Variant allows HandleSigma() to return either a Step value (indicating + // the next Sigma step to send) or a CHIP_ERROR (indicating a failure that will trigger + // a Status Report). + using NextStep = Variant; + // This struct only serves as a base struct for EncodeSigma1Inputs and ParsedSigma1 + struct Sigma1Param + { + ByteSpan initiatorRandom; + uint16_t initiatorSessionId; + ByteSpan destinationId; + bool sessionResumptionRequested = false; + ByteSpan resumptionId; + ByteSpan initiatorResumeMIC; + }; + + struct EncodeSigma1Inputs : Sigma1Param + { + const Crypto::P256PublicKey * initiatorEphPubKey = nullptr; + const ReliableMessageProtocolConfig * initiatorMrpConfig = nullptr; + uint8_t initiatorResume1MICBuffer[Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES]; + }; + + struct ParsedSigma1 : Sigma1Param + { + ByteSpan initiatorEphPubKey; + bool initiatorMrpParamsPresent = false; + }; + + struct EncodeSigma2Inputs + { + uint8_t responderRandom[kSigmaParamRandomNumberSize]; + uint16_t responderSessionId; + const Crypto::P256PublicKey * responderEphPubKey = nullptr; + // ScopedMemoryBufferWithSize is not used for msgR2Encrypted since encrypted2Length might differ from the allocated buffer + // size + Platform::ScopedMemoryBuffer msgR2Encrypted; + size_t encrypted2Length = 0; + const ReliableMessageProtocolConfig * responderMrpConfig; + }; + + struct EncodeSigma2ResumeInputs + { + ByteSpan resumptionId; + uint8_t sigma2ResumeMICBuffer[Crypto::CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES]; + MutableByteSpan resumeMIC{ sigma2ResumeMICBuffer }; + uint16_t responderSessionId; + const ReliableMessageProtocolConfig * responderMrpConfig; + }; + + /** + * @brief Encodes a Sigma1 message into TLV format and allocates a buffer for it, which is owned by the PacketBufferHandle + * outparam. + * + * @param outMsg PacketBufferHandle passed by reference. A new buffer will be allocated and assigned to it within the + * method. + * + * @param inParam a struct containing all the values that will be encoded into TLV format + * + **/ + static CHIP_ERROR EncodeSigma1(System::PacketBufferHandle & outMsg, EncodeSigma1Inputs & inParam); + + /** + * Parse a Sigma1 message. This function will return success only if the + * message passes schema checks. Specifically: + * * The tags come in order. + * * The required tags are present. + * * The values for the tags that are present satisfy schema requirements + * (e.g. constraints on octet string lengths) + * * Either resumptionID and initiatorResume1MICBuffer are both present or both are + * absent. + * + * On success, the members of outParam will be set to the values corresponding to the message. + * These values will be valid as long as the buffer that the passed-in tlvReader is reading from is valid. + * + * On success, either the sessionResumptionRequested field will be set to true + * and the resumptionID and initiatorResumeMIC fields will be set to + * valid values, or the sessionResumptionRequested field will be set to false. + */ + CHIP_ERROR ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma1 & parsedMessage); + + /** + * @brief Encodes a Sigma2 message into TLV format and allocates a buffer for it, which is owned by the PacketBufferHandle + * outparam. + * + * @param outMsg PacketBufferHandle passed by reference. A new buffer will be allocated and assigned to it within the + * method. + * + * @param inParam a struct containing all the values that will be encoded into TLV format + * + **/ + + static CHIP_ERROR EncodeSigma2(System::PacketBufferHandle & outMsg, EncodeSigma2Inputs & inParam); + + /** + * @brief Encodes a Sigma2_Resume message into TLV format and allocates a buffer for it, which is owned by the + * PacketBufferHandle outparam. + * + * @param outMsg PacketBufferHandle passed by reference. A new buffer will be allocated and assigned to it within the + * method. + * + * @param inParam a struct containing all the values that will be encoded into TLV format + * + **/ + static CHIP_ERROR EncodeSigma2Resume(System::PacketBufferHandle & outMsg, EncodeSigma2ResumeInputs & inParam); + private: friend class TestCASESession; @@ -236,10 +327,15 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, CHIP_ERROR SendSigma1(); CHIP_ERROR HandleSigma1_and_SendSigma2(System::PacketBufferHandle && msg); - CHIP_ERROR HandleSigma1(System::PacketBufferHandle && msg); + NextStep HandleSigma1(System::PacketBufferHandle && msg); CHIP_ERROR TryResumeSession(SessionResumptionStorage::ConstResumptionIdView resumptionId, ByteSpan resume1MIC, ByteSpan initiatorRandom); - CHIP_ERROR SendSigma2(); + + CHIP_ERROR PrepareSigma2(EncodeSigma2Inputs & output); + CHIP_ERROR PrepareSigma2Resume(EncodeSigma2ResumeInputs & output); + CHIP_ERROR SendSigma2(System::PacketBufferHandle && msg_R2); + CHIP_ERROR SendSigma2Resume(System::PacketBufferHandle && msg_R2_resume); + CHIP_ERROR HandleSigma2_and_SendSigma3(System::PacketBufferHandle && msg); CHIP_ERROR HandleSigma2(System::PacketBufferHandle && msg); CHIP_ERROR HandleSigma2Resume(System::PacketBufferHandle && msg); diff --git a/src/protocols/secure_channel/tests/TestCASESession.cpp b/src/protocols/secure_channel/tests/TestCASESession.cpp index 67b4cdd7d69faf..81a2142c716021 100644 --- a/src/protocols/secure_channel/tests/TestCASESession.cpp +++ b/src/protocols/secure_channel/tests/TestCASESession.cpp @@ -59,6 +59,23 @@ using namespace chip::Crypto; namespace chip { class TestCASESecurePairingDelegate; +// Exposing CASESession's Protected members in order to be able to call the protected methods, and instantiate protected structures. +// Also to be able to instantiate New CASESessions repeatedly inside a single TestCase (which is not possible if we inherit +// CASESession in the Test Fixture) +class CASESessionAccess : public CASESession +{ +public: + using CASESession::EncodeSigma1Inputs; + using CASESession::EncodeSigma2Inputs; + using CASESession::EncodeSigma2ResumeInputs; + using CASESession::ParsedSigma1; + + using CASESession::EncodeSigma1; + using CASESession::EncodeSigma2; + using CASESession::EncodeSigma2Resume; + using CASESession::ParseSigma1; +}; + class TestCASESession : public Test::LoopbackMessagingContext { public: @@ -614,24 +631,24 @@ struct Sigma1Params { // Purposefully not using constants like kSigmaParamRandomNumberSize that // the code uses, so we have a cross-check. - static constexpr size_t initiatorRandomLen = 32; - static constexpr uint16_t initiatorSessionId = 0; - static constexpr size_t destinationIdLen = 32; - static constexpr size_t initiatorEphPubKeyLen = 65; - static constexpr size_t resumptionIdLen = 0; // Nonzero means include it. - static constexpr size_t initiatorResumeMICLen = 0; // Nonzero means include it. - - static constexpr uint8_t initiatorRandomTag = 1; - static constexpr uint8_t initiatorSessionIdTag = 2; - static constexpr uint8_t destinationIdTag = 3; - static constexpr uint8_t initiatorEphPubKeyTag = 4; - static constexpr uint8_t resumptionIdTag = 6; - static constexpr uint8_t initiatorResumeMICTag = 7; + static constexpr size_t kInitiatorRandomLen = 32; + static constexpr uint16_t kInitiatorSessionId = 0; + static constexpr size_t kDestinationIdLen = 32; + static constexpr size_t kInitiatorEphPubKeyLen = 65; + static constexpr size_t kResumptionIdLen = 0; // Nonzero means include it. + static constexpr size_t kInitiatorResumeMICLen = 0; // Nonzero means include it. + + static constexpr uint8_t kInitiatorRandomTag = 1; + static constexpr uint8_t kInitiatorSessionIdTag = 2; + static constexpr uint8_t kDestinationIdTag = 3; + static constexpr uint8_t kInitiatorEphPubKeyTag = 4; + static constexpr uint8_t kResumptionIdTag = 6; + static constexpr uint8_t kInitiatorResumeMICTag = 7; static constexpr TLV::Tag NumToTag(uint8_t num) { return TLV::ContextTag(num); } - static constexpr bool includeStructEnd = true; + static constexpr bool kIncludeStructEnd = true; - static constexpr bool expectSuccess = true; + static constexpr bool kExpectSuccess = true; }; TEST_F(TestCASESession, DestinationIdTest) @@ -649,10 +666,10 @@ TEST_F(TestCASESession, DestinationIdTest) 0x9b, 0xc6, 0x1c, 0xd9, 0xc6, 0x2a, 0x2d, 0xf6, 0xd6, 0x4d, 0xfc, 0xaa, 0x9d, 0xc4, 0x72, 0xd4 }; - const uint8_t kInitiatorRandomFromSpec[Sigma1Params::initiatorRandomLen] = { 0x7e, 0x17, 0x12, 0x31, 0x56, 0x8d, 0xfa, 0x17, - 0x20, 0x6b, 0x3a, 0xcc, 0xf8, 0xfa, 0xec, 0x2f, - 0x4d, 0x21, 0xb5, 0x80, 0x11, 0x31, 0x96, 0xf4, - 0x7c, 0x7c, 0x4d, 0xeb, 0x81, 0x0a, 0x73, 0xdc }; + const uint8_t kInitiatorRandomFromSpec[Sigma1Params::kInitiatorRandomLen] = { 0x7e, 0x17, 0x12, 0x31, 0x56, 0x8d, 0xfa, 0x17, + 0x20, 0x6b, 0x3a, 0xcc, 0xf8, 0xfa, 0xec, 0x2f, + 0x4d, 0x21, 0xb5, 0x80, 0x11, 0x31, 0x96, 0xf4, + 0x7c, 0x7c, 0x4d, 0xeb, 0x81, 0x0a, 0x73, 0xdc }; const uint8_t kExpectedDestinationIdFromSpec[Crypto::kSHA256_Hash_Length] = { 0xdc, 0x35, 0xdd, 0x5f, 0xc9, 0x13, 0x4c, 0xc5, 0x54, 0x45, 0x38, 0xc9, 0xc3, 0xfc, 0x42, 0x97, @@ -686,7 +703,7 @@ TEST_F(TestCASESession, DestinationIdTest) } template -static CHIP_ERROR EncodeSigma1(MutableByteSpan & buf) +static CHIP_ERROR EncodeSigma1Helper(MutableByteSpan & buf) { using namespace TLV; @@ -695,39 +712,37 @@ static CHIP_ERROR EncodeSigma1(MutableByteSpan & buf) TLVType containerType; ReturnErrorOnFailure(writer.StartContainer(AnonymousTag(), kTLVType_Structure, containerType)); - uint8_t initiatorRandom[Params::initiatorRandomLen] = { 1 }; - ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::initiatorRandomTag), ByteSpan(initiatorRandom))); + uint8_t initiatorRandom[Params::kInitiatorRandomLen] = { 1 }; + ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::kInitiatorRandomTag), ByteSpan(initiatorRandom))); - ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::initiatorSessionIdTag), Params::initiatorSessionId)); + ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::kInitiatorSessionIdTag), Params::kInitiatorSessionId)); - uint8_t destinationId[Params::destinationIdLen] = { 2 }; - ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::destinationIdTag), ByteSpan(destinationId))); + uint8_t destinationId[Params::kDestinationIdLen] = { 2 }; + ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::kDestinationIdTag), ByteSpan(destinationId))); - uint8_t initiatorEphPubKey[Params::initiatorEphPubKeyLen] = { 3 }; - ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::initiatorEphPubKeyTag), ByteSpan(initiatorEphPubKey))); + uint8_t initiatorEphPubKey[Params::kInitiatorEphPubKeyLen] = { 3 }; + ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::kInitiatorEphPubKeyTag), ByteSpan(initiatorEphPubKey))); - // I wish we had "if constexpr" support here, so the compiler would know - // resumptionIdLen is nonzero inside the block.... - if (Params::resumptionIdLen != 0) + if constexpr (Params::kResumptionIdLen != 0) { - uint8_t resumptionId[Params::resumptionIdLen]; + uint8_t resumptionId[Params::kResumptionIdLen]; // to fix _FORTIFY_SOURCE issue, _FORTIFY_SOURCE=2 by default on Android - (&memset)(resumptionId, 4, Params::resumptionIdLen); + (&memset)(resumptionId, 4, Params::kResumptionIdLen); ReturnErrorOnFailure( - writer.Put(Params::NumToTag(Params::resumptionIdTag), ByteSpan(resumptionId, Params::resumptionIdLen))); + writer.Put(Params::NumToTag(Params::kResumptionIdTag), ByteSpan(resumptionId, Params::kResumptionIdLen))); } - if (Params::initiatorResumeMICLen != 0) + if constexpr (Params::kInitiatorResumeMICLen != 0) { - uint8_t initiatorResumeMIC[Params::initiatorResumeMICLen]; + uint8_t initiatorResumeMIC[Params::kInitiatorResumeMICLen]; // to fix _FORTIFY_SOURCE issue, _FORTIFY_SOURCE=2 by default on Android - (&memset)(initiatorResumeMIC, 5, Params::initiatorResumeMICLen); - ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::initiatorResumeMICTag), - ByteSpan(initiatorResumeMIC, Params::initiatorResumeMICLen))); + (&memset)(initiatorResumeMIC, 5, Params::kInitiatorResumeMICLen); + ReturnErrorOnFailure(writer.Put(Params::NumToTag(Params::kInitiatorResumeMICTag), + ByteSpan(initiatorResumeMIC, Params::kInitiatorResumeMICLen))); } - if (Params::includeStructEnd) + if constexpr (Params::kIncludeStructEnd) { ReturnErrorOnFailure(writer.EndContainer(containerType)); } @@ -741,37 +756,30 @@ static CHIP_ERROR EncodeSigma1(MutableByteSpan & buf) do \ { \ MutableByteSpan buf(mem.Get(), bufferSize); \ - EXPECT_EQ(EncodeSigma1(buf), CHIP_NO_ERROR); \ + EXPECT_EQ(EncodeSigma1Helper(buf), CHIP_NO_ERROR); \ \ TLV::ContiguousBufferTLVReader reader; \ reader.Init(buf); \ + CASESessionAccess session; \ + CASESessionAccess::ParsedSigma1 parsedSigma1; \ \ - ByteSpan initiatorRandom; \ - uint16_t initiatorSessionId; \ - ByteSpan destinationId; \ - ByteSpan initiatorEphPubKey; \ - bool resumptionRequested; \ - ByteSpan resumptionId; \ - ByteSpan initiatorResumeMIC; \ - CASESession session; \ - EXPECT_EQ(session.ParseSigma1(reader, initiatorRandom, initiatorSessionId, destinationId, initiatorEphPubKey, \ - resumptionRequested, resumptionId, initiatorResumeMIC) == CHIP_NO_ERROR, \ - params::expectSuccess); \ - if (params::expectSuccess) \ + EXPECT_EQ(session.ParseSigma1(reader, parsedSigma1) == CHIP_NO_ERROR, params::kExpectSuccess); \ + if (params::kExpectSuccess) \ { \ - EXPECT_EQ(resumptionRequested, params::resumptionIdLen != 0 && params::initiatorResumeMICLen != 0); \ + EXPECT_EQ(parsedSigma1.sessionResumptionRequested, \ + params::kResumptionIdLen != 0 && params::kInitiatorResumeMICLen != 0); \ /* Add other verification tests here as desired */ \ } \ } while (0) struct BadSigma1ParamsBase : public Sigma1Params { - static constexpr bool expectSuccess = false; + static constexpr bool kExpectSuccess = false; }; struct Sigma1NoStructEnd : public BadSigma1ParamsBase { - static constexpr bool includeStructEnd = false; + static constexpr bool kIncludeStructEnd = false; }; struct Sigma1WrongTags : public BadSigma1ParamsBase @@ -781,72 +789,72 @@ struct Sigma1WrongTags : public BadSigma1ParamsBase struct Sigma1TooLongRandom : public BadSigma1ParamsBase { - static constexpr size_t initiatorRandomLen = 33; + static constexpr size_t kInitiatorRandomLen = 33; }; struct Sigma1TooShortRandom : public BadSigma1ParamsBase { - static constexpr size_t initiatorRandomLen = 31; + static constexpr size_t kInitiatorRandomLen = 31; }; struct Sigma1TooLongDest : public BadSigma1ParamsBase { - static constexpr size_t destinationIdLen = 33; + static constexpr size_t kDestinationIdLen = 33; }; struct Sigma1TooShortDest : public BadSigma1ParamsBase { - static constexpr size_t destinationIdLen = 31; + static constexpr size_t kDestinationIdLen = 31; }; struct Sigma1TooLongPubkey : public BadSigma1ParamsBase { - static constexpr size_t initiatorEphPubKeyLen = 66; + static constexpr size_t kInitiatorEphPubKeyLen = 66; }; struct Sigma1TooShortPubkey : public BadSigma1ParamsBase { - static constexpr size_t initiatorEphPubKeyLen = 64; + static constexpr size_t kInitiatorEphPubKeyLen = 64; }; struct Sigma1WithResumption : public Sigma1Params { - static constexpr size_t resumptionIdLen = 16; - static constexpr size_t initiatorResumeMICLen = 16; + static constexpr size_t kResumptionIdLen = 16; + static constexpr size_t kInitiatorResumeMICLen = 16; }; struct Sigma1TooLongResumptionId : public Sigma1WithResumption { - static constexpr size_t resumptionIdLen = 17; - static constexpr bool expectSuccess = false; + static constexpr size_t kResumptionIdLen = 17; + static constexpr bool kExpectSuccess = false; }; struct Sigma1TooShortResumptionId : public BadSigma1ParamsBase { - static constexpr size_t resumptionIdLen = 15; - static constexpr bool expectSuccess = false; + static constexpr size_t kResumptionIdLen = 15; + static constexpr bool kExpectSuccess = false; }; struct Sigma1TooLongResumeMIC : public Sigma1WithResumption { - static constexpr size_t resumptionIdLen = 17; - static constexpr bool expectSuccess = false; + static constexpr size_t kResumptionIdLen = 17; + static constexpr bool kExpectSuccess = false; }; struct Sigma1TooShortResumeMIC : public Sigma1WithResumption { - static constexpr size_t initiatorResumeMICLen = 15; - static constexpr bool expectSuccess = false; + static constexpr size_t kInitiatorResumeMICLen = 15; + static constexpr bool kExpectSuccess = false; }; struct Sigma1SessionIdMax : public Sigma1Params { - static constexpr uint32_t initiatorSessionId = UINT16_MAX; + static constexpr uint32_t kInitiatorSessionId = UINT16_MAX; }; struct Sigma1SessionIdTooBig : public BadSigma1ParamsBase { - static constexpr uint32_t initiatorSessionId = UINT16_MAX + 1; + static constexpr uint32_t kInitiatorSessionId = UINT16_MAX + 1; }; TEST_F(TestCASESession, Sigma1ParsingTest) @@ -874,6 +882,231 @@ TEST_F(TestCASESession, Sigma1ParsingTest) TestSigma1Parsing(mem, bufferSize, Sigma1SessionIdTooBig); } +TEST_F(TestCASESession, EncodeSigma1Test) +{ + CASESessionAccess::EncodeSigma1Inputs encodeParams; + + uint8_t random[32]; + EXPECT_EQ(chip::Crypto::DRBG_get_bytes(&random[0], sizeof(random)), CHIP_NO_ERROR); + encodeParams.initiatorRandom = ByteSpan(random); + encodeParams.initiatorSessionId = 7315; + uint8_t destinationId[32] = { 0xDE, 0xAD }; + encodeParams.destinationId = ByteSpan(destinationId); + + ReliableMessageProtocolConfig mrpConfig = GetDefaultMRPConfig(); + encodeParams.initiatorMrpConfig = &mrpConfig; + + { + System::PacketBufferHandle msg; + // EncodeSigma1 should fail when there is no public key + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, CASESessionAccess::EncodeSigma1(msg, encodeParams)); + } + + Crypto::P256Keypair * ephemeralKey = gDeviceOperationalKeystore.AllocateEphemeralKeypairForCASE(); + ASSERT_NE(ephemeralKey, nullptr); + EXPECT_EQ(CHIP_NO_ERROR, ephemeralKey->Initialize(ECPKeyTarget::ECDH)); + encodeParams.initiatorEphPubKey = &ephemeralKey->Pubkey(); + + { + System::PacketBufferHandle msg; + // EncodeSigma1 will Succeed when Public Key is provided + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma1(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg; + // EncodeSigma1 should fail when MRP config is missing + encodeParams.initiatorMrpConfig = nullptr; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, CASESessionAccess::EncodeSigma1(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg; + // Succeed when MRP Config is provided + encodeParams.initiatorMrpConfig = &mrpConfig; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma1(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg1; + + // Round Trip Test: Encode Sigma1, Parse it then verify parsed values + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma1(msg1, encodeParams)); + + System::PacketBufferTLVReader tlvReader; + tlvReader.Init(std::move(msg1)); + + CASESessionAccess session; + CASESessionAccess::ParsedSigma1 parsedMessage; + + EXPECT_EQ(CHIP_NO_ERROR, session.ParseSigma1(tlvReader, parsedMessage)); + + // compare parsed values with original values + EXPECT_TRUE(parsedMessage.initiatorRandom.data_equal(encodeParams.initiatorRandom)); + EXPECT_EQ(parsedMessage.initiatorSessionId, encodeParams.initiatorSessionId); + EXPECT_TRUE(parsedMessage.destinationId.data_equal(encodeParams.destinationId)); + EXPECT_TRUE(parsedMessage.initiatorEphPubKey.data_equal( + ByteSpan(encodeParams.initiatorEphPubKey->ConstBytes(), encodeParams.initiatorEphPubKey->Length()))); + } + + { + // Round Trip Test: Sigma1 with Session Resumption + // Encode Sigma1 with Resumption, parse it and and verify with original values + chip::SessionResumptionStorage::ResumptionIdStorage resumptionId; + + EXPECT_EQ(chip::Crypto::DRBG_get_bytes(resumptionId.data(), resumptionId.size()), CHIP_NO_ERROR); + EXPECT_EQ(chip::Crypto::DRBG_get_bytes(&encodeParams.initiatorResume1MICBuffer[0], + sizeof(encodeParams.initiatorResume1MICBuffer)), + CHIP_NO_ERROR); + + encodeParams.resumptionId = ByteSpan(resumptionId.data(), resumptionId.size()); + encodeParams.initiatorResumeMIC = ByteSpan(encodeParams.initiatorResume1MICBuffer); + encodeParams.sessionResumptionRequested = true; + + System::PacketBufferHandle msg2; + + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma1(msg2, encodeParams)); + + System::PacketBufferTLVReader tlvReader; + tlvReader.Init(std::move(msg2)); + + CASESessionAccess session; + CASESessionAccess::ParsedSigma1 parsedMessage; + + EXPECT_EQ(CHIP_NO_ERROR, session.ParseSigma1(tlvReader, parsedMessage)); + + // RoundTrip + EXPECT_TRUE(parsedMessage.initiatorRandom.data_equal(encodeParams.initiatorRandom)); + EXPECT_EQ(parsedMessage.initiatorSessionId, encodeParams.initiatorSessionId); + EXPECT_TRUE(parsedMessage.destinationId.data_equal(encodeParams.destinationId)); + EXPECT_TRUE(parsedMessage.initiatorEphPubKey.data_equal( + ByteSpan(encodeParams.initiatorEphPubKey->ConstBytes(), encodeParams.initiatorEphPubKey->Length()))); + + EXPECT_TRUE(parsedMessage.resumptionId.data_equal(encodeParams.resumptionId)); + EXPECT_TRUE(parsedMessage.initiatorResumeMIC.data_equal(encodeParams.initiatorResumeMIC)); + EXPECT_TRUE(parsedMessage.initiatorMrpParamsPresent); + } + // Release EphemeralKeyPair + gDeviceOperationalKeystore.ReleaseEphemeralKeypair(ephemeralKey); +} + +TEST_F(TestCASESession, EncodeSigma2Test) +{ + CASESessionAccess::EncodeSigma2Inputs encodeParams; + constexpr uint8_t kEncrypted2datalen = 100U; + + EXPECT_EQ(chip::Crypto::DRBG_get_bytes(&encodeParams.responderRandom[0], sizeof(encodeParams.responderRandom)), CHIP_NO_ERROR); + encodeParams.responderSessionId = 7315; + + // Generate Ephemeral Public Key + Crypto::P256Keypair * ephemeralKey = gDeviceOperationalKeystore.AllocateEphemeralKeypairForCASE(); + ASSERT_NE(ephemeralKey, nullptr); + EXPECT_EQ(CHIP_NO_ERROR, ephemeralKey->Initialize(ECPKeyTarget::ECDH)); + encodeParams.responderEphPubKey = &ephemeralKey->Pubkey(); + + // TBEData2Encrypted + encodeParams.encrypted2Length = kEncrypted2datalen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; + encodeParams.msgR2Encrypted.Alloc(encodeParams.encrypted2Length); + + // responder Session Parameters + ReliableMessageProtocolConfig mrpConfig = GetDefaultMRPConfig(); + encodeParams.responderMrpConfig = &mrpConfig; + + { + System::PacketBufferHandle msg; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + // EncodeSigma2 frees msgR2Encrypted after encoding it + encodeParams.msgR2Encrypted.Alloc(encodeParams.encrypted2Length); + } + + { + System::PacketBufferHandle msg; + + // EncodeSigma2 should fail when there is no public key + encodeParams.responderEphPubKey = nullptr; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + } + + encodeParams.responderEphPubKey = &ephemeralKey->Pubkey(); + + { + System::PacketBufferHandle msg; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + // EncodeSigma2 frees msgR2Encrypted after encoding it + encodeParams.msgR2Encrypted.Alloc(encodeParams.encrypted2Length); + } + + { + System::PacketBufferHandle msg; + // EncodeSigma2 should fail when TBEData2Encrypted is not allocated + encodeParams.msgR2Encrypted.Free(); + EXPECT_EQ(CHIP_ERROR_INCORRECT_STATE, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + } + + encodeParams.msgR2Encrypted.Alloc(encodeParams.encrypted2Length); + { + System::PacketBufferHandle msg; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + // EncodeSigma2 frees msgR2Encrypted after encoding it + encodeParams.msgR2Encrypted.Alloc(encodeParams.encrypted2Length); + } + + { + System::PacketBufferHandle msg; + // EncodeSigma2 should fail when the encrypted2Length is not set + encodeParams.encrypted2Length = 0; + EXPECT_EQ(CHIP_ERROR_INCORRECT_STATE, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + } + // Set encrypted2Length again + encodeParams.encrypted2Length = kEncrypted2datalen + CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; + + { + System::PacketBufferHandle msg; + // EncodeSigma2 should fail when MRP config is missing + encodeParams.responderMrpConfig = nullptr; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg; + // Succeed when MRP Config is provided + encodeParams.responderMrpConfig = &mrpConfig; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2(msg, encodeParams)); + } + // Release EphemeralKeyPair + gDeviceOperationalKeystore.ReleaseEphemeralKeypair(ephemeralKey); +} + +TEST_F(TestCASESession, EncodeSigma2ResumeTest) +{ + CASESessionAccess::EncodeSigma2ResumeInputs encodeParams; + + encodeParams.responderSessionId = 7315; + + // responder Session Parameters + ReliableMessageProtocolConfig mrpConfig = GetDefaultMRPConfig(); + encodeParams.responderMrpConfig = &mrpConfig; + + { + System::PacketBufferHandle msg; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2Resume(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg; + // EncodeSigma2Resume should fail when MRP config is missing + encodeParams.responderMrpConfig = nullptr; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, CASESessionAccess::EncodeSigma2Resume(msg, encodeParams)); + } + + { + System::PacketBufferHandle msg; + // Succeed when MRP Config is provided + encodeParams.responderMrpConfig = &mrpConfig; + EXPECT_EQ(CHIP_NO_ERROR, CASESessionAccess::EncodeSigma2Resume(msg, encodeParams)); + } +} + struct SessionResumptionTestStorage : SessionResumptionStorage { SessionResumptionTestStorage(CHIP_ERROR findMethodReturnCode, ScopedNodeId peerNodeId, ResumptionIdStorage * resumptionId, @@ -1126,7 +1359,7 @@ TEST_F(TestCASESession, Sigma1BadDestinationIdTest) MutableByteSpan buf(data->Start(), data->AvailableDataLength()); // This uses a bogus destination id that is not going to match anything in practice. - EXPECT_EQ(EncodeSigma1(buf), CHIP_NO_ERROR); + EXPECT_EQ(EncodeSigma1Helper(buf), CHIP_NO_ERROR); data->SetDataLength(static_cast(buf.size())); Optional session = sessionManager.CreateUnauthenticatedSession(GetAliceAddress(), GetDefaultMRPConfig());