From e62885508d5d91849c9953312fdb8f04972cddbe Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Wed, 15 Nov 2023 11:21:03 -0500 Subject: [PATCH] Update session parameters to be inline with matter 1.3 spec (#30405) --- src/app/BUILD.gn | 10 +- src/app/SpecificationVersion.h | 31 +++++ src/lib/core/CHIPConfig.h | 13 ++ src/protocols/secure_channel/BUILD.gn | 2 + src/protocols/secure_channel/CASESession.cpp | 54 +++----- src/protocols/secure_channel/PASESession.cpp | 37 ++--- .../secure_channel/PairingSession.cpp | 130 +++++++++++++----- src/protocols/secure_channel/PairingSession.h | 17 +-- .../secure_channel/SessionParameters.h | 109 +++++++++++++++ .../tests/TestPairingSession.cpp | 5 +- 10 files changed, 311 insertions(+), 97 deletions(-) create mode 100644 src/app/SpecificationVersion.h create mode 100644 src/protocols/secure_channel/SessionParameters.h diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index a7a9baddf55cd8..17ce830117265c 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -64,6 +64,14 @@ buildconfig_header("app_buildconfig") { ] } +source_set("revision_info") { + sources = [ + "DataModelRevision.h", + "InteractionModelRevision.h", + "SpecificationVersion.h", + ] +} + source_set("app_config") { sources = [ "AppConfig.h" ] @@ -101,7 +109,6 @@ static_library("app") { "FailSafeContext.h", "GlobalAttributes.h", "InteractionModelEngine.cpp", - "InteractionModelRevision.h", "InteractionModelTimeout.h", "MessageDef/ArrayBuilder.cpp", "MessageDef/ArrayParser.cpp", @@ -237,6 +244,7 @@ static_library("app") { public_deps = [ ":app_config", + ":revision_info", "${chip_root}/src/access", "${chip_root}/src/app/icd:notifier", "${chip_root}/src/app/icd:observer", diff --git a/src/app/SpecificationVersion.h b/src/app/SpecificationVersion.h new file mode 100644 index 00000000000000..b0570dad14c4ce --- /dev/null +++ b/src/app/SpecificationVersion.h @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/** + * CHIP_DEVICE_SPECIFICATION_VERSION + * + * A number identifying the specification version against which the + * Node is certified. + * + * See section 11.1.5.22. "SpecificationVersion Attribute" in "Service and + * Device Management" chapter of the core Matter specification. + */ +#ifndef CHIP_DEVICE_SPECIFICATION_VERSION +#define CHIP_DEVICE_SPECIFICATION_VERSION 0x01030000 +#endif diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 1a25b18e339ec5..fb04f9bbefd943 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1600,6 +1600,19 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED 0 #endif +/** + * @def CHIP_CONFIG_MAX_PATHS_PER_INVOKE + * + * @brief The maximum number of elements in the InvokeRequests list that the Node is able to process. + */ +#ifndef CHIP_CONFIG_MAX_PATHS_PER_INVOKE +#define CHIP_CONFIG_MAX_PATHS_PER_INVOKE 1 +#endif + +#if CHIP_CONFIG_MAX_PATHS_PER_INVOKE < 1 || CHIP_CONFIG_MAX_PATHS_PER_INVOKE > 65535 +#error "CHIP_CONFIG_MAX_PATHS_PER_INVOKE is not allowed to be a number less than 1 or greater than 65535" +#endif + /** * @def CHIP_CONFIG_ICD_OBSERVERS_POOL_SIZE * diff --git a/src/protocols/secure_channel/BUILD.gn b/src/protocols/secure_channel/BUILD.gn index 5a24a984719a5e..2061b04e82b6d5 100644 --- a/src/protocols/secure_channel/BUILD.gn +++ b/src/protocols/secure_channel/BUILD.gn @@ -61,4 +61,6 @@ static_library("secure_channel") { "${chip_root}/src/tracing:macros", "${chip_root}/src/transport", ] + + deps = [ "${chip_root}/src/app:revision_info" ] } diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 2afc40feacaf02..57375646a202b2 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -640,13 +641,11 @@ CHIP_ERROR CASESession::RecoverInitiatorIpk() CHIP_ERROR CASESession::SendSigma1() { MATTER_TRACE_SCOPE("SendSigma1", "CASESession"); - const size_t mrpParamsSize = - mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t), sizeof(uint16_t)) : 0; - size_t data_len = TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, // initiatorRandom - sizeof(uint16_t), // initiatorSessionId, - kSHA256_Hash_Length, // destinationId - kP256_PublicKey_Length, // InitiatorEphPubKey, - mrpParamsSize, // initiatorMRPParams + 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; @@ -699,11 +698,7 @@ CHIP_ERROR CASESession::SendSigma1() ReturnErrorOnFailure( tlvWriter.PutBytes(TLV::ContextTag(4), mEphemeralKey->Pubkey(), static_cast(mEphemeralKey->Pubkey().Length()))); - if (mLocalMRPConfig.HasValue()) - { - ChipLogDetail(SecureChannel, "Including MRP parameters"); - ReturnErrorOnFailure(EncodeMRPParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter)); - } + ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig, tlvWriter)); // Try to find persistent session, and resume it. bool resuming = false; @@ -916,10 +911,9 @@ CHIP_ERROR CASESession::HandleSigma1(System::PacketBufferHandle && msg) CHIP_ERROR CASESession::SendSigma2Resume() { MATTER_TRACE_SCOPE("SendSigma2Resume", "CASESession"); - const size_t mrpParamsSize = - mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t), sizeof(uint16_t)) : 0; - size_t max_sigma2_resume_data_len = TLV::EstimateStructOverhead( - SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, sizeof(uint16_t), mrpParamsSize); + size_t max_sigma2_resume_data_len = + TLV::EstimateStructOverhead(SessionResumptionStorage::kResumptionIdSize, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, + sizeof(uint16_t), SessionParameters::kEstimatedTLVSize); System::PacketBufferTLVWriter tlvWriter; System::PacketBufferHandle msg_R2_resume; @@ -948,11 +942,7 @@ CHIP_ERROR CASESession::SendSigma2Resume() ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), GetLocalSessionId().Value())); - if (mLocalMRPConfig.HasValue()) - { - ChipLogDetail(SecureChannel, "Including MRP parameters"); - ReturnErrorOnFailure(EncodeMRPParameters(TLV::ContextTag(4), mLocalMRPConfig.Value(), tlvWriter)); - } + ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(4), mLocalMRPConfig, tlvWriter)); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize(&msg_R2_resume)); @@ -1067,10 +1057,10 @@ CHIP_ERROR CASESession::SendSigma2() msg_R2_Encrypted.Get() + msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES)); // Construct Sigma2 Msg - const size_t mrpParamsSize = - mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t), sizeof(uint16_t)) : 0; - size_t data_len = TLV::EstimateStructOverhead(kSigmaParamRandomNumberSize, sizeof(uint16_t), kP256_PublicKey_Length, - msg_r2_signed_enc_len, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, mrpParamsSize); + 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); System::PacketBufferHandle msg_R2 = System::PacketBufferHandle::New(data_len); VerifyOrReturnError(!msg_R2.IsNull(), CHIP_ERROR_NO_MEMORY); @@ -1086,11 +1076,9 @@ CHIP_ERROR CASESession::SendSigma2() 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))); - if (mLocalMRPConfig.HasValue()) - { - ChipLogDetail(SecureChannel, "Including MRP parameters"); - ReturnErrorOnFailure(EncodeMRPParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriterMsg2)); - } + + ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig, tlvWriterMsg2)); + ReturnErrorOnFailure(tlvWriterMsg2.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriterMsg2.Finalize(&msg_R2)); @@ -1147,7 +1135,7 @@ CHIP_ERROR CASESession::HandleSigma2Resume(System::PacketBufferHandle && msg) if (tlvReader.Next() != CHIP_END_OF_TLV) { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(4), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); } ChipLogDetail(SecureChannel, "Peer assigned session session ID %d", responderSessionId); @@ -1340,7 +1328,7 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) if (tlvReader.Next() != CHIP_END_OF_TLV) { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(kTag_Sigma2_ResponderMRPParams), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); } exit: @@ -2029,7 +2017,7 @@ CHIP_ERROR CASESession::ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, if (err == CHIP_NO_ERROR && tlvReader.GetTag() == ContextTag(kInitiatorMRPParamsTag)) { ReturnErrorOnFailure(DecodeMRPParametersIfPresent(TLV::ContextTag(kInitiatorMRPParamsTag), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); err = tlvReader.Next(); } diff --git a/src/protocols/secure_channel/PASESession.cpp b/src/protocols/secure_channel/PASESession.cpp index 966bc1dbe8dae0..8e2f27f176cfca 100644 --- a/src/protocols/secure_channel/PASESession.cpp +++ b/src/protocols/secure_channel/PASESession.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -270,13 +271,12 @@ CHIP_ERROR PASESession::SendPBKDFParamRequest() ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData))); - const size_t mrpParamsSize = mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t)) : 0; - const size_t max_msg_len = TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize, // initiatorRandom, - sizeof(uint16_t), // initiatorSessionId - sizeof(PasscodeId), // passcodeId, - sizeof(uint8_t), // hasPBKDFParameters - mrpParamsSize // MRP Parameters - ); + const size_t max_msg_len = TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize, // initiatorRandom, + sizeof(uint16_t), // initiatorSessionId + sizeof(PasscodeId), // passcodeId, + sizeof(uint8_t), // hasPBKDFParameters + SessionParameters::kEstimatedTLVSize // Session Parameters + ); System::PacketBufferHandle req = System::PacketBufferHandle::New(max_msg_len); VerifyOrReturnError(!req.IsNull(), CHIP_ERROR_NO_MEMORY); @@ -290,11 +290,9 @@ CHIP_ERROR PASESession::SendPBKDFParamRequest() ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), GetLocalSessionId().Value())); ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), kDefaultCommissioningPasscodeId)); ReturnErrorOnFailure(tlvWriter.PutBoolean(TLV::ContextTag(4), mHavePBKDFParameters)); - if (mLocalMRPConfig.HasValue()) - { - ChipLogDetail(SecureChannel, "Including MRP parameters in PBKDF param request"); - ReturnErrorOnFailure(EncodeMRPParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter)); - } + + ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig, tlvWriter)); + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize(&req)); @@ -357,7 +355,7 @@ CHIP_ERROR PASESession::HandlePBKDFParamRequest(System::PacketBufferHandle && ms if (tlvReader.Next() != CHIP_END_OF_TLV) { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); } err = SendPBKDFParamResponse(ByteSpan(initiatorRandom), hasPBKDFParameters); @@ -382,13 +380,12 @@ CHIP_ERROR PASESession::SendPBKDFParamResponse(ByteSpan initiatorRandom, bool in ReturnErrorOnFailure(DRBG_get_bytes(mPBKDFLocalRandomData, sizeof(mPBKDFLocalRandomData))); - const size_t mrpParamsSize = mLocalMRPConfig.HasValue() ? TLV::EstimateStructOverhead(sizeof(uint16_t), sizeof(uint16_t)) : 0; const size_t max_msg_len = TLV::EstimateStructOverhead(kPBKDFParamRandomNumberSize, // initiatorRandom kPBKDFParamRandomNumberSize, // responderRandom sizeof(uint16_t), // responderSessionId TLV::EstimateStructOverhead(sizeof(uint32_t), mSaltLength), // pbkdf_parameters - mrpParamsSize // MRP Parameters + SessionParameters::kEstimatedTLVSize // Session Parameters ); System::PacketBufferHandle resp = System::PacketBufferHandle::New(max_msg_len); @@ -413,11 +410,7 @@ CHIP_ERROR PASESession::SendPBKDFParamResponse(ByteSpan initiatorRandom, bool in ReturnErrorOnFailure(tlvWriter.EndContainer(pbkdfParamContainer)); } - if (mLocalMRPConfig.HasValue()) - { - ChipLogDetail(SecureChannel, "Including MRP parameters in PBKDF param response"); - ReturnErrorOnFailure(EncodeMRPParameters(TLV::ContextTag(5), mLocalMRPConfig.Value(), tlvWriter)); - } + ReturnErrorOnFailure(EncodeSessionParameters(TLV::ContextTag(5), mLocalMRPConfig, tlvWriter)); ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); ReturnErrorOnFailure(tlvWriter.Finalize(&resp)); @@ -481,7 +474,7 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m if (tlvReader.Next() != CHIP_END_OF_TLV) { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); } // TODO - Add a unit test that exercises mHavePBKDFParameters path @@ -506,7 +499,7 @@ CHIP_ERROR PASESession::HandlePBKDFParamResponse(System::PacketBufferHandle && m if (tlvReader.Next() != CHIP_END_OF_TLV) { SuccessOrExit(err = DecodeMRPParametersIfPresent(TLV::ContextTag(5), tlvReader)); - mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(mRemoteMRPConfig); + mExchangeCtxt->GetSessionHandle()->AsUnauthenticatedSession()->SetRemoteMRPConfig(GetRemoteMRPConfig()); } } diff --git a/src/protocols/secure_channel/PairingSession.cpp b/src/protocols/secure_channel/PairingSession.cpp index af555bfeee5046..d3c6e96c1ef8bd 100644 --- a/src/protocols/secure_channel/PairingSession.cpp +++ b/src/protocols/secure_channel/PairingSession.cpp @@ -18,6 +18,10 @@ #include +#include +#include +#include +#include #include #include @@ -44,7 +48,7 @@ CHIP_ERROR PairingSession::ActivateSecureSession(const Transport::PeerAddress & // Call Activate last, otherwise errors on anything after would lead to // a partially valid session. - secureSession->Activate(GetLocalScopedNodeId(), GetPeer(), GetPeerCATs(), peerSessionId, mRemoteMRPConfig); + secureSession->Activate(GetLocalScopedNodeId(), GetPeer(), GetPeerCATs(), peerSessionId, GetRemoteMRPConfig()); ChipLogDetail(Inet, "New secure session activated for device " ChipLogFormatScopedNodeId ", LSID:%d PSID:%d!", ChipLogValueScopedNodeId(GetPeer()), secureSession->GetLocalSessionId(), peerSessionId); @@ -88,19 +92,44 @@ void PairingSession::DiscardExchange() } } -CHIP_ERROR PairingSession::EncodeMRPParameters(TLV::Tag tag, const ReliableMessageProtocolConfig & mrpLocalConfig, - TLV::TLVWriter & tlvWriter) +CHIP_ERROR PairingSession::EncodeSessionParameters(TLV::Tag tag, const Optional & providedMrpConfig, + TLV::TLVWriter & tlvWriter) { + // TODO: https://github.com/project-chip/connectedhomeip/issues/30456. Based on the spec we need to send values here now, + // but it is not entirely clear what we should be sending here when `providedMrpConfig.HasValue() == false`. For now we + // are sending the default MRP config values. + ReliableMessageProtocolConfig mrpLocalConfig = GetDefaultMRPConfig(); + if (providedMrpConfig.HasValue()) + { + mrpLocalConfig = providedMrpConfig.Value(); + } TLV::TLVType mrpParamsContainer; ReturnErrorOnFailure(tlvWriter.StartContainer(tag, TLV::kTLVType_Structure, mrpParamsContainer)); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), mrpLocalConfig.mIdleRetransTimeout.count())); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), mrpLocalConfig.mActiveRetransTimeout.count())); - ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), mrpLocalConfig.mActiveThresholdTime.count())); + ReturnErrorOnFailure( + tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionIdleInterval), mrpLocalConfig.mIdleRetransTimeout.count())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveInterval), + mrpLocalConfig.mActiveRetransTimeout.count())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSessionActiveThreshold), + mrpLocalConfig.mActiveThresholdTime.count())); + + uint16_t dataModel = CHIP_DEVICE_DATA_MODEL_REVISION; + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kDataModelRevision), dataModel)); + + uint16_t interactionModel = CHIP_DEVICE_INTERACTION_MODEL_REVISION; + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kInteractionModelRevision), interactionModel)); + + uint32_t specVersion = CHIP_DEVICE_SPECIFICATION_VERSION; + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kSpecificationVersion), specVersion)); + + uint16_t maxPathsPerInvoke = CHIP_CONFIG_MAX_PATHS_PER_INVOKE; + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(SessionParameters::Tag::kMaxPathsPerInvoke), maxPathsPerInvoke)); return tlvWriter.EndContainer(mrpParamsContainer); } CHIP_ERROR PairingSession::DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TLV::ContiguousBufferTLVReader & tlvReader) { + CHIP_ERROR err = CHIP_NO_ERROR; + // The MRP parameters are optional. if (tlvReader.GetTag() != expectedTag) { @@ -110,50 +139,89 @@ CHIP_ERROR PairingSession::DecodeMRPParametersIfPresent(TLV::Tag expectedTag, TL TLV::TLVType containerType = TLV::kTLVType_Structure; ReturnErrorOnFailure(tlvReader.EnterContainer(containerType)); - uint32_t tlvElementValue = 0; - ReturnErrorOnFailure(tlvReader.Next()); ChipLogDetail(SecureChannel, "Found MRP parameters in the message"); // All TLV elements in the structure are optional. If the first element is present, process it and move // the TLV reader to the next element. - if (TLV::TagNumFromTag(tlvReader.GetTag()) == 1) + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionIdleInterval) { - ReturnErrorOnFailure(tlvReader.Get(tlvElementValue)); - mRemoteMRPConfig.mIdleRetransTimeout = System::Clock::Milliseconds32(tlvElementValue); + uint32_t idleRetransTimeout; + ReturnErrorOnFailure(tlvReader.Get(idleRetransTimeout)); + mRemoteSessionParams.SetMRPIdleRetransTimeout(System::Clock::Milliseconds32(idleRetransTimeout)); // The next element is optional. If it's not present, return CHIP_NO_ERROR. - CHIP_ERROR err = tlvReader.Next(); - if (err == CHIP_END_OF_TLV) - { - return tlvReader.ExitContainer(containerType); - } - ReturnErrorOnFailure(err); + SuccessOrExit(err = tlvReader.Next()); } - if (TLV::TagNumFromTag(tlvReader.GetTag()) == 2) + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveInterval) { - ReturnErrorOnFailure(tlvReader.Get(tlvElementValue)); - mRemoteMRPConfig.mActiveRetransTimeout = System::Clock::Milliseconds32(tlvElementValue); + uint32_t activeRetransTimeout; + ReturnErrorOnFailure(tlvReader.Get(activeRetransTimeout)); + mRemoteSessionParams.SetMRPActiveRetransTimeout(System::Clock::Milliseconds32(activeRetransTimeout)); // The next element is optional. If it's not present, return CHIP_NO_ERROR. - CHIP_ERROR err = tlvReader.Next(); - if (err == CHIP_END_OF_TLV) - { - return tlvReader.ExitContainer(containerType); - } - ReturnErrorOnFailure(err); + SuccessOrExit(err = tlvReader.Next()); } - if (TLV::TagNumFromTag(tlvReader.GetTag()) == 3) + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSessionActiveThreshold) { - ReturnErrorOnFailure(tlvReader.Get(tlvElementValue)); - mRemoteMRPConfig.mActiveThresholdTime = System::Clock::Milliseconds16(tlvElementValue); + uint16_t activeThresholdTime; + ReturnErrorOnFailure(tlvReader.Get(activeThresholdTime)); + mRemoteSessionParams.SetMRPActiveThresholdTime(System::Clock::Milliseconds16(activeThresholdTime)); + + // The next element is optional. If it's not present, return CHIP_NO_ERROR. + SuccessOrExit(err = tlvReader.Next()); + } + + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kDataModelRevision) + { + uint16_t dataModelRevision; + ReturnErrorOnFailure(tlvReader.Get(dataModelRevision)); + mRemoteSessionParams.SetDataModelRevision(dataModelRevision); + + // The next element is optional. If it's not present, return CHIP_NO_ERROR. + SuccessOrExit(err = tlvReader.Next()); + } + + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kInteractionModelRevision) + { + uint16_t interactionModelRevision; + ReturnErrorOnFailure(tlvReader.Get(interactionModelRevision)); + mRemoteSessionParams.SetInteractionModelRevision(interactionModelRevision); + + // The next element is optional. If it's not present, return CHIP_NO_ERROR. + SuccessOrExit(err = tlvReader.Next()); + } + + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kSpecificationVersion) + { + uint32_t specificationVersion; + ReturnErrorOnFailure(tlvReader.Get(specificationVersion)); + mRemoteSessionParams.SetSpecificationVersion(specificationVersion); + + // The next element is optional. If it's not present, return CHIP_NO_ERROR. + SuccessOrExit(err = tlvReader.Next()); } - // Future proofing - Don't error out if there are other tags - return tlvReader.ExitContainer(containerType); + if (TLV::TagNumFromTag(tlvReader.GetTag()) == SessionParameters::Tag::kMaxPathsPerInvoke) + { + uint16_t maxPathsPerInvoke; + ReturnErrorOnFailure(tlvReader.Get(maxPathsPerInvoke)); + mRemoteSessionParams.SetMaxPathsPerInvoke(maxPathsPerInvoke); + + // The next element is optional. If it's not present, return CHIP_NO_ERROR. + SuccessOrExit(err = tlvReader.Next()); + } + + // Future proofing - Don't error out if there are other tags +exit: + if (err == CHIP_END_OF_TLV) + { + return tlvReader.ExitContainer(containerType); + } + return err; } bool PairingSession::IsSessionEstablishmentInProgress() diff --git a/src/protocols/secure_channel/PairingSession.h b/src/protocols/secure_channel/PairingSession.h index c604cd0662dfd3..039705efa16745 100644 --- a/src/protocols/secure_channel/PairingSession.h +++ b/src/protocols/secure_channel/PairingSession.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -96,14 +97,14 @@ class DLL_EXPORT PairingSession : public SessionDelegate */ virtual CHIP_ERROR DeriveSecureSession(CryptoContext & session) const = 0; - const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteMRPConfig; } - void SetRemoteMRPConfig(const ReliableMessageProtocolConfig & config) { mRemoteMRPConfig = config; } + const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteSessionParams.GetMRPConfig(); } + void SetRemoteMRPConfig(const ReliableMessageProtocolConfig & config) { mRemoteSessionParams.SetMRPConfig(config); } /** - * Encode the provided MRP parameters using the provided TLV tag. + * Encode the Session Parameters using the provided TLV tag. */ - static CHIP_ERROR EncodeMRPParameters(TLV::Tag tag, const ReliableMessageProtocolConfig & mrpLocalConfig, - TLV::TLVWriter & tlvWriter); + static CHIP_ERROR EncodeSessionParameters(TLV::Tag tag, const Optional & mrpLocalConfig, + TLV::TLVWriter & tlvWriter); protected: /** @@ -200,7 +201,7 @@ class DLL_EXPORT PairingSession : public SessionDelegate /** * Try to decode the current element (pointed by the TLV reader) as MRP parameters. - * If the MRP parameters are found, mRemoteMRPConfig is updated with the devoded values. + * If the MRP parameters are found, mRemoteSessionParams is updated with the devoded values. * * MRP parameters are optional. So, if the TLV reader is not pointing to the MRP parameters, * the function is a noop. @@ -231,9 +232,9 @@ class DLL_EXPORT PairingSession : public SessionDelegate SessionEstablishmentDelegate * mDelegate = nullptr; // mLocalMRPConfig is our config which is sent to the other end and used by the peer session. - // mRemoteMRPConfig is received from other end and set to our session. + // mRemoteSessionParams is received from other end and set to our session. Optional mLocalMRPConfig; - ReliableMessageProtocolConfig mRemoteMRPConfig = GetDefaultMRPConfig(); + SessionParameters mRemoteSessionParams; private: Optional mPeerSessionId; diff --git a/src/protocols/secure_channel/SessionParameters.h b/src/protocols/secure_channel/SessionParameters.h new file mode 100644 index 00000000000000..a595e7803aa633 --- /dev/null +++ b/src/protocols/secure_channel/SessionParameters.h @@ -0,0 +1,109 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { + +// TODO We should get part of this from constexpr that is in ReliableMessageProtocolConfig.h + +class SessionParameters +{ +public: + SessionParameters(ReliableMessageProtocolConfig mrpConfig = GetDefaultMRPConfig()) : mMRPConfig(mrpConfig) {} + + // This estimated TLV size calc is here instead of messaging/ReliableMessageProtocolConfig.h + // because we would need to add `include `. While we could make it all work + // from a build standpoint, if any new MRP config gets added accessors will still need to be + // added here so having this calc done here isn't problematic. + static constexpr size_t kSizeOfSessionIdleInterval = sizeof(uint32_t); + static constexpr size_t kSizeOfSessionActiveInterval = sizeof(uint32_t); + static constexpr size_t kSizeOfSessionActiveThreshold = sizeof(uint16_t); + static constexpr size_t kSizeOfDataModelRevision = sizeof(uint16_t); + static constexpr size_t kSizeOfInteractionModelRevision = sizeof(uint16_t); + static constexpr size_t kSizeOfSpecificationVersion = sizeof(uint32_t); + static constexpr size_t kSizeOfMaxPathsPerInvoke = sizeof(uint16_t); + + static constexpr size_t kEstimatedTLVSize = TLV::EstimateStructOverhead( + kSizeOfSessionIdleInterval, kSizeOfSessionActiveInterval, kSizeOfSessionActiveThreshold, kSizeOfDataModelRevision, + kSizeOfInteractionModelRevision, kSizeOfSpecificationVersion, kSizeOfMaxPathsPerInvoke); + + // From Section 4.12.8 "Parameters and Constants" in chapter "Secure Channel". + enum Tag : uint32_t + { + kSessionIdleInterval = 1, + kSessionActiveInterval = 2, + kSessionActiveThreshold = 3, + kDataModelRevision = 4, + kInteractionModelRevision = 5, + kSpecificationVersion = 6, + kMaxPathsPerInvoke = 7, + }; + + const ReliableMessageProtocolConfig & GetMRPConfig() const { return mMRPConfig; } + void SetMRPConfig(const ReliableMessageProtocolConfig & config) { mMRPConfig = config; } + void SetMRPIdleRetransTimeout(const System::Clock::Milliseconds32 idleRetransTimeout) + { + mMRPConfig.mIdleRetransTimeout = idleRetransTimeout; + } + void SetMRPActiveRetransTimeout(const System::Clock::Milliseconds32 activeRetransTimeout) + { + mMRPConfig.mActiveRetransTimeout = activeRetransTimeout; + } + void SetMRPActiveThresholdTime(const System::Clock::Milliseconds16 activeThresholdTime) + { + mMRPConfig.mActiveThresholdTime = activeThresholdTime; + } + + const Optional & GetDataModelRevision() const { return mDataModelRevision; } + void SetDataModelRevision(const uint16_t dataModelRevision) { mDataModelRevision = MakeOptional(dataModelRevision); } + + const Optional & GetInteractionModelRevision() const { return mInteractionModelRevision; } + void SetInteractionModelRevision(const uint16_t interactionModelRevision) + { + mInteractionModelRevision = MakeOptional(interactionModelRevision); + } + + const Optional & GetSpecificationVersion() const { return mSpecificationVersion; } + void SetSpecificationVersion(const uint32_t specificationVersion) + { + mSpecificationVersion = MakeOptional(specificationVersion); + } + + uint16_t GetMaxPathsPerInvoke() const { return mMaxPathsPerInvoke; } + void SetMaxPathsPerInvoke(const uint16_t maxPathsPerInvoke) { mMaxPathsPerInvoke = maxPathsPerInvoke; } + +private: + ReliableMessageProtocolConfig mMRPConfig; + // For legacy reasons if we do not get DataModelRevision it means either 16 or 17. But there isn't + // a way to know for certain. + Optional mDataModelRevision; + // For legacy reasons if we do not get InteractionModelRevision it means either 10 or 11. But there + // isn't a way to know for certain. + Optional mInteractionModelRevision; + // For legacy reasons if we do not get SpecificationVersion it means that version is less than + // 0x01030000. But there isn't a way to know for certain. + Optional mSpecificationVersion; + // When maxPathsPerInvoke is not provided legacy is always 1 + uint16_t mMaxPathsPerInvoke = 1; +}; + +} // namespace chip diff --git a/src/protocols/secure_channel/tests/TestPairingSession.cpp b/src/protocols/secure_channel/tests/TestPairingSession.cpp index 714a18e03fc1a4..ac1c4537888bc8 100644 --- a/src/protocols/secure_channel/tests/TestPairingSession.cpp +++ b/src/protocols/secure_channel/tests/TestPairingSession.cpp @@ -46,7 +46,7 @@ class TestPairingSession : public PairingSession void OnSessionReleased() override {} - const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return mRemoteMRPConfig; } + const ReliableMessageProtocolConfig & GetRemoteMRPConfig() const { return PairingSession::GetRemoteMRPConfig(); } CHIP_ERROR DeriveSecureSession(CryptoContext & session) const override { return CHIP_NO_ERROR; } @@ -70,7 +70,8 @@ void PairingSessionEncodeDecodeMRPParams(nlTestSuite * inSuite, void * inContext NL_TEST_ASSERT(inSuite, writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, PairingSession::EncodeMRPParameters(TLV::ContextTag(1), config, writer) == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, + PairingSession::EncodeSessionParameters(TLV::ContextTag(1), MakeOptional(config), writer) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, writer.EndContainer(outerContainerType) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, writer.Finalize(&buf) == CHIP_NO_ERROR);