From a68f2c06a8c01acb46c2c47282d3e721a7746606 Mon Sep 17 00:00:00 2001 From: Alami-Amine Date: Tue, 14 Jan 2025 19:40:53 +0100 Subject: [PATCH] Integrating Comments and Adding comments --- src/protocols/secure_channel/CASESession.cpp | 87 +++++++++--------- src/protocols/secure_channel/CASESession.h | 90 +++++++++++++++++-- .../secure_channel/tests/TestCASESession.cpp | 7 +- 3 files changed, 133 insertions(+), 51 deletions(-) diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 55dc4224589086..aa5de2498f488a 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -110,6 +110,8 @@ constexpr chip::TLV::Tag AsTlvContextTag(Enum e) return chip::TLV::ContextTag(chip::to_underlying(e)); } +constexpr size_t kCaseOverheadForFutureTbeData = 128; + } // namespace namespace chip { @@ -1520,15 +1522,12 @@ CHIP_ERROR CASESession::HandleSigma2(System::PacketBufferHandle && msg) GetRemoteSessionParameters()); } - size_t msgR2EncryptedLen = parsedSigma2.msgR2Encrypted.AllocatedSize() - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; - - ReturnErrorOnFailure(AES_CCM_decrypt(parsedSigma2.msgR2Encrypted.Get(), msgR2EncryptedLen, nullptr, 0, - parsedSigma2.msgR2Encrypted.Get() + msgR2EncryptedLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, - sr2k.KeyHandle(), kTBEData2_Nonce, kTBEDataNonceLength, - parsedSigma2.msgR2Encrypted.Get())); + ReturnErrorOnFailure(AES_CCM_decrypt(parsedSigma2.msgR2EncryptedPayload.data(), parsedSigma2.msgR2EncryptedPayload.size(), + nullptr, 0, parsedSigma2.msgR2Mic.data(), parsedSigma2.msgR2Mic.size(), sr2k.KeyHandle(), + kTBEData2_Nonce, kTBEDataNonceLength, parsedSigma2.msgR2EncryptedPayload.data())); ContiguousBufferTLVReader decryptedDataTlvReader; - decryptedDataTlvReader.Init(parsedSigma2.msgR2Encrypted.Get(), msgR2EncryptedLen); + decryptedDataTlvReader.Init(parsedSigma2.msgR2EncryptedPayload.data(), parsedSigma2.msgR2EncryptedPayload.size()); ParsedSigma2TBEData parsedSigma2TBEData; ReturnErrorOnFailure(ParseSigma2TBEData(decryptedDataTlvReader, parsedSigma2TBEData)); @@ -1600,8 +1599,6 @@ CHIP_ERROR CASESession::ParseSigma2(ContiguousBufferTLVReader & tlvReader, Parse // Generate decrypted data ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma2Tags::kEncrypted2))); - constexpr size_t kCaseOverheadForFutureTbeData = 128; - size_t maxMsgR2SignedEncLen = EstimateStructOverhead(kMaxCHIPCertLength, // responderNOC kMaxCHIPCertLength, // responderICAC kMax_ECDSA_Signature_Length, // signature @@ -1615,9 +1612,13 @@ CHIP_ERROR CASESession::ParseSigma2(ContiguousBufferTLVReader & tlvReader, Parse VerifyOrReturnError(msgR2EncryptedLenWithTag <= maxMsgR2SignedEncLen, CHIP_ERROR_INVALID_TLV_ELEMENT); VerifyOrReturnError(msgR2EncryptedLenWithTag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_TLV_ELEMENT); VerifyOrReturnError(outParsedSigma2.msgR2Encrypted.Alloc(msgR2EncryptedLenWithTag), CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(tlvReader.GetBytes(outParsedSigma2.msgR2Encrypted.Get(), outParsedSigma2.msgR2Encrypted.AllocatedSize())); + size_t msgR2EncryptedPayloadLen = msgR2EncryptedLenWithTag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; + outParsedSigma2.msgR2EncryptedPayload = MutableByteSpan(outParsedSigma2.msgR2Encrypted.Get(), msgR2EncryptedPayloadLen); + outParsedSigma2.msgR2Mic = + ByteSpan(outParsedSigma2.msgR2Encrypted.Get() + msgR2EncryptedPayloadLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES); + // Retrieve responderSessionParams if present CHIP_ERROR err = tlvReader.Next(); if (err == CHIP_NO_ERROR && tlvReader.GetTag() == AsTlvContextTag(Sigma2Tags::kResponderSessionParams)) @@ -1662,11 +1663,10 @@ CHIP_ERROR CASESession::ParseSigma2TBEData(ContiguousBufferTLVReader & decrypted } VerifyOrReturnError(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), CHIP_ERROR_INVALID_TLV_TAG); - // TODO verify if the below modification in the check is correct (also for Sigma 3) // tbsData2Signature's length should equal kMax_ECDSA_Signature_Length as per the Specification - VerifyOrReturnError(outParsedSigma2TBE.tbsData2Signature.Capacity() == decryptedDataTlvReader.GetLength(), - CHIP_ERROR_INVALID_TLV_ELEMENT); - outParsedSigma2TBE.tbsData2Signature.SetLength(decryptedDataTlvReader.GetLength()); + size_t signatureLen = decryptedDataTlvReader.GetLength(); + VerifyOrReturnError(outParsedSigma2TBE.tbsData2Signature.Capacity() == signatureLen, CHIP_ERROR_INVALID_TLV_ELEMENT); + outParsedSigma2TBE.tbsData2Signature.SetLength(signatureLen); ReturnErrorOnFailure(decryptedDataTlvReader.GetBytes(outParsedSigma2TBE.tbsData2Signature.Bytes(), outParsedSigma2TBE.tbsData2Signature.Length())); @@ -1893,16 +1893,12 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) { MATTER_TRACE_SCOPE("HandleSigma3", "CASESession"); CHIP_ERROR err = CHIP_NO_ERROR; - System::PacketBufferTLVReader tlvReader; ContiguousBufferTLVReader decryptedDataTlvReader; TLVType containerType = kTLVType_Structure; const uint8_t * buf = msg->Start(); const size_t bufLen = msg->DataLength(); - Platform::ScopedMemoryBufferWithSize msgR3Encrypted; - size_t msgR3EncryptedLen = 0; - AutoReleaseSessionKey sr3k(*mSessionManager->GetSessionKeystore()); uint8_t msg_salt[kIPKSize + kSHA256_Hash_Length]; @@ -1925,32 +1921,39 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) VerifyOrExit(mEphemeralKey != nullptr, err = CHIP_ERROR_INTERNAL); - tlvReader.Init(std::move(msg)); - - SuccessOrExit(err = ParseSigma3(tlvReader, msgR3Encrypted)); - // Step 1 + // msgR3Encrypted will be allocated and initialised within ParseSigma3() + Platform::ScopedMemoryBufferWithSize msgR3Encrypted; + // both msgR3EncryptedPayload and msgR3Mic will become backed by msgR3Encrypted in ParseSigma3() + MutableByteSpan msgR3EncryptedPayload; + ByteSpan msgR3Mic; { + System::PacketBufferTLVReader tlvReader; + tlvReader.Init(std::move(msg)); + SuccessOrExit(err = ParseSigma3(tlvReader, msgR3Encrypted, msgR3EncryptedPayload, msgR3Mic)); + + // Generate the S3K key MutableByteSpan saltSpan(msg_salt); SuccessOrExit(err = ConstructSaltSigma3(ByteSpan(mIPK), saltSpan)); SuccessOrExit(err = DeriveSigmaKey(saltSpan, ByteSpan(kKDFSR3Info), sr3k)); - } - - SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, bufLen })); + // Add Sigma3 to the TranscriptHash which will be used to generate the Session Encryption Keys + SuccessOrExit(err = mCommissioningHash.AddData(ByteSpan{ buf, bufLen })); + } // Step 2 - Decrypt data blob - msgR3EncryptedLen = msgR3Encrypted.AllocatedSize() - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; - - SuccessOrExit(err = AES_CCM_decrypt(msgR3Encrypted.Get(), msgR3EncryptedLen, nullptr, 0, - msgR3Encrypted.Get() + msgR3EncryptedLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, - sr3k.KeyHandle(), kTBEData3_Nonce, kTBEDataNonceLength, msgR3Encrypted.Get())); + SuccessOrExit(err = AES_CCM_decrypt(msgR3EncryptedPayload.data(), msgR3EncryptedPayload.size(), nullptr, 0, msgR3Mic.data(), + msgR3Mic.size(), sr3k.KeyHandle(), kTBEData3_Nonce, kTBEDataNonceLength, + msgR3EncryptedPayload.data())); - decryptedDataTlvReader.Init(msgR3Encrypted.Get(), msgR3EncryptedLen); + decryptedDataTlvReader.Init(msgR3EncryptedPayload.data(), msgR3EncryptedPayload.size()); SuccessOrExit(err = ParseSigma3TBEData(decryptedDataTlvReader, data)); // Step 3 - Construct Sigma3 TBS Data - data.msgR3SignedLen = TLV::EstimateStructOverhead(data.initiatorNOC.size(), data.initiatorICAC.size(), - kP256_PublicKey_Length, kP256_PublicKey_Length); + data.msgR3SignedLen = TLV::EstimateStructOverhead(data.initiatorNOC.size(), // initiatorNOC + data.initiatorICAC.size(), // initiatorICAC + kP256_PublicKey_Length, // initiatorEphPubKey + kP256_PublicKey_Length // responderEphPubKey + ); VerifyOrExit(data.msgR3Signed.Alloc(data.msgR3SignedLen), err = CHIP_ERROR_NO_MEMORY); @@ -2007,7 +2010,8 @@ CHIP_ERROR CASESession::HandleSigma3a(System::PacketBufferHandle && msg) } CHIP_ERROR CASESession::ParseSigma3(ContiguousBufferTLVReader & tlvReader, - Platform::ScopedMemoryBufferWithSize & msgR3Encrypted) + Platform::ScopedMemoryBufferWithSize & outMsgR3Encrypted, + MutableByteSpan & outMsgR3EncryptedPayload, ByteSpan & outMsgR3Mic) { TLVType containerType = kTLVType_Structure; @@ -2017,8 +2021,6 @@ CHIP_ERROR CASESession::ParseSigma3(ContiguousBufferTLVReader & tlvReader, // Fetch encrypted data ReturnErrorOnFailure(tlvReader.Next(AsTlvContextTag(Sigma3Tags::kEncrypted3))); - constexpr size_t kCaseOverheadForFutureTbeData = 128; - size_t maxMsgR3SignedEncLen = EstimateStructOverhead(kMaxCHIPCertLength, // initiatorNOC kMaxCHIPCertLength, // initiatorICAC kMax_ECDSA_Signature_Length, // signature @@ -2030,9 +2032,12 @@ CHIP_ERROR CASESession::ParseSigma3(ContiguousBufferTLVReader & tlvReader, // Validate we did not receive a buffer larger than legal VerifyOrReturnError(msgR3EncryptedLenWithTag <= maxMsgR3SignedEncLen, CHIP_ERROR_INVALID_TLV_ELEMENT); VerifyOrReturnError(msgR3EncryptedLenWithTag > CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES, CHIP_ERROR_INVALID_TLV_ELEMENT); - VerifyOrReturnError(msgR3Encrypted.Alloc(msgR3EncryptedLenWithTag), CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(outMsgR3Encrypted.Alloc(msgR3EncryptedLenWithTag), CHIP_ERROR_NO_MEMORY); + ReturnErrorOnFailure(tlvReader.GetBytes(outMsgR3Encrypted.Get(), outMsgR3Encrypted.AllocatedSize())); - ReturnErrorOnFailure(tlvReader.GetBytes(msgR3Encrypted.Get(), msgR3Encrypted.AllocatedSize())); + size_t msgR3EncryptedPayloadLen = msgR3EncryptedLenWithTag - CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES; + outMsgR3EncryptedPayload = MutableByteSpan(outMsgR3Encrypted.Get(), msgR3EncryptedPayloadLen); + outMsgR3Mic = ByteSpan(outMsgR3Encrypted.Get() + msgR3EncryptedPayloadLen, CHIP_CRYPTO_AEAD_MIC_LENGTH_BYTES); ReturnErrorOnFailure(tlvReader.ExitContainer(containerType)); @@ -2060,9 +2065,9 @@ CHIP_ERROR CASESession::ParseSigma3TBEData(ContiguousBufferTLVReader & decrypted } VerifyOrReturnError(decryptedDataTlvReader.GetTag() == AsTlvContextTag(TBEDataTags::kSignature), CHIP_ERROR_INVALID_TLV_TAG); - VerifyOrReturnError(outHandleSigma3TBEData.tbsData3Signature.Capacity() == decryptedDataTlvReader.GetLength(), - CHIP_ERROR_INVALID_TLV_ELEMENT); - outHandleSigma3TBEData.tbsData3Signature.SetLength(decryptedDataTlvReader.GetLength()); + size_t signatureLen = decryptedDataTlvReader.GetLength(); + VerifyOrReturnError(outHandleSigma3TBEData.tbsData3Signature.Capacity() == signatureLen, CHIP_ERROR_INVALID_TLV_ELEMENT); + outHandleSigma3TBEData.tbsData3Signature.SetLength(signatureLen); ReturnErrorOnFailure(decryptedDataTlvReader.GetBytes(outHandleSigma3TBEData.tbsData3Signature.Bytes(), outHandleSigma3TBEData.tbsData3Signature.Length())); diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index f514d0ca8f554b..ed300dbd03a02c 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -221,6 +221,9 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, struct ParsedSigma1 : Sigma1Param { + // Backed by: Sigma1 PacketBuffer passed to the method HandleSigma1() + // Lifetime: Valid for the lifetime of the tlvReader, which takes ownership of the Sigma1 PacketBuffer in the HandleSigma1() + // method. ByteSpan initiatorEphPubKey; bool initiatorSessionParamStructPresent = false; SessionParameters initiatorSessionParams; @@ -239,20 +242,30 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, }; struct ParsedSigma2 { + // Below ByteSpans are Backed by: Sigma2 PacketBuffer passed to the method HandleSigma2() + // Lifetime: Valid for the lifetime of the tlvReader, which takes ownership of the Sigma2 PacketBuffer in the HandleSigma2() + // method. ByteSpan responderRandom; - uint16_t responderSessionId; ByteSpan responderEphPubKey; + Platform::ScopedMemoryBufferWithSize msgR2Encrypted; - bool responderSessionParamStructPresent = false; + // Below ByteSpans are Backed by: msgR2Encrypted buffer + // Lifetime: Valid as long as msgR2Encrypted is not released + MutableByteSpan msgR2EncryptedPayload; + ByteSpan msgR2Mic; SessionParameters responderSessionParams; + uint16_t responderSessionId; + bool responderSessionParamStructPresent = false; }; struct ParsedSigma2TBEData { + // Below ByteSpans are Backed by: msgR2Encrypted Buffer, member of ParsedSigma2 struct + // Lifetime: Valid for the lifetime of the instance of ParsedSigma2 that contains the msgR2Encrypted Buffer. ByteSpan responderNOC; ByteSpan responderICAC; - Crypto::P256ECDSASignature tbsData2Signature; ByteSpan resumptionId; + Crypto::P256ECDSASignature tbsData2Signature; }; struct EncodeSigma2ResumeInputs @@ -266,10 +279,13 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, struct ParsedSigma2Resume { + // Below ByteSpans are Backed by: Sigma2Resume PacketBuffer passed to the method HandleSigma2Resume() + // Lifetime: Valid for the lifetime of the tlvReader, which takes ownership of the Sigma2Resume PacketBuffer in the + // HandleSigma2Resume() method. ByteSpan resumptionId; ByteSpan sigma2ResumeMIC; - uint16_t responderSessionId; SessionParameters responderSessionParams; + uint16_t responderSessionId; bool responderSessionParamStructPresent = false; }; @@ -301,6 +317,8 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, chip::Platform::ScopedMemoryBuffer msgR3Signed; size_t msgR3SignedLen; + // Below ByteSpans are Backed by: msgR3Encrypted Buffer, local to the HandleSigma3a() method, + // The Spans are later modified to point to the msgR3Signed member of this struct. ByteSpan initiatorNOC; ByteSpan initiatorICAC; @@ -348,10 +366,40 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, */ static CHIP_ERROR ParseSigma1(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma1 & parsedMessage); - static CHIP_ERROR ParseSigma2(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma2 & parsedMessage); + /** + * Parse a Sigma2 message. This function will return success only if the + * message passes schema checks. + * + * @param tlvReader a reference to the TLVReader that has ownership of the Sigma2 PacketBuffer. + * @param outParsedSigma2 a reference to ParsedSigma2. All members of parsedMessage will stay valid as long as tlvReader is + * valid. + * + * @note Calls to this function must always be made with a newly created and fresh ParsedSigma2 parameter. + **/ + static CHIP_ERROR ParseSigma2(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma2 & outParsedSigma2); - static CHIP_ERROR ParseSigma2TBEData(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma2TBEData & parsedMessage); + /** + * Parse a decrypted TBEData2Encrypted message. This function will return success only if the message passes schema checks. + * + * @param tlvReader a reference to the TLVReader that points to the decrypted TBEData2Encrypted buffer (i.e. + * msgR2Encrypted member of ParsedSigma2 struct) + * @param outParsedSigma2TBEData a reference to ParsedSigma2TBEData. All members of parsedMessage will stay valid as long + * as the msgR2Encrypted member of ParsedSigma2 is valid + * + * @note Calls to this function must always be made with a newly created and fresh ParsedSigma2TBEData parameter. + **/ + static CHIP_ERROR ParseSigma2TBEData(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma2TBEData & outParsedSigma2TBEData); + /** + * Parse a Sigma2Resume message. This function will return success only if the + * message passes schema checks. + * + * @param tlvReader a reference to the TLVReader that has ownership of the Sigma2Resume PacketBuffer. + * @param outParsedSigma2Resume a reference to ParsedSigma2Resume. All members of parsedMessage will stay valid as long + * as tlvReader is valid. + * + * @note Calls to this function must always be made with a newly created and fresh ParsedSigma2Resume parameter. + **/ static CHIP_ERROR ParseSigma2Resume(TLV::ContiguousBufferTLVReader & tlvReader, ParsedSigma2Resume & outParsedSigma2Resume); /** @@ -380,9 +428,37 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, **/ static CHIP_ERROR EncodeSigma2Resume(System::PacketBufferHandle & outMsg, EncodeSigma2ResumeInputs & inParam); + /** + * Parse a Sigma3 message. This function will return success only if the + * message passes schema checks. + * + * @param tlvReader a reference to the TLVReader that has ownership of the Sigma3 PacketBuffer. + * + * @param outMsgR3Encrypted The encrypted3 (TBEData3Encrypted) TLV element. This will be a buffer that is owned by the caller + * but is allocated and initialised within ParseSigma3. Calls to this function must always be made with + * a newly created and fresh outMsgR3Encrypted + * + * @param outMsgR3EncryptedPayload reference to a span that will be set to point to the payload of outMsgR3Encrypted within + * ParseSigma3. Calls to this function must always be made with a newly created and fresh + * outMsgR3Mic + * + * @param outMsgR3Mic reference to a span that will be set to point to the MIC of outMsgR3Encrypted within ParseSigma3. + * Calls to this function must always be made with a newly created and fresh outMsgR3Mic + * + * @note all out parameters will be valid as long the Buffer outMsgR3Encrypted is valid. + **/ static CHIP_ERROR ParseSigma3(TLV::ContiguousBufferTLVReader & tlvReader, - Platform::ScopedMemoryBufferWithSize & msgR3Encrypted); + Platform::ScopedMemoryBufferWithSize & outMsgR3Encrypted, + MutableByteSpan & outMsgR3EncryptedPayload, ByteSpan & outMsgR3Mic); + /** + * Parse a decrypted TBEData3Encrypted message. This function will return success only if the + * message passes schema checks. + * + * @param tlvReader a reference to the TLVReader that points to the decrypted TBEData3Encrypted buffer. + * @param data a reference to HandleSigma3Data. + * + **/ static CHIP_ERROR ParseSigma3TBEData(TLV::ContiguousBufferTLVReader & tlvReader, HandleSigma3Data & data); private: diff --git a/src/protocols/secure_channel/tests/TestCASESession.cpp b/src/protocols/secure_channel/tests/TestCASESession.cpp index 1acaaf422f8c16..7ce3b3260e68ae 100644 --- a/src/protocols/secure_channel/tests/TestCASESession.cpp +++ b/src/protocols/secure_channel/tests/TestCASESession.cpp @@ -1175,7 +1175,6 @@ struct Sigma2FutureProofTlvElementNoStructEnd : public BadSigma2ParamsBase static constexpr bool kIncludeStructEnd = false; }; -// TODO: Consider making this test (and similar ones) to Value-Parameterized tests once pw_unit_test:light starts supporting them TEST_F(TestCASESession, Sigma2ParsingTest) { // 1280 bytes must be enough by definition. @@ -2027,8 +2026,11 @@ static CHIP_ERROR EncodeSigma3Helper(MutableByteSpan & buf) TLV::ContiguousBufferTLVReader reader; \ reader.Init(buf); \ Platform::ScopedMemoryBufferWithSize msgR3Encrypted; \ + MutableByteSpan msgR3EncryptedPayload; \ + ByteSpan msgR3Mic; \ \ - EXPECT_EQ(CASESessionAccess::ParseSigma3(reader, msgR3Encrypted) == CHIP_NO_ERROR, params::kExpectSuccess); \ + EXPECT_EQ(CASESessionAccess::ParseSigma3(reader, msgR3Encrypted, msgR3EncryptedPayload, msgR3Mic) == CHIP_NO_ERROR, \ + params::kExpectSuccess); \ if (params::kExpectSuccess) \ { \ /* Add other verification tests here as desired */ \ @@ -2070,7 +2072,6 @@ struct Sigma3FutureProofTlvElementNoStructEnd : public BadSigma3ParamsBase static constexpr bool kIncludeStructEnd = false; }; -// TODO: Consider making this test (and similar ones) to Value-Parameterized tests once pw_unit_test:light starts supporting them TEST_F(TestCASESession, Sigma3ParsingTest) { // 1280 bytes must be enough by definition.