blob: 6a99d92a94cc588a07248df7417c887e410f47c5 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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.
*/
/**
* @file
* This file implements the the CHIP CASE Session object that provides
* APIs for constructing a secure session using a certificate from the device's
* operational credentials.
*
*/
#include <protocols/secure_channel/CASESession.h>
#include <inttypes.h>
#include <string.h>
#include <core/CHIPEncoding.h>
#include <core/CHIPSafeCasts.h>
#include <protocols/Protocols.h>
#include <support/BufferWriter.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/SafeInt.h>
#include <support/ScopedBuffer.h>
#include <transport/SecureSessionMgr.h>
namespace chip {
constexpr uint8_t kIPKInfo[] = { 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f,
0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79 };
constexpr uint8_t kKDFSR2Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x52, 0x32 };
constexpr uint8_t kKDFSR3Info[] = { 0x53, 0x69, 0x67, 0x6d, 0x61, 0x52, 0x33 };
constexpr size_t kKDFInfoLength = sizeof(kKDFSR2Info);
constexpr uint8_t kKDFSEInfo[] = { 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73 };
constexpr size_t kKDFSEInfoLength = sizeof(kKDFSEInfo);
constexpr uint8_t kIVSR2[] = { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x52, 0x32 };
constexpr uint8_t kIVSR3[] = { 0x4e, 0x43, 0x41, 0x53, 0x45, 0x5f, 0x53, 0x69, 0x67, 0x6d, 0x61, 0x52, 0x33 };
constexpr size_t kIVLength = sizeof(kIVSR2);
constexpr size_t kTAGSize = 16;
using namespace Crypto;
using namespace Credentials;
using namespace Messaging;
#ifdef ENABLE_HSM_HKDF
using HKDF_sha_crypto = HKDF_shaHSM;
#else
using HKDF_sha_crypto = HKDF_sha;
#endif
// Wait at most 10 seconds for the response from the peer.
// This timeout value assumes the underlying transport is reliable.
// The session establishment fails if the response is not received within timeout window.
static constexpr ExchangeContext::Timeout kSigma_Response_Timeout = 10000;
CASESession::CASESession()
{
mTrustedRootId.mId = nullptr;
// dummy initialization REMOVE LATER
for (size_t i = 0; i < mFabricSecret.Capacity(); i++)
{
mFabricSecret[i] = static_cast<uint8_t>(i);
}
mFabricSecret.SetLength(mFabricSecret.Capacity());
}
CASESession::~CASESession()
{
// Let's clear out any security state stored in the object, before destroying it.
Clear();
}
void CASESession::Clear()
{
// This function zeroes out and resets the memory used by the object.
// It's done so that no security related information will be leaked.
mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr;
mCommissioningHash.Clear();
mPairingComplete = false;
mConnectionState.Reset();
if (mTrustedRootId.mId != nullptr)
{
chip::Platform::MemoryFree(const_cast<uint8_t *>(mTrustedRootId.mId));
mTrustedRootId.mId = nullptr;
}
CloseExchange();
}
void CASESession::CloseExchange()
{
if (mExchangeCtxt != nullptr)
{
mExchangeCtxt->Close();
mExchangeCtxt = nullptr;
}
}
CHIP_ERROR CASESession::Serialize(CASESessionSerialized & output)
{
uint16_t serializedLen = 0;
CASESessionSerializable serializable;
VerifyOrReturnError(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner), CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(ToSerializable(serializable));
serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast<uint8_t *>(&serializable)),
static_cast<uint16_t>(sizeof(serializable)), Uint8::to_char(output.inner));
VerifyOrReturnError(serializedLen > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(serializedLen < sizeof(output.inner), CHIP_ERROR_INVALID_ARGUMENT);
output.inner[serializedLen] = '\0';
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::Deserialize(CASESessionSerialized & input)
{
CASESessionSerializable serializable;
size_t maxlen = BASE64_ENCODED_LEN(sizeof(serializable));
size_t len = strnlen(Uint8::to_char(input.inner), maxlen);
uint16_t deserializedLen = 0;
VerifyOrReturnError(len < sizeof(CASESessionSerialized), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(CanCastTo<uint16_t>(len), CHIP_ERROR_INVALID_ARGUMENT);
memset(&serializable, 0, sizeof(serializable));
deserializedLen =
Base64Decode(Uint8::to_const_char(input.inner), static_cast<uint16_t>(len), Uint8::to_uchar((uint8_t *) &serializable));
VerifyOrReturnError(deserializedLen > 0, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(deserializedLen <= sizeof(serializable), CHIP_ERROR_INVALID_ARGUMENT);
ReturnErrorOnFailure(FromSerializable(serializable));
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::ToSerializable(CASESessionSerializable & serializable)
{
const NodeId peerNodeId = mConnectionState.GetPeerNodeId();
VerifyOrReturnError(CanCastTo<uint16_t>(mSharedSecret.Length()), CHIP_ERROR_INTERNAL);
VerifyOrReturnError(CanCastTo<uint16_t>(sizeof(mMessageDigest)), CHIP_ERROR_INTERNAL);
VerifyOrReturnError(CanCastTo<uint64_t>(peerNodeId), CHIP_ERROR_INTERNAL);
memset(&serializable, 0, sizeof(serializable));
serializable.mSharedSecretLen = static_cast<uint16_t>(mSharedSecret.Length());
serializable.mMessageDigestLen = static_cast<uint16_t>(sizeof(mMessageDigest));
serializable.mPairingComplete = (mPairingComplete) ? 1 : 0;
serializable.mPeerNodeId = peerNodeId;
serializable.mLocalKeyId = mConnectionState.GetLocalKeyID();
serializable.mPeerKeyId = mConnectionState.GetPeerKeyID();
memcpy(serializable.mSharedSecret, mSharedSecret, mSharedSecret.Length());
memcpy(serializable.mMessageDigest, mMessageDigest, sizeof(mMessageDigest));
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::FromSerializable(const CASESessionSerializable & serializable)
{
mPairingComplete = (serializable.mPairingComplete == 1);
ReturnErrorOnFailure(mSharedSecret.SetLength(static_cast<size_t>(serializable.mSharedSecretLen)));
VerifyOrReturnError(serializable.mMessageDigestLen <= sizeof(mMessageDigest), CHIP_ERROR_INVALID_ARGUMENT);
memset(mSharedSecret, 0, sizeof(mSharedSecret.Capacity()));
memcpy(mSharedSecret, serializable.mSharedSecret, mSharedSecret.Length());
memcpy(mMessageDigest, serializable.mMessageDigest, serializable.mMessageDigestLen);
mConnectionState.SetPeerNodeId(serializable.mPeerNodeId);
mConnectionState.SetLocalKeyID(serializable.mLocalKeyId);
mConnectionState.SetPeerKeyID(serializable.mPeerKeyId);
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::Init(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId,
SessionEstablishmentDelegate * delegate)
{
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(operationalCredentialSet != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(operationalCredentialSet->GetCertCount() > 0, CHIP_ERROR_CERT_NOT_FOUND);
Clear();
ReturnErrorOnFailure(mCommissioningHash.Begin());
mDelegate = delegate;
mConnectionState.SetLocalKeyID(myKeyId);
mOpCredSet = operationalCredentialSet;
mValidContext.Reset();
mValidContext.mRequiredKeyUsages.Set(KeyUsageFlags::kDigitalSignature);
mValidContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth);
return CHIP_NO_ERROR;
}
CHIP_ERROR
CASESession::ListenForSessionEstablishment(OperationalCredentialSet * operationalCredentialSet, uint16_t myKeyId,
SessionEstablishmentDelegate * delegate)
{
ReturnErrorOnFailure(Init(operationalCredentialSet, myKeyId, delegate));
mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaR1;
mPairingComplete = false;
ChipLogDetail(SecureChannel, "Waiting for SigmaR1 msg");
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::EstablishSession(const Transport::PeerAddress peerAddress,
OperationalCredentialSet * operationalCredentialSet, NodeId peerNodeId, uint16_t myKeyId,
ExchangeContext * exchangeCtxt, SessionEstablishmentDelegate * delegate)
{
CHIP_ERROR err = CHIP_NO_ERROR;
// Return early on error here, as we have not initalized any state yet
ReturnErrorCodeIf(exchangeCtxt == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
err = Init(operationalCredentialSet, myKeyId, delegate);
// We are setting the exchange context specifically before checking for error.
// This is to make sure the exchange will get closed if Init() returned an error.
mExchangeCtxt = exchangeCtxt;
// From here onwards, let's go to exit on error, as some state might have already
// been initialized
SuccessOrExit(err);
mExchangeCtxt->SetResponseTimeout(kSigma_Response_Timeout);
mConnectionState.SetPeerAddress(peerAddress);
mConnectionState.SetPeerNodeId(peerNodeId);
err = SendSigmaR1();
SuccessOrExit(err);
exit:
if (err != CHIP_NO_ERROR)
{
Clear();
}
return err;
}
void CASESession::OnResponseTimeout(ExchangeContext * ec)
{
VerifyOrReturn(ec != nullptr, ChipLogError(SecureChannel, "CASESession::OnResponseTimeout was called by null exchange"));
VerifyOrReturn(mExchangeCtxt == ec, ChipLogError(SecureChannel, "CASESession::OnResponseTimeout exchange doesn't match"));
ChipLogError(SecureChannel,
"CASESession timed out while waiting for a response from the peer. Expected message type was %" PRIu8,
static_cast<std::underlying_type_t<decltype(mNextExpectedMsg)>>(mNextExpectedMsg));
mDelegate->OnSessionEstablishmentError(CHIP_ERROR_TIMEOUT);
Clear();
}
CHIP_ERROR CASESession::DeriveSecureSession(SecureSession & session, SecureSession::SessionRole role)
{
uint16_t saltlen;
(void) kKDFSEInfo;
(void) kKDFSEInfoLength;
VerifyOrReturnError(mPairingComplete, CHIP_ERROR_INCORRECT_STATE);
// Generate Salt for Encryption keys
saltlen = kSHA256_Hash_Length;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_salt;
ReturnErrorCodeIf(!msg_salt.Alloc(saltlen), CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_salt.Get(), saltlen);
// TODO: Add IPK to Salt
bbuf.Put(mMessageDigest, sizeof(mMessageDigest));
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
}
ReturnErrorOnFailure(session.InitFromSecret(ByteSpan(mSharedSecret, mSharedSecret.Length()), ByteSpan(msg_salt.Get(), saltlen),
SecureSession::SessionInfoType::kSessionEstablishment, role));
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::SendSigmaR1()
{
uint16_t data_len = static_cast<uint16_t>(kSigmaParamRandomNumberSize + sizeof(uint16_t) + sizeof(uint16_t) +
mOpCredSet->GetCertCount() * kTrustedRootIdSize + kP256_PublicKey_Length);
System::PacketBufferHandle msg_R1;
uint8_t * msg = nullptr;
msg_R1 = System::PacketBufferHandle::New(data_len);
VerifyOrReturnError(!msg_R1.IsNull(), CHIP_ERROR_NO_MEMORY);
msg = msg_R1->Start();
// Step 1
// Fill in the random value
ReturnErrorOnFailure(DRBG_get_bytes(msg, kSigmaParamRandomNumberSize));
// Step 4
ReturnErrorOnFailure(mEphemeralKey.Initialize());
// Step 5
// Let's construct the rest of the message using Encoding::LittleEndian::BufferWriter
{
uint16_t n_trusted_roots = mOpCredSet->GetCertCount();
Encoding::LittleEndian::BufferWriter bbuf(&msg[kSigmaParamRandomNumberSize], data_len - kSigmaParamRandomNumberSize);
// Initiator's session ID
bbuf.Put16(mConnectionState.GetLocalKeyID());
// Step 2/3
bbuf.Put16(n_trusted_roots);
for (uint16_t i = 0; i < n_trusted_roots; ++i)
{
if (mOpCredSet->GetTrustedRootId(i) != nullptr && mOpCredSet->GetTrustedRootId(i)->mId != nullptr)
{
bbuf.Put(mOpCredSet->GetTrustedRootId(i)->mId, kTrustedRootIdSize);
}
}
bbuf.Put(mEphemeralKey.Pubkey(), mEphemeralKey.Pubkey().Length());
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
}
msg_R1->SetDataLength(data_len);
ReturnErrorOnFailure(mCommissioningHash.AddData(msg_R1->Start(), msg_R1->DataLength()));
ReturnErrorOnFailure(ComputeIPK(mConnectionState.GetLocalKeyID(), mIPK, sizeof(mIPK)));
mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaR2;
// Call delegate to send the msg to peer
ReturnErrorOnFailure(mExchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::CASE_SigmaR1, std::move(msg_R1),
SendFlags(SendMessageFlags::kExpectResponse)));
ChipLogDetail(SecureChannel, "Sent SigmaR1 msg");
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::HandleSigmaR1_and_SendSigmaR2(const System::PacketBufferHandle & msg)
{
ReturnErrorOnFailure(HandleSigmaR1(msg));
ReturnErrorOnFailure(SendSigmaR2());
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::HandleSigmaR1(const System::PacketBufferHandle & msg)
{
CHIP_ERROR err = CHIP_NO_ERROR;
uint16_t encryptionKeyId = 0;
const uint8_t * buf = msg->Start();
uint16_t buflen = msg->DataLength();
uint16_t fixed_buflen =
kSigmaParamRandomNumberSize + sizeof(encryptionKeyId) + sizeof(uint16_t) + kTrustedRootIdSize + kP256_PublicKey_Length;
uint32_t n_trusted_roots;
Encoding::LittleEndian::BufferWriter bbuf(mRemotePubKey, mRemotePubKey.Length());
VerifyOrExit(buf != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
VerifyOrExit(buflen >= fixed_buflen, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
ChipLogDetail(SecureChannel, "Received SigmaR1 msg");
err = mCommissioningHash.AddData(msg->Start(), msg->DataLength());
SuccessOrExit(err);
// Let's skip the random number portion of the message
buf += kSigmaParamRandomNumberSize;
encryptionKeyId = chip::Encoding::LittleEndian::Read16(buf);
n_trusted_roots = chip::Encoding::LittleEndian::Read16(buf);
// Step 1/2
err = FindValidTrustedRoot(&buf, n_trusted_roots);
SuccessOrExit(err);
// write public key from message
bbuf.Put(buf, kP256_PublicKey_Length);
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
ChipLogDetail(SecureChannel, "Peer assigned session key ID %d", encryptionKeyId);
mConnectionState.SetPeerKeyID(encryptionKeyId);
exit:
if (err == CHIP_ERROR_CERT_NOT_TRUSTED)
{
SendErrorMsg(SigmaErrorType::kNoSharedTrustRoots);
}
else if (err != CHIP_NO_ERROR)
{
SendErrorMsg(SigmaErrorType::kUnexpected);
}
return err;
}
CHIP_ERROR CASESession::SendSigmaR2()
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle msg_R2;
uint16_t data_len;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_rand;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Signed;
uint16_t msg_r2_signed_len;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Encrypted;
size_t msg_r2_signed_enc_len;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_salt;
uint16_t saltlen;
uint8_t sr2k[kAEADKeySize];
P256ECDSASignature sigmaR2Signature;
uint8_t tag[kTAGSize];
HKDF_sha_crypto mHKDF;
saltlen = kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length;
VerifyOrExit(msg_salt.Alloc(saltlen), err = CHIP_ERROR_NO_MEMORY);
VerifyOrExit(msg_rand.Alloc(kSigmaParamRandomNumberSize), err = CHIP_ERROR_NO_MEMORY);
// Step 1
// Fill in the random value
err = DRBG_get_bytes(msg_rand.Get(), kSigmaParamRandomNumberSize);
SuccessOrExit(err);
// Step 3
// hardcoded to use a p256keypair
err = mEphemeralKey.Initialize();
SuccessOrExit(err);
// Step 4
err = mEphemeralKey.ECDH_derive_secret(mRemotePubKey, mSharedSecret);
SuccessOrExit(err);
err = ComputeIPK(mConnectionState.GetLocalKeyID(), mIPK, sizeof(mIPK));
SuccessOrExit(err);
// Step 5
{
MutableByteSpan saltSpan(msg_salt.Get(), saltlen);
err = ConstructSaltSigmaR2(ByteSpan(msg_rand.Get(), kSigmaParamRandomNumberSize), mEphemeralKey.Pubkey(), mIPK,
sizeof(mIPK), saltSpan);
SuccessOrExit(err);
}
err = mHKDF.HKDF_SHA256(mSharedSecret, mSharedSecret.Length(), msg_salt.Get(), saltlen, kKDFSR2Info, kKDFInfoLength, sr2k,
kAEADKeySize);
SuccessOrExit(err);
// Step 6
msg_r2_signed_len =
static_cast<uint16_t>(sizeof(uint16_t) + mOpCredSet->GetDevOpCredLen(mTrustedRootId) + kP256_PublicKey_Length * 2);
VerifyOrExit(msg_R2_Signed.Alloc(msg_r2_signed_len), err = CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R2_Signed.Get(), msg_r2_signed_len);
bbuf.Put(mEphemeralKey.Pubkey(), mEphemeralKey.Pubkey().Length());
bbuf.Put16(mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mOpCredSet->GetDevOpCred(mTrustedRootId), mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mRemotePubKey, mRemotePubKey.Length());
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
// Step 7
err = mOpCredSet->SignMsg(mTrustedRootId, msg_R2_Signed.Get(), msg_r2_signed_len, sigmaR2Signature);
SuccessOrExit(err);
// Step 8
msg_r2_signed_enc_len = sizeof(uint16_t) + mOpCredSet->GetDevOpCredLen(mTrustedRootId) + sigmaR2Signature.Length();
VerifyOrExit(msg_R2_Encrypted.Alloc(msg_r2_signed_enc_len), err = CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len);
bbuf.Put16(mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mOpCredSet->GetDevOpCred(mTrustedRootId), mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(sigmaR2Signature, sigmaR2Signature.Length());
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
// Step 9
err = AES_CCM_encrypt(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len, nullptr, 0, sr2k, kAEADKeySize, kIVSR2, kIVLength,
msg_R2_Encrypted.Get(), tag, sizeof(tag));
SuccessOrExit(err);
data_len = static_cast<uint16_t>(kSigmaParamRandomNumberSize + sizeof(uint16_t) + kTrustedRootIdSize + kP256_PublicKey_Length +
msg_r2_signed_enc_len + sizeof(tag));
msg_R2 = System::PacketBufferHandle::New(data_len);
VerifyOrExit(!msg_R2.IsNull(), err = CHIP_ERROR_NO_MEMORY);
// Step 10
// now construct sigmaR2
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R2->Start(), data_len);
bbuf.Put(msg_rand.Get(), kSigmaParamRandomNumberSize);
// Responder's session ID
bbuf.Put16(mConnectionState.GetLocalKeyID());
// Step 2
bbuf.Put(mTrustedRootId.mId, mTrustedRootId.mLen);
bbuf.Put(mEphemeralKey.Pubkey(), mEphemeralKey.Pubkey().Length());
bbuf.Put(msg_R2_Encrypted.Get(), msg_r2_signed_enc_len);
bbuf.Put(tag, sizeof(tag));
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
msg_R2->SetDataLength(data_len);
err = mCommissioningHash.AddData(msg_R2->Start(), msg_R2->DataLength());
SuccessOrExit(err);
mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaR3;
// Call delegate to send the msg to peer
err = mExchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::CASE_SigmaR2, std::move(msg_R2),
SendFlags(SendMessageFlags::kExpectResponse));
SuccessOrExit(err);
ChipLogDetail(SecureChannel, "Sent SigmaR2 msg");
exit:
if (err != CHIP_NO_ERROR)
{
SendErrorMsg(SigmaErrorType::kUnexpected);
}
return err;
}
CHIP_ERROR CASESession::HandleSigmaR2_and_SendSigmaR3(const System::PacketBufferHandle & msg)
{
ReturnErrorOnFailure(HandleSigmaR2(msg));
ReturnErrorOnFailure(SendSigmaR3());
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::HandleSigmaR2(const System::PacketBufferHandle & msg)
{
CHIP_ERROR err = CHIP_NO_ERROR;
const uint8_t * buf = msg->Start();
size_t buflen = msg->DataLength();
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_salt;
uint16_t saltlen;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R2_Signed;
uint16_t msg_r2_signed_len;
uint8_t sr2k[kAEADKeySize];
P256ECDSASignature sigmaR2SignedData;
size_t sigLen;
P256PublicKey remoteCredential;
const uint8_t * remoteDeviceOpCert;
uint16_t remoteDeviceOpCertLen;
uint8_t * msg_r2_encrypted;
const uint8_t * tag = buf + buflen - kTAGSize;
uint16_t encryptionKeyId = 0;
HKDF_sha_crypto mHKDF;
VerifyOrExit(buf != nullptr, err = CHIP_ERROR_MESSAGE_INCOMPLETE);
ChipLogDetail(SecureChannel, "Received SigmaR2 msg");
// Step 1
// skip random part
buf += kSigmaParamRandomNumberSize;
encryptionKeyId = chip::Encoding::LittleEndian::Read16(buf);
ChipLogDetail(SecureChannel, "Peer assigned session key ID %d", encryptionKeyId);
mConnectionState.SetPeerKeyID(encryptionKeyId);
err = FindValidTrustedRoot(&buf, 1);
SuccessOrExit(err);
// fill in Remote Public Key
{
Encoding::LittleEndian::BufferWriter bbuf(mRemotePubKey, mRemotePubKey.Length());
bbuf.Put(buf, mRemotePubKey.Length());
buf += kP256_PublicKey_Length;
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
// Step 2
err = mEphemeralKey.ECDH_derive_secret(mRemotePubKey, mSharedSecret);
SuccessOrExit(err);
// Step 3
saltlen = kIPKSize + kSigmaParamRandomNumberSize + kP256_PublicKey_Length + kSHA256_Hash_Length;
VerifyOrExit(msg_salt.Alloc(saltlen), err = CHIP_ERROR_NO_MEMORY);
err = ComputeIPK(mConnectionState.GetPeerKeyID(), mRemoteIPK, sizeof(mRemoteIPK));
SuccessOrExit(err);
{
MutableByteSpan saltSpan(msg_salt.Get(), saltlen);
err = ConstructSaltSigmaR2(ByteSpan(msg->Start(), msg->DataLength()), mRemotePubKey, mRemoteIPK, sizeof(mRemoteIPK),
saltSpan);
SuccessOrExit(err);
}
err = mHKDF.HKDF_SHA256(mSharedSecret, mSharedSecret.Length(), msg_salt.Get(), saltlen, kKDFSR2Info, kKDFInfoLength, sr2k,
kAEADKeySize);
SuccessOrExit(err);
err = mCommissioningHash.AddData(msg->Start(), msg->DataLength());
SuccessOrExit(err);
// Step 4
msg_r2_encrypted = const_cast<uint8_t *>(buf);
err = AES_CCM_decrypt(msg_r2_encrypted,
buflen - kSigmaParamRandomNumberSize - sizeof(encryptionKeyId) - kTrustedRootIdSize -
kP256_PublicKey_Length - kTAGSize,
nullptr, 0, tag, kTAGSize, sr2k, kAEADKeySize, kIVSR2, kIVLength, msg_r2_encrypted);
SuccessOrExit(err);
// Step 5
// Validate responder identity located in msg_r2_encrypted
// Constructing responder identity
err = Validate_and_RetrieveResponderID(&buf, remoteCredential, &remoteDeviceOpCert, remoteDeviceOpCertLen);
SuccessOrExit(err);
// Step 6 - Construct msg_R2_Signed and validate the signature in msg_r2_encrypted
msg_r2_signed_len = static_cast<uint16_t>(sizeof(uint16_t) + remoteDeviceOpCertLen + kP256_PublicKey_Length * 2);
VerifyOrExit(msg_R2_Signed.Alloc(msg_r2_signed_len), err = CHIP_ERROR_NO_MEMORY);
sigLen = buflen - kSigmaParamRandomNumberSize - sizeof(encryptionKeyId) - kTrustedRootIdSize - kP256_PublicKey_Length -
sizeof(uint16_t) - remoteDeviceOpCertLen - kTAGSize;
{
MutableByteSpan msg_R2_Span(msg_R2_Signed.Get(), msg_r2_signed_len);
err = ConstructSignedCredentials(&buf, remoteDeviceOpCert, remoteDeviceOpCertLen, msg_R2_Span, sigmaR2SignedData, sigLen);
SuccessOrExit(err);
}
err = remoteCredential.ECDSA_validate_msg_signature(msg_R2_Signed.Get(), msg_r2_signed_len, sigmaR2SignedData);
SuccessOrExit(err);
exit:
if (err == CHIP_ERROR_INVALID_SIGNATURE)
{
SendErrorMsg(SigmaErrorType::kInvalidSignature);
}
else if (err == CHIP_ERROR_CERT_NOT_TRUSTED)
{
SendErrorMsg(SigmaErrorType::kNoSharedTrustRoots);
}
else if (err != CHIP_NO_ERROR)
{
SendErrorMsg(SigmaErrorType::kUnexpected);
}
return err;
}
CHIP_ERROR CASESession::SendSigmaR3()
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle msg_R3;
uint16_t data_len;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Encrypted;
uint16_t msg_r3_encrypted_len;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_salt;
uint16_t saltlen;
uint8_t sr3k[kAEADKeySize];
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Signed;
uint16_t msg_r3_signed_len;
P256ECDSASignature sigmaR3Signature;
uint8_t tag[kTAGSize];
HKDF_sha_crypto mHKDF;
// Step 1
saltlen = kIPKSize + kSHA256_Hash_Length;
ChipLogDetail(SecureChannel, "Sending SigmaR3");
VerifyOrExit(msg_salt.Alloc(saltlen), err = CHIP_ERROR_NO_MEMORY);
{
MutableByteSpan saltSpan(msg_salt.Get(), saltlen);
err = ConstructSaltSigmaR3(mIPK, sizeof(mIPK), saltSpan);
SuccessOrExit(err);
}
err = mHKDF.HKDF_SHA256(mSharedSecret, mSharedSecret.Length(), msg_salt.Get(), saltlen, kKDFSR3Info, kKDFInfoLength, sr3k,
kAEADKeySize);
SuccessOrExit(err);
// Step 2
msg_r3_signed_len =
static_cast<uint16_t>(sizeof(uint16_t) + mOpCredSet->GetDevOpCredLen(mTrustedRootId) + kP256_PublicKey_Length * 2);
VerifyOrExit(msg_R3_Signed.Alloc(msg_r3_signed_len), err = CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R3_Signed.Get(), msg_r3_signed_len);
bbuf.Put(mEphemeralKey.Pubkey(), mEphemeralKey.Pubkey().Length());
bbuf.Put16(mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mOpCredSet->GetDevOpCred(mTrustedRootId), mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mRemotePubKey, mRemotePubKey.Length());
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
// Step 3
err = mOpCredSet->SignMsg(mTrustedRootId, msg_R3_Signed.Get(), msg_r3_signed_len, sigmaR3Signature);
SuccessOrExit(err);
// Step 4
msg_r3_encrypted_len = static_cast<uint16_t>(sizeof(uint16_t) + mOpCredSet->GetDevOpCredLen(mTrustedRootId) +
static_cast<uint16_t>(sigmaR3Signature.Length()));
VerifyOrExit(msg_R3_Encrypted.Alloc(msg_r3_encrypted_len), err = CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R3_Encrypted.Get(), msg_r3_encrypted_len);
bbuf.Put16(mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(mOpCredSet->GetDevOpCred(mTrustedRootId), mOpCredSet->GetDevOpCredLen(mTrustedRootId));
bbuf.Put(sigmaR3Signature, sigmaR3Signature.Length());
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
// Step 5
err = AES_CCM_encrypt(msg_R3_Encrypted.Get(), msg_r3_encrypted_len, nullptr, 0, sr3k, kAEADKeySize, kIVSR3, kIVLength,
msg_R3_Encrypted.Get(), tag, sizeof(tag));
SuccessOrExit(err);
// Step 6
data_len = static_cast<uint16_t>(sizeof(tag) + msg_r3_encrypted_len);
msg_R3 = System::PacketBufferHandle::New(data_len);
VerifyOrExit(!msg_R3.IsNull(), err = CHIP_ERROR_NO_MEMORY);
{
Encoding::LittleEndian::BufferWriter bbuf(msg_R3->Start(), data_len);
bbuf.Put(msg_R3_Encrypted.Get(), msg_r3_encrypted_len);
bbuf.Put(tag, sizeof(tag));
VerifyOrExit(bbuf.Fit(), err = CHIP_ERROR_NO_MEMORY);
}
msg_R3->SetDataLength(data_len);
err = mCommissioningHash.AddData(msg_R3->Start(), msg_R3->DataLength());
SuccessOrExit(err);
// Call delegate to send the Msg3 to peer
err = mExchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::CASE_SigmaR3, std::move(msg_R3));
SuccessOrExit(err);
ChipLogDetail(SecureChannel, "Sent SigmaR3 msg");
err = mCommissioningHash.Finish(mMessageDigest);
SuccessOrExit(err);
mPairingComplete = true;
// Close the exchange, as no additional messages are expected from the peer
CloseExchange();
// Call delegate to indicate pairing completion
mDelegate->OnSessionEstablished();
exit:
if (err != CHIP_NO_ERROR)
{
SendErrorMsg(SigmaErrorType::kUnexpected);
}
return err;
}
CHIP_ERROR CASESession::HandleSigmaR3(const System::PacketBufferHandle & msg)
{
CHIP_ERROR err = CHIP_NO_ERROR;
const uint8_t * buf = msg->Start();
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_R3_Signed;
uint16_t msg_r3_signed_len;
uint8_t sr3k[kAEADKeySize];
P256ECDSASignature sigmaR3SignedData;
size_t sigLen;
P256PublicKey remoteCredential;
const uint8_t * remoteDeviceOpCert;
uint16_t remoteDeviceOpCertLen;
chip::Platform::ScopedMemoryBuffer<uint8_t> msg_salt;
uint16_t saltlen;
uint8_t * tag = msg->Start() + msg->DataLength() - kTAGSize;
HKDF_sha_crypto mHKDF;
ChipLogDetail(SecureChannel, "Received SigmaR3 msg");
mNextExpectedMsg = Protocols::SecureChannel::MsgType::CASE_SigmaErr;
// Step 1
saltlen = kIPKSize + kSHA256_Hash_Length;
VerifyOrExit(msg_salt.Alloc(saltlen), err = CHIP_ERROR_NO_MEMORY);
err = ComputeIPK(mConnectionState.GetPeerKeyID(), mRemoteIPK, sizeof(mRemoteIPK));
SuccessOrExit(err);
{
MutableByteSpan saltSpan(msg_salt.Get(), saltlen);
err = ConstructSaltSigmaR3(mRemoteIPK, sizeof(mRemoteIPK), saltSpan);
SuccessOrExit(err);
}
err = mHKDF.HKDF_SHA256(mSharedSecret, mSharedSecret.Length(), msg_salt.Get(), saltlen, kKDFSR3Info, kKDFInfoLength, sr3k,
kAEADKeySize);
SuccessOrExit(err);
err = mCommissioningHash.AddData(msg->Start(), msg->DataLength());
SuccessOrExit(err);
// Step 2
err = AES_CCM_decrypt(msg->Start(), msg->DataLength() - kTAGSize, nullptr, 0, tag, kTAGSize, sr3k, kAEADKeySize, kIVSR3,
kIVLength, msg->Start());
SuccessOrExit(err);
// Step 3
// Validate initiator identity located in msg->Start()
// Constructing responder identity
err = Validate_and_RetrieveResponderID(&buf, remoteCredential, &remoteDeviceOpCert, remoteDeviceOpCertLen);
SuccessOrExit(err);
// Step 4
msg_r3_signed_len = static_cast<uint16_t>(sizeof(uint16_t) + remoteDeviceOpCertLen + kP256_PublicKey_Length * 2);
VerifyOrExit(msg_R3_Signed.Alloc(msg_r3_signed_len), err = CHIP_ERROR_NO_MEMORY);
sigLen = msg->DataLength() - sizeof(uint16_t) - remoteDeviceOpCertLen - kTAGSize;
{
MutableByteSpan msg_R3_Span(msg_R3_Signed.Get(), msg_r3_signed_len);
err = ConstructSignedCredentials(&buf, remoteDeviceOpCert, remoteDeviceOpCertLen, msg_R3_Span, sigmaR3SignedData, sigLen);
SuccessOrExit(err);
}
err = remoteCredential.ECDSA_validate_msg_signature(msg_R3_Signed.Get(), msg_r3_signed_len, sigmaR3SignedData);
SuccessOrExit(err);
err = mCommissioningHash.Finish(mMessageDigest);
SuccessOrExit(err);
mPairingComplete = true;
// Close the exchange, as no additional messages are expected from the peer
CloseExchange();
// Call delegate to indicate pairing completion
mDelegate->OnSessionEstablished();
exit:
if (err == CHIP_ERROR_INVALID_SIGNATURE)
{
SendErrorMsg(SigmaErrorType::kInvalidSignature);
}
else if (err != CHIP_NO_ERROR)
{
SendErrorMsg(SigmaErrorType::kUnexpected);
}
return err;
}
void CASESession::SendErrorMsg(SigmaErrorType errorCode)
{
System::PacketBufferHandle msg;
uint16_t msglen = sizeof(SigmaErrorMsg);
SigmaErrorMsg * pMsg = nullptr;
msg = System::PacketBufferHandle::New(msglen);
VerifyOrReturn(!msg.IsNull(), ChipLogError(SecureChannel, "Failed to allocate error message"));
pMsg = reinterpret_cast<SigmaErrorMsg *>(msg->Start());
pMsg->error = errorCode;
msg->SetDataLength(msglen);
VerifyOrReturn(mExchangeCtxt->SendMessage(Protocols::SecureChannel::MsgType::CASE_SigmaErr, std::move(msg)) != CHIP_NO_ERROR,
ChipLogError(SecureChannel, "Failed to send error message"));
}
CHIP_ERROR CASESession::FindValidTrustedRoot(const uint8_t ** msgIterator, uint32_t nTrustedRoots)
{
CertificateKeyId trustedRoot[kMaxTrustedRootIds];
for (uint32_t i = 0; i < nTrustedRoots; ++i)
{
trustedRoot[i].mId = *msgIterator;
trustedRoot[i].mLen = kTrustedRootIdSize;
*msgIterator += kTrustedRootIdSize;
if (mOpCredSet->IsTrustedRootIn(trustedRoot[i]))
{
if (mTrustedRootId.mId != nullptr)
{
chip::Platform::MemoryFree(const_cast<uint8_t *>(mTrustedRootId.mId));
mTrustedRootId.mId = nullptr;
}
mTrustedRootId.mId = reinterpret_cast<const uint8_t *>(chip::Platform::MemoryAlloc(kTrustedRootIdSize));
VerifyOrReturnError(mTrustedRootId.mId != nullptr, CHIP_ERROR_NO_MEMORY);
memcpy(const_cast<uint8_t *>(mTrustedRootId.mId), trustedRoot[i].mId, trustedRoot[i].mLen);
mTrustedRootId.mLen = trustedRoot[i].mLen;
break;
}
}
VerifyOrReturnError(mTrustedRootId.mId != nullptr, CHIP_ERROR_CERT_NOT_TRUSTED);
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::ConstructSaltSigmaR2(const ByteSpan & rand, const P256PublicKey & pubkey, const uint8_t * ipk,
size_t ipkLen, MutableByteSpan & salt)
{
uint8_t md[kSHA256_Hash_Length];
memset(salt.data(), 0, salt.size());
Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
bbuf.Put(ipk, ipkLen);
bbuf.Put(rand.data(), kSigmaParamRandomNumberSize);
bbuf.Put(pubkey, pubkey.Length());
ReturnErrorOnFailure(mCommissioningHash.Finish(md));
bbuf.Put(md, kSHA256_Hash_Length);
ReturnErrorOnFailure(mCommissioningHash.Begin());
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::ConstructSaltSigmaR3(const uint8_t * ipk, size_t ipkLen, MutableByteSpan & salt)
{
uint8_t md[kSHA256_Hash_Length];
memset(salt.data(), 0, salt.size());
Encoding::LittleEndian::BufferWriter bbuf(salt.data(), salt.size());
bbuf.Put(ipk, ipkLen);
ReturnErrorOnFailure(mCommissioningHash.Finish(md));
bbuf.Put(md, kSHA256_Hash_Length);
ReturnErrorOnFailure(mCommissioningHash.Begin());
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::Validate_and_RetrieveResponderID(const uint8_t ** msgIterator, P256PublicKey & responderID,
const uint8_t ** responderOpCert, uint16_t & responderOpCertLen)
{
ChipCertificateData * resultCert = nullptr;
ChipCertificateSet certSet;
// Certificate set can contain up to 3 certs (NOC, ICA cert, and Root CA cert)
ReturnErrorOnFailure(certSet.Init(3, kMaxCHIPCertLength * 3));
responderOpCertLen = chip::Encoding::LittleEndian::Read16(*msgIterator);
*responderOpCert = *msgIterator;
*msgIterator += responderOpCertLen;
Encoding::LittleEndian::BufferWriter bbuf(responderID, responderID.Length());
ReturnErrorOnFailure(
certSet.LoadCerts(*responderOpCert, responderOpCertLen, BitFlags<CertDecodeFlags>(CertDecodeFlags::kGenerateTBSHash)));
bbuf.Put(certSet.GetCertSet()[0].mPublicKey, certSet.GetCertSet()[0].mPublicKeyLen);
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
// Validate responder identity located in msg_r2_encrypted
ReturnErrorOnFailure(
mOpCredSet->FindCertSet(mTrustedRootId)
->LoadCerts(*responderOpCert, responderOpCertLen, BitFlags<CertDecodeFlags>(CertDecodeFlags::kGenerateTBSHash)));
ReturnErrorOnFailure(SetEffectiveTime());
// Locate the subject DN and key id that will be used as input the FindValidCert() method.
{
const ChipDN & subjectDN = certSet.GetCertSet()[0].mSubjectDN;
const CertificateKeyId & subjectKeyId = certSet.GetCertSet()[0].mSubjectKeyId;
ReturnErrorOnFailure(mOpCredSet->FindValidCert(mTrustedRootId, subjectDN, subjectKeyId, mValidContext, resultCert));
}
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::ConstructSignedCredentials(const uint8_t ** msgIterator, const uint8_t * responderOpCert,
uint16_t responderOpCertLen, MutableByteSpan & signedCredentials,
P256ECDSASignature & signature, size_t sigLen)
{
{
Encoding::LittleEndian::BufferWriter bbuf(signedCredentials.data(), signedCredentials.size());
bbuf.Put(mRemotePubKey, mRemotePubKey.Length());
bbuf.Put16(responderOpCertLen);
bbuf.Put(responderOpCert, responderOpCertLen);
bbuf.Put(mEphemeralKey.Pubkey(), mEphemeralKey.Pubkey().Length());
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
}
{
signature.SetLength(sigLen);
Encoding::LittleEndian::BufferWriter bbuf(signature, signature.Length());
bbuf.Put(*msgIterator, signature.Length());
VerifyOrReturnError(bbuf.Fit(), CHIP_ERROR_NO_MEMORY);
}
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::ComputeIPK(const uint16_t sessionID, uint8_t * ipk, size_t ipkLen)
{
HKDF_sha_crypto mHKDF;
ReturnErrorOnFailure(mHKDF.HKDF_SHA256(mFabricSecret, mFabricSecret.Length(), reinterpret_cast<const uint8_t *>(&sessionID),
sizeof(sessionID), kIPKInfo, sizeof(kIPKInfo), ipk, ipkLen));
return CHIP_NO_ERROR;
}
// TODO: Remove this and replace with system method to retrieve current time
CHIP_ERROR CASESession::SetEffectiveTime(void)
{
using namespace ASN1;
ASN1UniversalTime effectiveTime;
effectiveTime.Year = 2021;
effectiveTime.Month = 2;
effectiveTime.Day = 12;
effectiveTime.Hour = 10;
effectiveTime.Minute = 10;
effectiveTime.Second = 10;
return ASN1ToChipEpochTime(effectiveTime, mValidContext.mEffectiveTime);
}
CHIP_ERROR CASESession::HandleErrorMsg(const System::PacketBufferHandle & msg)
{
ReturnErrorCodeIf(msg->Start() == nullptr || msg->DataLength() != sizeof(SigmaErrorMsg), CHIP_ERROR_MESSAGE_INCOMPLETE);
static_assert(sizeof(SigmaErrorMsg) == sizeof(uint8_t),
"Assuming size of SigmaErrorMsg message is 1 octet, so that endian-ness conversion is not needed");
SigmaErrorMsg * pMsg = reinterpret_cast<SigmaErrorMsg *>(msg->Start());
ChipLogError(SecureChannel, "Received error (%d) during CASE pairing process", pMsg->error);
CHIP_ERROR err = CHIP_NO_ERROR;
switch (pMsg->error)
{
case SigmaErrorType::kNoSharedTrustRoots:
err = CHIP_ERROR_CERT_NOT_TRUSTED;
break;
case SigmaErrorType::kUnsupportedVersion:
err = CHIP_ERROR_UNSUPPORTED_CASE_CONFIGURATION;
break;
case SigmaErrorType::kInvalidSignature:
case SigmaErrorType::kInvalidResumptionTag:
case SigmaErrorType::kUnexpected:
err = CHIP_ERROR_INVALID_CASE_PARAMETER;
break;
default:
err = CHIP_ERROR_INTERNAL;
break;
};
return err;
}
CHIP_ERROR CASESession::ValidateReceivedMessage(ExchangeContext * ec, const PacketHeader & packetHeader,
const PayloadHeader & payloadHeader, System::PacketBufferHandle & msg)
{
VerifyOrReturnError(ec != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
// mExchangeCtxt can be nullptr if this is the first message (CASE_SigmaR1) received by CASESession
// via UnsolicitedMessageHandler. The exchange context is allocated by exchange manager and provided
// to the handler (CASESession object).
if (mExchangeCtxt != nullptr)
{
if (mExchangeCtxt != ec)
{
// Close the incoming exchange explicitly, as the cleanup code only closes mExchangeCtxt
ec->Close();
ReturnErrorOnFailure(CHIP_ERROR_INVALID_ARGUMENT);
}
}
else
{
mExchangeCtxt = ec;
mExchangeCtxt->SetResponseTimeout(kSigma_Response_Timeout);
}
VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(payloadHeader.HasMessageType(mNextExpectedMsg) ||
payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::CASE_SigmaErr),
CHIP_ERROR_INVALID_MESSAGE_TYPE);
if (packetHeader.GetSourceNodeId().HasValue())
{
if (mConnectionState.GetPeerNodeId() == kUndefinedNodeId)
{
mConnectionState.SetPeerNodeId(packetHeader.GetSourceNodeId().Value());
}
else
{
VerifyOrReturnError(packetHeader.GetSourceNodeId().Value() == mConnectionState.GetPeerNodeId(),
CHIP_ERROR_WRONG_NODE_ID);
}
}
return CHIP_NO_ERROR;
}
CHIP_ERROR CASESession::OnMessageReceived(ExchangeContext * ec, const PacketHeader & packetHeader,
const PayloadHeader & payloadHeader, System::PacketBufferHandle && msg)
{
CHIP_ERROR err = ValidateReceivedMessage(ec, packetHeader, payloadHeader, msg);
SuccessOrExit(err);
mConnectionState.SetPeerAddress(mMessageDispatch.GetPeerAddress());
switch (static_cast<Protocols::SecureChannel::MsgType>(payloadHeader.GetMessageType()))
{
case Protocols::SecureChannel::MsgType::CASE_SigmaR1:
err = HandleSigmaR1_and_SendSigmaR2(msg);
break;
case Protocols::SecureChannel::MsgType::CASE_SigmaR2:
err = HandleSigmaR2_and_SendSigmaR3(msg);
break;
case Protocols::SecureChannel::MsgType::CASE_SigmaR3:
err = HandleSigmaR3(msg);
break;
case Protocols::SecureChannel::MsgType::CASE_SigmaErr:
err = HandleErrorMsg(msg);
break;
default:
SendErrorMsg(SigmaErrorType::kUnexpected);
err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
break;
};
exit:
// Call delegate to indicate session establishment failure.
if (err != CHIP_NO_ERROR)
{
Clear();
mDelegate->OnSessionEstablishmentError(err);
}
return err;
}
} // namespace chip